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; } }