(*op_array->refcount)++;
if (op_array->static_variables) {
- op_array->static_variables = zend_array_dup(op_array->static_variables);
+ if (!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
+ GC_REFCOUNT(op_array->static_variables)++;
+ }
}
op_array->run_time_cache = NULL;
} else if (function->type == ZEND_INTERNAL_FUNCTION) {
zend_hash_init(CG(active_op_array)->static_variables, 8, NULL, ZVAL_PTR_DTOR, 0);
}
+ if (GC_REFCOUNT(CG(active_op_array)->static_variables) > 1) {
+ if (!(GC_FLAGS(CG(active_op_array)->static_variables) & IS_ARRAY_IMMUTABLE)) {
+ GC_REFCOUNT(CG(active_op_array)->static_variables)--;
+ }
+ CG(active_op_array)->static_variables = zend_array_dup(CG(active_op_array)->static_variables);
+ }
zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value);
opline = zend_emit_op(&result, by_ref ? ZEND_FETCH_W : ZEND_FETCH_R, &var_node, NULL);
} else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) {
ZEND_ASSERT(EX(func)->op_array.static_variables != NULL);
ht = EX(func)->op_array.static_variables;
+ if (GC_REFCOUNT(ht) > 1) {
+ if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
+ GC_REFCOUNT(ht)--;
+ }
+ EX(func)->op_array.static_variables = ht = zend_array_dup(ht);
+ }
} else {
ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL);
if (!EX(symbol_table)) {
ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array)
{
- if (op_array->static_variables) {
+ if (op_array->static_variables &&
+ !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
zend_hash_clean(op_array->static_variables);
}
}
zval *end;
uint32_t i;
- if (op_array->static_variables) {
- zend_hash_destroy(op_array->static_variables);
- FREE_HASHTABLE(op_array->static_variables);
+ if (op_array->static_variables &&
+ !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
+ if (--GC_REFCOUNT(op_array->static_variables) == 0) {
+ zend_array_destroy(op_array->static_variables);
+ FREE_HASHTABLE(op_array->static_variables);
+ }
}
if (op_array->run_time_cache && !op_array->function_name) {
#define IS_STR_CONSTANT (1<<3) /* constant index */
#define IS_STR_CONSTANT_UNQUALIFIED (1<<4) /* the same as IS_CONSTANT_UNQUALIFIED */
+/* array flags */
+#define IS_ARRAY_IMMUTABLE (1<<1) /* the same as IS_TYPE_IMMUTABLE */
+
/* object flags (zval.value->gc.u.flags) */
#define IS_OBJ_APPLY_COUNT 0x07
#define IS_OBJ_DESTRUCTOR_CALLED (1<<3)
return ZEND_HASH_APPLY_STOP;
} else {
if (function->op_array.static_variables) {
- accel_fast_hash_destroy(function->op_array.static_variables);
+ if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
+ if (--GC_REFCOUNT(function->op_array.static_variables) == 0) {
+ accel_fast_hash_destroy(function->op_array.static_variables);
+ }
+ }
function->op_array.static_variables = NULL;
}
return ZEND_HASH_APPLY_REMOVE;
break;
} else {
if (func->op_array.static_variables) {
- accel_fast_hash_destroy(func->op_array.static_variables);
+ if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
+ if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
+ accel_fast_hash_destroy(func->op_array.static_variables);
+ }
+ }
}
zend_accel_fast_del_bucket(EG(function_table), _idx-1, _p);
}
ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
if (func->type == ZEND_USER_FUNCTION) {
if (func->op_array.static_variables) {
- accel_fast_hash_destroy(func->op_array.static_variables);
+ if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
+ if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
+ accel_fast_hash_destroy(func->op_array.static_variables);
+ }
+ }
func->op_array.static_variables = NULL;
}
}
if (function->type == ZEND_USER_FUNCTION) {
if (function->op_array.static_variables) {
-
- FREE_HASHTABLE(function->op_array.static_variables);
+ if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
+ if (--GC_REFCOUNT(function->op_array.static_variables) == 0) {
+ FREE_HASHTABLE(function->op_array.static_variables);
+ }
+ }
function->op_array.static_variables = NULL;
}
}
/* protect reference count */
op_array->refcount = &zend_accel_refcount;
(*op_array->refcount) = ZEND_PROTECTED_REFCOUNT;
-
- /* copy statics */
- if (UNEXPECTED(op_array->static_variables)) {
- HashTable *shared_statics = op_array->static_variables;
-
- ALLOC_HASHTABLE(op_array->static_variables);
- GC_REFCOUNT(op_array->static_variables) = 1;
- GC_TYPE(op_array->static_variables) = IS_ARRAY;
- zend_hash_clone_zval(op_array->static_variables, shared_statics, 0);
- }
}
static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce)
/* make immutable array */
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
+ GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
}
}
/* make immutable array */
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
+ GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
}
}
} else {
zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref));
Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z));
+ Z_TYPE_FLAGS_P(z) = IS_TYPE_CONSTANT | IS_TYPE_IMMUTABLE;
+ GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
}
break;
}
}
if (op_array->static_variables) {
- zend_hash_persist(op_array->static_variables, zend_persist_zval);
- zend_accel_store(op_array->static_variables, sizeof(HashTable));
+ HashTable *stored = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
+
+ if (stored) {
+ op_array->static_variables = stored;
+ } else {
+ zend_hash_persist(op_array->static_variables, zend_persist_zval_const);
+ zend_accel_store(op_array->static_variables, sizeof(HashTable));
+ /* make immutable array */
+ GC_REFCOUNT(op_array->static_variables) = 2;
+ GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << 8);
+ op_array->static_variables->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
+ }
}
if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
}
if (op_array->static_variables) {
- ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable));
- zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc);
+ if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) {
+ HashTable *old = op_array->static_variables;
+
+ ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable));
+ zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc);
+ zend_shared_alloc_register_xlat_entry(old, op_array->static_variables);
+ }
}
if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
/* Return an empty array in case no static variables exist */
array_init(return_value);
if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) {
+ if (GC_REFCOUNT(fptr->op_array.static_variables) > 1) {
+ if (!(GC_FLAGS(fptr->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
+ GC_REFCOUNT(fptr->op_array.static_variables)--;
+ }
+ fptr->op_array.static_variables = zend_array_dup(fptr->op_array.static_variables);
+ }
zend_hash_apply_with_argument(fptr->op_array.static_variables, (apply_func_arg_t) zval_update_constant_inline_change, fptr->common.scope);
zend_hash_copy(Z_ARRVAL_P(return_value), fptr->op_array.static_variables, zval_add_ref);
}