static inline void zend_clone_zval(zval *src, int bind) { void *ptr; if (Z_IMMUTABLE_P(src)) { return; } switch (Z_TYPE_P(src)) { case IS_STRING: case IS_CONSTANT: Z_STR_P(src) = zend_clone_str(Z_STR_P(src)); break; case IS_ARRAY: if (Z_ARR_P(src) != &EG(symbol_table)) { if (bind && Z_REFCOUNT_P(src) > 1 && (ptr = accel_xlat_get(Z_ARR_P(src))) != NULL) { Z_ARR_P(src) = ptr; } else { zend_array *old = Z_ARR_P(src); Z_ARR_P(src) = emalloc(sizeof(zend_array)); Z_ARR_P(src)->gc = old->gc; if (bind && Z_REFCOUNT_P(src) > 1) { accel_xlat_set(old, Z_ARR_P(src)); } zend_hash_clone_zval(Z_ARRVAL_P(src), old, 0); } } break; case IS_REFERENCE: if (bind && Z_REFCOUNT_P(src) > 1 && (ptr = accel_xlat_get(Z_REF_P(src))) != NULL) { Z_REF_P(src) = ptr; } else { zend_reference *old = Z_REF_P(src); ZVAL_NEW_REF(src, &old->val); Z_REF_P(src)->gc = old->gc; if (bind && Z_REFCOUNT_P(src) > 1) { accel_xlat_set(old, Z_REF_P(src)); } zend_clone_zval(Z_REFVAL_P(src), bind); } break; case IS_CONSTANT_AST: if (bind && Z_REFCOUNT_P(src) > 1 && (ptr = accel_xlat_get(Z_AST_P(src))) != NULL) { Z_AST_P(src) = ptr; } else { zend_ast_ref *old = Z_AST_P(src); ZVAL_NEW_AST(src, old->ast); Z_AST_P(src)->gc = old->gc; if (bind && Z_REFCOUNT_P(src) > 1) { accel_xlat_set(old, Z_AST_P(src)); } Z_ASTVAL_P(src) = zend_ast_clone(Z_ASTVAL_P(src)); } break; } }
static void zend_persist_zval_const(zval *z) { zend_uchar flags; void *new_ptr; switch (Z_TYPE_P(z)) { case IS_STRING: case IS_CONSTANT: flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT); zend_accel_memdup_interned_string(Z_STR_P(z)); Z_GC_FLAGS_P(z) |= flags; Z_TYPE_FLAGS_P(z) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); break; case IS_ARRAY: new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z)); if (new_ptr) { Z_ARR_P(z) = new_ptr; Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; } else { if (Z_IMMUTABLE_P(z)) { Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array)); zend_hash_persist_immutable(Z_ARRVAL_P(z)); } else { GC_REMOVE_FROM_BUFFER(Z_ARR_P(z)); zend_accel_store(Z_ARR_P(z), sizeof(zend_array)); zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval); /* make immutable array */ Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; GC_REFCOUNT(Z_COUNTED_P(z)) = 2; Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; } } break; case IS_REFERENCE: new_ptr = zend_shared_alloc_get_xlat_entry(Z_REF_P(z)); if (new_ptr) { Z_REF_P(z) = new_ptr; } else { zend_accel_store(Z_REF_P(z), sizeof(zend_reference)); zend_persist_zval(Z_REFVAL_P(z)); } break; case IS_CONSTANT_AST: new_ptr = zend_shared_alloc_get_xlat_entry(Z_AST_P(z)); if (new_ptr) { Z_AST_P(z) = new_ptr; } else { zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref)); Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z)); } break; } }
static void zend_file_cache_serialize_zval(zval *zv, zend_persistent_script *script, zend_file_cache_metainfo *info, void *buf) { switch (Z_TYPE_P(zv)) { case IS_STRING: case IS_CONSTANT: if (!IS_SERIALIZED(Z_STR_P(zv))) { SERIALIZE_STR(Z_STR_P(zv)); } break; case IS_ARRAY: if (!IS_SERIALIZED(Z_ARR_P(zv))) { HashTable *ht; SERIALIZE_PTR(Z_ARR_P(zv)); ht = Z_ARR_P(zv); UNSERIALIZE_PTR(ht); zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval); } break; case IS_REFERENCE: if (!IS_SERIALIZED(Z_REF_P(zv))) { zend_reference *ref; SERIALIZE_PTR(Z_REF_P(zv)); ref = Z_REF_P(zv); UNSERIALIZE_PTR(ref); zend_file_cache_serialize_zval(&ref->val, script, info, buf); } break; case IS_CONSTANT_AST: if (!IS_SERIALIZED(Z_AST_P(zv))) { zend_ast_ref *ast; SERIALIZE_PTR(Z_AST_P(zv)); ast = Z_AST_P(zv); UNSERIALIZE_PTR(ast); if (!IS_SERIALIZED(ast->ast)) { ast->ast = zend_file_cache_serialize_ast(ast->ast, script, info, buf); } } break; } }
static void zend_persist_zval_calc(zval *z) { zend_uchar flags; uint size; switch (Z_TYPE_P(z)) { case IS_STRING: case IS_CONSTANT: flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT); ADD_INTERNED_STRING(Z_STR_P(z), 0); if (!Z_REFCOUNTED_P(z)) { Z_TYPE_FLAGS_P(z) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE); } Z_GC_FLAGS_P(z) |= flags; break; case IS_ARRAY: size = zend_shared_memdup_size(Z_ARR_P(z), sizeof(zend_array)); if (size) { ADD_SIZE(size); zend_hash_persist_calc(Z_ARRVAL_P(z), zend_persist_zval_calc); } break; case IS_REFERENCE: size = zend_shared_memdup_size(Z_REF_P(z), sizeof(zend_reference)); if (size) { ADD_SIZE(size); zend_persist_zval_calc(Z_REFVAL_P(z)); } break; case IS_CONSTANT_AST: size = zend_shared_memdup_size(Z_AST_P(z), sizeof(zend_ast_ref)); if (size) { ADD_SIZE(size); zend_persist_ast_calc(Z_ASTVAL_P(z)); } break; } }
/* {{{ my_copy_zval */ static APC_HOTSPOT void my_copy_zval(zval* dst, const zval* src, apc_context_t* ctxt) { apc_pool* pool = ctxt->pool; assert(dst != NULL); assert(src != NULL); memcpy(dst, src, sizeof(zval)); if (Z_REFCOUNTED_P(src)) { if (zend_hash_num_elements(&ctxt->copied)) { zval *rc = zend_hash_index_find( &ctxt->copied, (uintptr_t) Z_COUNTED_P(src)); if (rc) { ZVAL_COPY(dst, rc); return; } } } switch (Z_TYPE_P(src)) { case IS_RESOURCE: case IS_TRUE: case IS_FALSE: case IS_LONG: case IS_DOUBLE: case IS_NULL: break; case IS_REFERENCE: Z_REF_P(dst) = my_copy_reference(Z_REF_P(src), ctxt); break; case IS_INDIRECT: my_copy_zval(dst, Z_INDIRECT_P(src), ctxt); break; case IS_CONSTANT: case IS_STRING: if (ctxt->copy == APC_COPY_OUT) { ZVAL_DUP(dst, src); } else { Z_TYPE_INFO_P(dst) = IS_STRING_EX; Z_STR_P(dst) = apc_pstrcpy(Z_STR_P(src), pool); } break; case IS_ARRAY: if(ctxt->serializer == NULL) { Z_ARRVAL_P(dst) = my_copy_hashtable(Z_ARRVAL_P(src), ctxt); break; } /* break intentionally omitted */ case IS_OBJECT: if(ctxt->copy == APC_COPY_IN) { dst = my_serialize_object(dst, src, ctxt); } else dst = my_unserialize_object(dst, src, ctxt); break; case IS_CALLABLE: /* XXX implement this */ assert(0); break; default: assert(0); } if (Z_REFCOUNTED_P(dst) && ctxt->copied.nTableSize) { zend_hash_index_update(&ctxt->copied, (uintptr_t) Z_COUNTED_P(src), dst); } }