Skip to content

Commit ba99aa1

Browse files
committed
Fixed issues related to optimization and persitence of classes linked with interfaces, traits or internal classes.
1 parent 53ea09e commit ba99aa1

File tree

6 files changed

+93
-24
lines changed

6 files changed

+93
-24
lines changed

Zend/zend_compile.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ typedef struct _zend_oparray_context {
260260
/* User class has methods with static variables | | | */
261261
#define ZEND_HAS_STATIC_IN_METHODS (1 << 15) /* X | | | */
262262
/* | | | */
263-
/* Function Flags (unused: 26...30) | | | */
263+
/* Function Flags (unused: 27...30) | | | */
264264
/* ============== | | | */
265265
/* | | | */
266266
/* deprecation flag | | | */
@@ -310,6 +310,9 @@ typedef struct _zend_oparray_context {
310310
/* internal function is allocated at arena (int only) | | | */
311311
#define ZEND_ACC_ARENA_ALLOCATED (1 << 25) /* | X | | */
312312
/* | | | */
313+
/* op_array is a clone of trait method | | | */
314+
#define ZEND_ACC_TRAIT_CLONE (1 << 26) /* | X | | */
315+
/* | | | */
313316
/* op_array uses strict mode types | | | */
314317
#define ZEND_ACC_STRICT_TYPES (1 << 31) /* | X | | */
315318

Zend/zend_inheritance.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,7 @@ static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_s
13081308
} else {
13091309
new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
13101310
memcpy(new_fn, fn, sizeof(zend_op_array));
1311+
new_fn->op_array.fn_flags |= ZEND_ACC_TRAIT_CLONE;
13111312
new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
13121313
}
13131314
function_add_ref(new_fn);

ext/opcache/Optimizer/optimize_func_calls.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
9595
{
9696
if (func->type == ZEND_USER_FUNCTION
9797
&& !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS))
98+
/* TODO: function copied from trait may be inconsistent ??? */
99+
&& !(func->op_array.fn_flags & (ZEND_ACC_TRAIT_CLONE))
98100
&& fcall->extended_value >= func->op_array.required_num_args
99101
&& func->op_array.opcodes[func->op_array.num_args].opcode == ZEND_RETURN) {
100102

ext/opcache/Optimizer/zend_call_graph.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ static int zend_op_array_collect(zend_call_graph *call_graph, zend_op_array *op_
5353
static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *script, zend_op_array_func_t func)
5454
{
5555
zend_class_entry *ce;
56+
zend_string *key;
5657
zend_op_array *op_array;
5758

5859
if (func(call_graph, &script->main_op_array) != SUCCESS) {
@@ -65,9 +66,12 @@ static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *scrip
6566
}
6667
} ZEND_HASH_FOREACH_END();
6768

68-
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
69+
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
70+
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
71+
continue;
72+
}
6973
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
70-
if (op_array->scope == ce) {
74+
if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
7175
if (func(call_graph, op_array) != SUCCESS) {
7276
return FAILURE;
7377
}

ext/opcache/Optimizer/zend_optimizer.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,7 @@ static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
14211421
int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level)
14221422
{
14231423
zend_class_entry *ce;
1424+
zend_string *key;
14241425
zend_op_array *op_array;
14251426
zend_string *name;
14261427
zend_optimizer_ctx ctx;
@@ -1440,9 +1441,12 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
14401441
zend_optimize_op_array(op_array, &ctx);
14411442
} ZEND_HASH_FOREACH_END();
14421443

1443-
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
1444+
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
1445+
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
1446+
continue;
1447+
}
14441448
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
1445-
if (op_array->scope == ce) {
1449+
if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
14461450
zend_optimize_op_array(op_array, &ctx);
14471451
}
14481452
} ZEND_HASH_FOREACH_END();
@@ -1544,27 +1548,35 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
15441548
zend_adjust_fcall_stack_size(op_array, &ctx);
15451549
} ZEND_HASH_FOREACH_END();
15461550

1547-
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
1551+
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
1552+
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
1553+
continue;
1554+
}
15481555
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
1549-
if (op_array->scope == ce) {
1556+
if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
15501557
zend_adjust_fcall_stack_size(op_array, &ctx);
15511558
}
15521559
} ZEND_HASH_FOREACH_END();
15531560
} ZEND_HASH_FOREACH_END();
15541561
}
15551562

1556-
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
1563+
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
1564+
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
1565+
continue;
1566+
}
15571567
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
15581568
if (op_array->scope != ce && op_array->type == ZEND_USER_FUNCTION) {
15591569
zend_op_array *orig_op_array =
15601570
zend_hash_find_ptr(&op_array->scope->function_table, name);
15611571

15621572
ZEND_ASSERT(orig_op_array != NULL);
15631573
if (orig_op_array != op_array) {
1574+
uint32_t fn_flags = op_array->fn_flags;
15641575
zend_function *prototype = op_array->prototype;
15651576
HashTable *ht = op_array->static_variables;
15661577

15671578
*op_array = *orig_op_array;
1579+
op_array->fn_flags = fn_flags;
15681580
op_array->prototype = prototype;
15691581
op_array->static_variables = ht;
15701582
}
@@ -1582,7 +1594,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
15821594

15831595
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
15841596
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
1585-
if (op_array->scope == ce) {
1597+
if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
15861598
zend_dump_op_array(op_array, ZEND_DUMP_RT_CONSTANTS, "after optimizer", NULL);
15871599
}
15881600
} ZEND_HASH_FOREACH_END();

ext/opcache/zend_persist.c

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ static void zend_persist_class_method(zval *zv)
719719
static void zend_persist_property_info(zval *zv)
720720
{
721721
zend_property_info *prop = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv));
722+
zend_class_entry *ce;
722723

723724
if (prop) {
724725
Z_PTR_P(zv) = prop;
@@ -729,7 +730,10 @@ static void zend_persist_property_info(zval *zv)
729730
} else {
730731
prop = Z_PTR_P(zv) = zend_shared_memdup_arena_put(Z_PTR_P(zv), sizeof(zend_property_info));
731732
}
732-
prop->ce = zend_shared_alloc_get_xlat_entry(prop->ce);
733+
ce = zend_shared_alloc_get_xlat_entry(prop->ce);
734+
if (ce) {
735+
prop->ce = ce;
736+
}
733737
zend_accel_store_interned_string(prop->name);
734738
if (prop->doc_comment) {
735739
if (ZCG(accel_directives).save_comments) {
@@ -747,6 +751,7 @@ static void zend_persist_property_info(zval *zv)
747751
static void zend_persist_class_constant(zval *zv)
748752
{
749753
zend_class_constant *c = zend_shared_alloc_get_xlat_entry(Z_PTR_P(zv));
754+
zend_class_entry *ce;
750755

751756
if (c) {
752757
Z_PTR_P(zv) = c;
@@ -758,7 +763,10 @@ static void zend_persist_class_constant(zval *zv)
758763
c = Z_PTR_P(zv) = zend_shared_memdup_arena_put(Z_PTR_P(zv), sizeof(zend_class_constant));
759764
}
760765
zend_persist_zval(&c->value);
761-
c->ce = zend_shared_alloc_get_xlat_entry(c->ce);
766+
ce = zend_shared_alloc_get_xlat_entry(c->ce);
767+
if (ce) {
768+
c->ce = ce;
769+
}
762770
if (c->doc_comment) {
763771
if (ZCG(accel_directives).save_comments) {
764772
zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
@@ -982,43 +990,82 @@ static int zend_update_parent_ce(zval *zv)
982990

983991
/* update methods */
984992
if (ce->constructor) {
985-
ce->constructor = zend_shared_alloc_get_xlat_entry(ce->constructor);
993+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->constructor);
994+
if (tmp != NULL) {
995+
ce->constructor = tmp;
996+
}
986997
}
987998
if (ce->destructor) {
988-
ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor);
999+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->destructor);
1000+
if (tmp != NULL) {
1001+
ce->destructor = tmp;
1002+
}
9891003
}
9901004
if (ce->clone) {
991-
ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone);
1005+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->clone);
1006+
if (tmp != NULL) {
1007+
ce->clone = tmp;
1008+
}
9921009
}
9931010
if (ce->__get) {
994-
ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get);
1011+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__get);
1012+
if (tmp != NULL) {
1013+
ce->__get = tmp;
1014+
}
9951015
}
9961016
if (ce->__set) {
997-
ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set);
1017+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__set);
1018+
if (tmp != NULL) {
1019+
ce->__set = tmp;
1020+
}
9981021
}
9991022
if (ce->__call) {
1000-
ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call);
1023+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__call);
1024+
if (tmp != NULL) {
1025+
ce->__call = tmp;
1026+
}
10011027
}
10021028
if (ce->serialize_func) {
1003-
ce->serialize_func = zend_shared_alloc_get_xlat_entry(ce->serialize_func);
1029+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->serialize_func);
1030+
if (tmp != NULL) {
1031+
ce->serialize_func = tmp;
1032+
}
10041033
}
10051034
if (ce->unserialize_func) {
1006-
ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func);
1035+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->unserialize_func);
1036+
if (tmp != NULL) {
1037+
ce->unserialize_func = tmp;
1038+
}
10071039
}
10081040
if (ce->__isset) {
1009-
ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset);
1041+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__isset);
1042+
if (tmp != NULL) {
1043+
ce->__isset = tmp;
1044+
}
10101045
}
10111046
if (ce->__unset) {
1012-
ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset);
1047+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__unset);
1048+
if (tmp != NULL) {
1049+
ce->__unset = tmp;
1050+
}
10131051
}
10141052
if (ce->__tostring) {
1015-
ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring);
1053+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__tostring);
1054+
if (tmp != NULL) {
1055+
ce->__tostring = tmp;
1056+
}
10161057
}
10171058
if (ce->__callstatic) {
1018-
ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
1059+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
1060+
if (tmp != NULL) {
1061+
ce->__callstatic = tmp;
1062+
}
10191063
}
10201064
if (ce->__debugInfo) {
1021-
ce->__debugInfo = zend_shared_alloc_get_xlat_entry(ce->__debugInfo);
1065+
zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__debugInfo);
1066+
if (tmp != NULL) {
1067+
ce->__debugInfo = tmp;
1068+
}
10221069
}
10231070
// zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce);
10241071
return 0;

0 commit comments

Comments
 (0)