Skip to content

Commit d851137

Browse files
committedFeb 20, 2015
Lazy duplication of op_array->static_variables
1 parent 582aa41 commit d851137

9 files changed

+75
-24
lines changed
 

‎Zend/zend_compile.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,9 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */
865865

866866
(*op_array->refcount)++;
867867
if (op_array->static_variables) {
868-
op_array->static_variables = zend_array_dup(op_array->static_variables);
868+
if (!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
869+
GC_REFCOUNT(op_array->static_variables)++;
870+
}
869871
}
870872
op_array->run_time_cache = NULL;
871873
} else if (function->type == ZEND_INTERNAL_FUNCTION) {
@@ -3092,6 +3094,12 @@ static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_
30923094
zend_hash_init(CG(active_op_array)->static_variables, 8, NULL, ZVAL_PTR_DTOR, 0);
30933095
}
30943096

3097+
if (GC_REFCOUNT(CG(active_op_array)->static_variables) > 1) {
3098+
if (!(GC_FLAGS(CG(active_op_array)->static_variables) & IS_ARRAY_IMMUTABLE)) {
3099+
GC_REFCOUNT(CG(active_op_array)->static_variables)--;
3100+
}
3101+
CG(active_op_array)->static_variables = zend_array_dup(CG(active_op_array)->static_variables);
3102+
}
30953103
zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value);
30963104

30973105
opline = zend_emit_op(&result, by_ref ? ZEND_FETCH_W : ZEND_FETCH_R, &var_node, NULL);

‎Zend/zend_execute.c

+6
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,12 @@ static zend_always_inline HashTable *zend_get_target_symbol_table(zend_execute_d
11661166
} else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) {
11671167
ZEND_ASSERT(EX(func)->op_array.static_variables != NULL);
11681168
ht = EX(func)->op_array.static_variables;
1169+
if (GC_REFCOUNT(ht) > 1) {
1170+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
1171+
GC_REFCOUNT(ht)--;
1172+
}
1173+
EX(func)->op_array.static_variables = ht = zend_array_dup(ht);
1174+
}
11691175
} else {
11701176
ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL);
11711177
if (!EX(symbol_table)) {

‎Zend/zend_opcode.c

+8-4
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ ZEND_API void zend_function_dtor(zval *zv)
130130

131131
ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array)
132132
{
133-
if (op_array->static_variables) {
133+
if (op_array->static_variables &&
134+
!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
134135
zend_hash_clean(op_array->static_variables);
135136
}
136137
}
@@ -317,9 +318,12 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
317318
zval *end;
318319
uint32_t i;
319320

320-
if (op_array->static_variables) {
321-
zend_hash_destroy(op_array->static_variables);
322-
FREE_HASHTABLE(op_array->static_variables);
321+
if (op_array->static_variables &&
322+
!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
323+
if (--GC_REFCOUNT(op_array->static_variables) == 0) {
324+
zend_array_destroy(op_array->static_variables);
325+
FREE_HASHTABLE(op_array->static_variables);
326+
}
323327
}
324328

325329
if (op_array->run_time_cache && !op_array->function_name) {

‎Zend/zend_types.h

+3
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
345345
#define IS_STR_CONSTANT (1<<3) /* constant index */
346346
#define IS_STR_CONSTANT_UNQUALIFIED (1<<4) /* the same as IS_CONSTANT_UNQUALIFIED */
347347

348+
/* array flags */
349+
#define IS_ARRAY_IMMUTABLE (1<<1) /* the same as IS_TYPE_IMMUTABLE */
350+
348351
/* object flags (zval.value->gc.u.flags) */
349352
#define IS_OBJ_APPLY_COUNT 0x07
350353
#define IS_OBJ_DESTRUCTOR_CALLED (1<<3)

‎ext/opcache/ZendAccelerator.c

+15-3
Original file line numberDiff line numberDiff line change
@@ -1973,7 +1973,11 @@ static int accel_clean_non_persistent_function(zval *zv)
19731973
return ZEND_HASH_APPLY_STOP;
19741974
} else {
19751975
if (function->op_array.static_variables) {
1976-
accel_fast_hash_destroy(function->op_array.static_variables);
1976+
if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
1977+
if (--GC_REFCOUNT(function->op_array.static_variables) == 0) {
1978+
accel_fast_hash_destroy(function->op_array.static_variables);
1979+
}
1980+
}
19771981
function->op_array.static_variables = NULL;
19781982
}
19791983
return ZEND_HASH_APPLY_REMOVE;
@@ -2025,7 +2029,11 @@ static void zend_accel_fast_shutdown(void)
20252029
break;
20262030
} else {
20272031
if (func->op_array.static_variables) {
2028-
accel_fast_hash_destroy(func->op_array.static_variables);
2032+
if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
2033+
if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
2034+
accel_fast_hash_destroy(func->op_array.static_variables);
2035+
}
2036+
}
20292037
}
20302038
zend_accel_fast_del_bucket(EG(function_table), _idx-1, _p);
20312039
}
@@ -2043,7 +2051,11 @@ static void zend_accel_fast_shutdown(void)
20432051
ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
20442052
if (func->type == ZEND_USER_FUNCTION) {
20452053
if (func->op_array.static_variables) {
2046-
accel_fast_hash_destroy(func->op_array.static_variables);
2054+
if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
2055+
if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
2056+
accel_fast_hash_destroy(func->op_array.static_variables);
2057+
}
2058+
}
20472059
func->op_array.static_variables = NULL;
20482060
}
20492061
}

‎ext/opcache/zend_accelerator_util_funcs.c

+5-12
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,11 @@ static void zend_accel_destroy_zend_function(zval *zv)
5555

5656
if (function->type == ZEND_USER_FUNCTION) {
5757
if (function->op_array.static_variables) {
58-
59-
FREE_HASHTABLE(function->op_array.static_variables);
58+
if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
59+
if (--GC_REFCOUNT(function->op_array.static_variables) == 0) {
60+
FREE_HASHTABLE(function->op_array.static_variables);
61+
}
62+
}
6063
function->op_array.static_variables = NULL;
6164
}
6265
}
@@ -372,16 +375,6 @@ static zend_always_inline void zend_prepare_function_for_execution(zend_op_array
372375
/* protect reference count */
373376
op_array->refcount = &zend_accel_refcount;
374377
(*op_array->refcount) = ZEND_PROTECTED_REFCOUNT;
375-
376-
/* copy statics */
377-
if (UNEXPECTED(op_array->static_variables)) {
378-
HashTable *shared_statics = op_array->static_variables;
379-
380-
ALLOC_HASHTABLE(op_array->static_variables);
381-
GC_REFCOUNT(op_array->static_variables) = 1;
382-
GC_TYPE(op_array->static_variables) = IS_ARRAY;
383-
zend_hash_clone_zval(op_array->static_variables, shared_statics, 0);
384-
}
385378
}
386379

387380
static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce)

‎ext/opcache/zend_persist.c

+16-2
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ static void zend_persist_zval(zval *z)
204204
/* make immutable array */
205205
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
206206
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
207+
GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
207208
Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
208209
}
209210
}
@@ -258,6 +259,7 @@ static void zend_persist_zval_const(zval *z)
258259
/* make immutable array */
259260
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
260261
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
262+
GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
261263
Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
262264
}
263265
}
@@ -278,6 +280,8 @@ static void zend_persist_zval_const(zval *z)
278280
} else {
279281
zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref));
280282
Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z));
283+
Z_TYPE_FLAGS_P(z) = IS_TYPE_CONSTANT | IS_TYPE_IMMUTABLE;
284+
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
281285
}
282286
break;
283287
}
@@ -313,8 +317,18 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
313317
}
314318

315319
if (op_array->static_variables) {
316-
zend_hash_persist(op_array->static_variables, zend_persist_zval);
317-
zend_accel_store(op_array->static_variables, sizeof(HashTable));
320+
HashTable *stored = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
321+
322+
if (stored) {
323+
op_array->static_variables = stored;
324+
} else {
325+
zend_hash_persist(op_array->static_variables, zend_persist_zval_const);
326+
zend_accel_store(op_array->static_variables, sizeof(HashTable));
327+
/* make immutable array */
328+
GC_REFCOUNT(op_array->static_variables) = 2;
329+
GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << 8);
330+
op_array->static_variables->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
331+
}
318332
}
319333

320334
if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {

‎ext/opcache/zend_persist_calc.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,13 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
150150
}
151151

152152
if (op_array->static_variables) {
153-
ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable));
154-
zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc);
153+
if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) {
154+
HashTable *old = op_array->static_variables;
155+
156+
ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable));
157+
zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc);
158+
zend_shared_alloc_register_xlat_entry(old, op_array->static_variables);
159+
}
155160
}
156161

157162
if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {

‎ext/reflection/php_reflection.c

+6
Original file line numberDiff line numberDiff line change
@@ -1852,6 +1852,12 @@ ZEND_METHOD(reflection_function, getStaticVariables)
18521852
/* Return an empty array in case no static variables exist */
18531853
array_init(return_value);
18541854
if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) {
1855+
if (GC_REFCOUNT(fptr->op_array.static_variables) > 1) {
1856+
if (!(GC_FLAGS(fptr->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
1857+
GC_REFCOUNT(fptr->op_array.static_variables)--;
1858+
}
1859+
fptr->op_array.static_variables = zend_array_dup(fptr->op_array.static_variables);
1860+
}
18551861
zend_hash_apply_with_argument(fptr->op_array.static_variables, (apply_func_arg_t) zval_update_constant_inline_change, fptr->common.scope);
18561862
zend_hash_copy(Z_ARRVAL_P(return_value), fptr->op_array.static_variables, zval_add_ref);
18571863
}

0 commit comments

Comments
 (0)
Please sign in to comment.