diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 8d34e0107c6..0736dba15b9 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -260,7 +260,7 @@ typedef struct _zend_oparray_context { /* User class has methods with static variables | | | */ #define ZEND_HAS_STATIC_IN_METHODS (1 << 15) /* X | | | */ /* | | | */ -/* Function Flags (unused: 26...30) | | | */ +/* Function Flags (unused: 27...30) | | | */ /* ============== | | | */ /* | | | */ /* deprecation flag | | | */ @@ -310,6 +310,9 @@ typedef struct _zend_oparray_context { /* internal function is allocated at arena (int only) | | | */ #define ZEND_ACC_ARENA_ALLOCATED (1 << 25) /* | X | | */ /* | | | */ +/* op_array is a clone of trait method | | | */ +#define ZEND_ACC_TRAIT_CLONE (1 << 26) /* | X | | */ +/* | | | */ /* op_array uses strict mode types | | | */ #define ZEND_ACC_STRICT_TYPES (1 << 31) /* | X | | */ diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 132b48b53fd..1abf2d9817f 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1308,6 +1308,7 @@ static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_s } else { new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); memcpy(new_fn, fn, sizeof(zend_op_array)); + new_fn->op_array.fn_flags |= ZEND_ACC_TRAIT_CLONE; new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE; } function_add_ref(new_fn); diff --git a/ext/opcache/Optimizer/zend_call_graph.c b/ext/opcache/Optimizer/zend_call_graph.c index d70cb0d33b4..0769b613ab8 100644 --- a/ext/opcache/Optimizer/zend_call_graph.c +++ b/ext/opcache/Optimizer/zend_call_graph.c @@ -67,7 +67,7 @@ static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *scrip ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) { - if (op_array->scope == ce) { + if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) { if (func(call_graph, op_array) != SUCCESS) { return FAILURE; } diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 6ffa08e0ebd..6ea7d1296e4 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -1442,7 +1442,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) { - if (op_array->scope == ce) { + if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) { zend_optimize_op_array(op_array, &ctx); } } ZEND_HASH_FOREACH_END(); @@ -1546,7 +1546,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) { - if (op_array->scope == ce) { + if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) { zend_adjust_fcall_stack_size(op_array, &ctx); } } ZEND_HASH_FOREACH_END(); @@ -1582,7 +1582,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend ZEND_HASH_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) { - if (op_array->scope == ce) { + if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) { zend_dump_op_array(op_array, ZEND_DUMP_RT_CONSTANTS, "after optimizer", NULL); } } ZEND_HASH_FOREACH_END(); diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index e4fe18c8f0a..b9576961ddc 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -3534,9 +3534,44 @@ static void preload_remove_empty_includes(void) static int preload_optimize(zend_persistent_script *script) { + zend_class_entry *ce; + zend_op_array *op_array; + + zend_shared_alloc_init_xlat_table(); + + ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) { + if (ce->ce_flags & ZEND_ACC_TRAIT) { + ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) { + if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) { + zend_shared_alloc_register_xlat_entry(op_array->opcodes, op_array); + } + } ZEND_HASH_FOREACH_END(); + } + } ZEND_HASH_FOREACH_END(); + if (!zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) { return FAILURE; } + + ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) { + if (ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS) { + ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) { + if (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) { + zend_op_array *orig_op_array = zend_shared_alloc_get_xlat_entry(op_array->opcodes); + uint32_t fn_flags = op_array->fn_flags; + zend_function *prototype = op_array->prototype; + HashTable *ht = op_array->static_variables; + *op_array = *orig_op_array; + op_array->fn_flags = fn_flags; + op_array->prototype = prototype; + op_array->static_variables = ht; + } + } ZEND_HASH_FOREACH_END(); + } + } ZEND_HASH_FOREACH_END(); + + zend_shared_alloc_destroy_xlat_table(); + ZEND_HASH_FOREACH_PTR(preload_scripts, script) { if (!zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) { return FAILURE; @@ -3729,8 +3764,6 @@ static int accel_preload(const char *config) script->ping_auto_globals_mask = zend_accel_get_auto_globals_no_jit(); } - zend_shared_alloc_init_xlat_table(); - /* Store all functions and classes in a single pseudo-file */ filename = zend_string_init("$PRELOAD$", strlen("$PRELOAD$"), 0); #if ZEND_USE_ABS_CONST_ADDR @@ -3767,6 +3800,8 @@ static int accel_preload(const char *config) return FAILURE; } + zend_shared_alloc_init_xlat_table(); + HANDLE_BLOCK_INTERRUPTIONS(); SHM_UNPROTECT();