diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 5e4af150861e..4b3207367fec 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -9216,6 +9216,12 @@ static int zend_jit_init_static_method_call(zend_jit_ctx *jit, zend_function *func = NULL; ir_ref func_ref, func_ref2, scope_ref, scope_ref2, if_cached, cold_path, ref; ir_ref if_static = IR_UNUSED; + bool is_megamorphic_call_from_trait = + (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) + && opline->op1_type != IS_CONST + && trace + && trace->op == ZEND_JIT_TRACE_INIT_CALL + && trace->func; if (info) { call_info = info->callee_info; @@ -9228,6 +9234,9 @@ static int zend_jit_init_static_method_call(zend_jit_ctx *jit, } ce = zend_get_known_class(op_array, opline, opline->op1_type, opline->op1); + if (is_megamorphic_call_from_trait) { + ce = NULL; + } if (!func && ce && (opline->op1_type == IS_CONST || !(ce->ce_flags & ZEND_ACC_TRAIT))) { zval *zv = RT_CONSTANT(opline, opline->op2); zend_string *method_name; @@ -9281,14 +9290,15 @@ static int zend_jit_init_static_method_call(zend_jit_ctx *jit, func_ref = ir_PHI_2(IR_ADDR, func_ref2, func_ref); scope_ref = ir_PHI_2(IR_ADDR, scope_ref2, scope_ref); - if ((!func || zend_jit_may_be_modified(func, op_array)) + if ((is_megamorphic_call_from_trait || !func || zend_jit_may_be_modified(func, op_array)) && trace && trace->op == ZEND_JIT_TRACE_INIT_CALL && trace->func) { int32_t exit_point; const void *exit_addr; - exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : 0); + exit_point = zend_jit_trace_get_exit_point(opline, + func && !is_megamorphic_call_from_trait ? ZEND_JIT_EXIT_INVALIDATE : 0); exit_addr = zend_jit_trace_get_exit_addr(exit_point); if (!exit_addr) { return 0; diff --git a/ext/opcache/tests/jit/gh23572.phpt b/ext/opcache/tests/jit/gh23572.phpt new file mode 100644 index 000000000000..018e29cf1133 --- /dev/null +++ b/ext/opcache/tests/jit/gh23572.phpt @@ -0,0 +1,85 @@ +--TEST-- +GH-23572: Tracing JIT calls the wrong self/parent static method from trait clones +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_buffer_size=16M +opcache.jit_hot_func=2 +opcache.jit_hot_loop=255 +opcache.jit_hot_return=255 +opcache.jit_hot_side_exit=255 +--FILE-- +callParent()); +} +var_dump($b->callParent()); +var_dump($b->callParent()); +var_dump($a->callParent()); + +for ($i = 0; $i < 4; $i++) { + var_dump($a->callSelf()); +} +var_dump($b->callSelf()); +var_dump($b->callSelf()); +var_dump($a->callSelf()); +?> +--EXPECT-- +string(8) "parent A" +string(8) "parent A" +string(8) "parent A" +string(8) "parent A" +string(8) "parent B" +string(8) "parent B" +string(8) "parent A" +string(6) "self A" +string(6) "self A" +string(6) "self A" +string(6) "self A" +string(6) "self B" +string(6) "self B" +string(6) "self A"