Skip to content

Commit 662497e

Browse files
committed
fix(opcache): persist substituted property hooks and skip SHM destroy
Signed-off-by: azjezz <azjezz@protonmail.com>
1 parent d857878 commit 662497e

4 files changed

Lines changed: 101 additions & 3 deletions

File tree

Zend/Optimizer/zend_optimizer.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,34 @@ ZEND_API void zend_optimize_script(zend_script *script, zend_long optimization_l
17481748
}
17491749
}
17501750
} ZEND_HASH_FOREACH_END();
1751+
1752+
zend_property_info *prop;
1753+
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, name, prop) {
1754+
if (prop->ce == ce || !prop->hooks) {
1755+
continue;
1756+
}
1757+
1758+
const zend_property_info *parent_prop = zend_hash_find_ptr(&prop->ce->properties_info, name);
1759+
if (!parent_prop || parent_prop == prop || !parent_prop->hooks) {
1760+
continue;
1761+
}
1762+
1763+
for (uint32_t hi = 0; hi < ZEND_PROPERTY_HOOK_COUNT; hi++) {
1764+
zend_function *clone_hook = prop->hooks[hi];
1765+
zend_function *parent_hook = parent_prop->hooks[hi];
1766+
if (!clone_hook || !parent_hook || clone_hook == parent_hook) {
1767+
continue;
1768+
}
1769+
1770+
zend_arg_info *arg_info = clone_hook->op_array.arg_info;
1771+
bool arg_info_substituted = (arg_info != parent_hook->op_array.arg_info);
1772+
1773+
clone_hook->op_array = parent_hook->op_array;
1774+
if (arg_info_substituted) {
1775+
clone_hook->op_array.arg_info = arg_info;
1776+
}
1777+
}
1778+
} ZEND_HASH_FOREACH_END();
17511779
} ZEND_HASH_FOREACH_END();
17521780

17531781
zend_optimizer_call_registered_passes(script, &ctx);

Zend/zend_opcode.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,22 @@ ZEND_API void zend_generic_type_table_destroy(zend_generic_type_table *table) {
188188
if (!table) {
189189
return;
190190
}
191+
192+
bool persisted = false;
193+
#define MAYBE_PERSISTED(ht) ((ht) && (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE))
194+
if (MAYBE_PERSISTED(table->parameters)
195+
|| MAYBE_PERSISTED(table->properties)
196+
|| MAYBE_PERSISTED(table->class_constants)
197+
|| MAYBE_PERSISTED(table->implements)
198+
|| MAYBE_PERSISTED(table->trait_uses)
199+
|| MAYBE_PERSISTED(table->turbofish_args)) {
200+
persisted = true;
201+
}
202+
#undef MAYBE_PERSISTED
203+
if (persisted) {
204+
return;
205+
}
206+
191207
if (table->return_type) {
192208
zend_type_release(*table->return_type, /* persistent */ false);
193209
efree(table->return_type);

ext/opcache/zend_persist.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,41 @@ static zend_property_info *zend_persist_property_info(zend_property_info *prop)
10281028
return prop;
10291029
}
10301030

1031+
static zend_property_info *zend_persist_substituted_property_info(zend_property_info *prop)
1032+
{
1033+
zend_class_entry *ce;
1034+
prop = zend_shared_memdup_put(prop, sizeof(zend_property_info));
1035+
ce = zend_shared_alloc_get_xlat_entry(prop->ce);
1036+
if (ce) {
1037+
prop->ce = ce;
1038+
}
1039+
1040+
if (prop->prototype) {
1041+
const zend_property_info *xlat_proto = zend_shared_alloc_get_xlat_entry(prop->prototype);
1042+
if (xlat_proto) {
1043+
prop->prototype = xlat_proto;
1044+
}
1045+
}
1046+
1047+
zend_persist_type(&prop->type);
1048+
if (prop->hooks) {
1049+
prop->hooks = zend_shared_memdup_put(prop->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1050+
for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1051+
if (prop->hooks[i]) {
1052+
zend_op_array *hook = zend_persist_class_method(&prop->hooks[i]->op_array, prop->ce);
1053+
const zend_property_info *new_prop_info = zend_shared_alloc_get_xlat_entry(hook->prop_info);
1054+
if (new_prop_info) {
1055+
hook->prop_info = new_prop_info;
1056+
}
1057+
1058+
prop->hooks[i] = (zend_function *) hook;
1059+
}
1060+
}
1061+
}
1062+
1063+
return prop;
1064+
}
1065+
10311066
static void zend_persist_class_constant(zval *zv)
10321067
{
10331068
const zend_class_constant *orig_c = Z_PTR_P(zv);
@@ -1163,9 +1198,11 @@ zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce)
11631198
if (prop->ce == orig_ce) {
11641199
Z_PTR(p->val) = zend_persist_property_info(prop);
11651200
} else {
1166-
prop = zend_shared_alloc_get_xlat_entry(prop);
1167-
if (prop) {
1168-
Z_PTR(p->val) = prop;
1201+
zend_property_info *xlat_prop = zend_shared_alloc_get_xlat_entry(prop);
1202+
if (xlat_prop) {
1203+
Z_PTR(p->val) = xlat_prop;
1204+
} else if (!zend_accel_in_shm(prop)) {
1205+
Z_PTR(p->val) = zend_persist_substituted_property_info(prop);
11691206
} else {
11701207
/* This can happen if preloading is used and we inherit a property from an
11711208
* internal class. In that case we should keep pointing to the internal

ext/opcache/zend_persist_calc.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,20 @@ static void zend_persist_property_info_calc(zend_property_info *prop)
565565
}
566566
}
567567

568+
static void zend_persist_substituted_property_info_calc(zend_property_info *prop)
569+
{
570+
ADD_SIZE(sizeof(zend_property_info));
571+
zend_persist_type_calc(&prop->type);
572+
if (prop->hooks) {
573+
ADD_SIZE(ZEND_PROPERTY_HOOK_STRUCT_SIZE);
574+
for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
575+
if (prop->hooks[i]) {
576+
zend_persist_class_method_calc(&prop->hooks[i]->op_array);
577+
}
578+
}
579+
}
580+
}
581+
568582
static void zend_persist_class_constant_calc(const zval *zv)
569583
{
570584
zend_class_constant *c = Z_PTR_P(zv);
@@ -648,6 +662,9 @@ void zend_persist_class_entry_calc(zend_class_entry *ce)
648662
ADD_INTERNED_STRING(p->key);
649663
if (prop->ce == ce) {
650664
zend_persist_property_info_calc(prop);
665+
} else if (!zend_accel_in_shm(prop) && !zend_shared_alloc_get_xlat_entry(prop)) {
666+
zend_shared_alloc_register_xlat_entry(prop, prop);
667+
zend_persist_substituted_property_info_calc(prop);
651668
}
652669
} ZEND_HASH_FOREACH_END();
653670

0 commit comments

Comments
 (0)