@@ -277,6 +277,8 @@ typedef struct _zend_jit_ctx {
277277 ir_ref tls;
278278#endif
279279 ir_ref fp;
280+ ir_ref poly_func_ref; /* restored from parent trace snapshot */
281+ ir_ref poly_this_ref; /* restored from parent trace snapshot */
280282 ir_ref trace_loop_ref;
281283 ir_ref return_inputs;
282284 const zend_op_array *op_array;
@@ -624,12 +626,12 @@ static void jit_SNAPSHOT(zend_jit_ctx *jit, ir_ref addr)
624626 uint32_t exit_point = 0, n = 0;
625627
626628 if (addr < 0) {
627- if (t->exit_count > 0
628- && jit->ctx.ir_base[addr].val.u64 == (uintptr_t)zend_jit_trace_get_exit_addr( t->exit_count - 1)) {
629- exit_point = t->exit_count - 1 ;
630- if (t->exit_info[ exit_point].flags & ZEND_JIT_EXIT_METHOD_CALL) {
631- n = 2;
632- }
629+ /* addr is not always the address of the *last* exit point,
630+ * so we can not optimize this to 'exit_point = t->exit_count-1' */
631+ exit_point = zend_jit_exit_point_by_addr(ptr) ;
632+ ZEND_ASSERT( exit_point != -1);
633+ if (t->exit_info[exit_point].flags & ZEND_JIT_EXIT_METHOD_CALL) {
634+ n = 2;
633635 }
634636 }
635637
@@ -660,8 +662,8 @@ static void jit_SNAPSHOT(zend_jit_ctx *jit, ir_ref addr)
660662 ir_SNAPSHOT_SET_OP(snapshot, i + 1, ref);
661663 }
662664 if (n) {
663- ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 1, t->exit_info[exit_point].poly_func_ref );
664- ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 2, t->exit_info[exit_point].poly_this_ref );
665+ ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 1, t->exit_info[exit_point].poly_func.ref );
666+ ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 2, t->exit_info[exit_point].poly_this.ref );
665667 }
666668 }
667669 }
@@ -710,6 +712,31 @@ uint32_t zend_jit_duplicate_exit_point(ir_ctx *ctx, zend_jit_trace_info *t, uint
710712 return new_exit_point;
711713}
712714
715+ static void zend_jit_resolve_ref_snapshot(zend_jit_ref_snapshot *dest, ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, int op)
716+ {
717+ int8_t *reg_ops = ctx->regs[snapshot_ref];
718+ ZEND_ASSERT(reg_ops[op] != ZREG_NONE);
719+
720+ int8_t reg = reg_ops[op];
721+ int32_t offset;
722+
723+ if (IR_REG_SPILLED(reg)) {
724+ reg = ((ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP) | IR_REG_SPILL_LOAD;
725+ offset = ir_get_spill_slot_offset(ctx, ir_insn_op(snapshot, op));
726+ } else {
727+ offset = 0;
728+ }
729+
730+ dest->reg = reg;
731+ dest->offset = offset;
732+ }
733+
734+ static bool zend_jit_ref_snapshot_equals(const zend_jit_ref_snapshot *a, const zend_jit_ref_snapshot *b)
735+ {
736+ return a->reg == b->reg
737+ && (!IR_REG_SPILLED(a->reg) || (a->offset == b->offset));
738+ }
739+
713740void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
714741{
715742 zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
@@ -722,18 +749,19 @@ void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snaps
722749 exit_flags = t->exit_info[exit_point].flags;
723750
724751 if (exit_flags & ZEND_JIT_EXIT_METHOD_CALL) {
725- int8_t *reg_ops = ctx->regs[snapshot_ref];
752+ zend_jit_ref_snapshot func, this;
753+ zend_jit_resolve_ref_snapshot(&func, ctx, snapshot_ref, snapshot, n - 1);
754+ zend_jit_resolve_ref_snapshot(&this, ctx, snapshot_ref, snapshot, n);
726755
727- ZEND_ASSERT(reg_ops[n - 1] != -1 && reg_ops[n] != -1);
728756 if ((exit_flags & ZEND_JIT_EXIT_FIXED)
729- && (t->exit_info[exit_point].poly_func_reg != reg_ops[n - 1]
730- || t->exit_info[exit_point].poly_this_reg != reg_ops[n] )) {
757+ && (!zend_jit_ref_snapshot_equals(& t->exit_info[exit_point].poly_func, &func)
758+ || !zend_jit_ref_snapshot_equals(& t->exit_info[exit_point].poly_this, &this) )) {
731759 exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
732760 addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
733761 exit_flags &= ~ZEND_JIT_EXIT_FIXED;
734762 }
735- t->exit_info[exit_point].poly_func_reg = reg_ops[n - 1] ;
736- t->exit_info[exit_point].poly_this_reg = reg_ops[n] ;
763+ t->exit_info[exit_point].poly_func = func ;
764+ t->exit_info[exit_point].poly_this = this ;
737765 n -= 2;
738766 }
739767
@@ -2751,6 +2779,8 @@ static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
27512779 jit->tls = IR_UNUSED;
27522780#endif
27532781 jit->fp = IR_UNUSED;
2782+ jit->poly_func_ref = IR_UNUSED;
2783+ jit->poly_this_ref = IR_UNUSED;
27542784 jit->trace_loop_ref = IR_UNUSED;
27552785 jit->return_inputs = IR_UNUSED;
27562786 jit->bb_start_ref = NULL;
@@ -4423,6 +4453,18 @@ static ir_ref zend_jit_deopt_rload(zend_jit_ctx *jit, ir_type type, int32_t reg)
44234453 return ir_RLOAD(type, reg);
44244454}
44254455
4456+ /* Same as zend_jit_deopt_rload(), but 'reg' may be spilled on C stack */
4457+ static ir_ref zend_jit_deopt_rload_spilled(zend_jit_ctx *jit, ir_type type, int8_t reg, int32_t offset)
4458+ {
4459+ ZEND_ASSERT(reg >= 0);
4460+
4461+ if (IR_REG_SPILLED(reg)) {
4462+ return ir_LOAD(type, ir_ADD_OFFSET(zend_jit_deopt_rload(jit, type, IR_REG_NUM(reg)), offset));
4463+ } else {
4464+ return zend_jit_deopt_rload(jit, type, reg);
4465+ }
4466+ }
4467+
44264468static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
44274469{
44284470 zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
@@ -8477,10 +8519,9 @@ static int zend_jit_stack_check(zend_jit_ctx *jit, const zend_op *opline, uint32
84778519 return 1;
84788520}
84798521
8480- static int zend_jit_free_trampoline(zend_jit_ctx *jit, int8_t func_reg )
8522+ static int zend_jit_free_trampoline(zend_jit_ctx *jit, ir_ref func )
84818523{
84828524 // JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8483- ir_ref func = ir_RLOAD_A(func_reg);
84848525 ir_ref if_trampoline = ir_IF(ir_AND_U32(
84858526 ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, common.fn_flags))),
84868527 ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE)));
@@ -8962,15 +9003,15 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
89629003 zend_class_entry *trace_ce,
89639004 zend_jit_trace_rec *trace,
89649005 int checked_stack,
8965- int8_t func_reg ,
8966- int8_t this_reg ,
9006+ ir_ref func_ref ,
9007+ ir_ref this_ref ,
89679008 bool polymorphic_side_trace)
89689009{
89699010 zend_func_info *info = ZEND_FUNC_INFO(op_array);
89709011 zend_call_info *call_info = NULL;
89719012 zend_function *func = NULL;
89729013 zval *function_name;
8973- ir_ref if_static = IR_UNUSED, cold_path, this_ref = IR_NULL, func_ref = IR_NULL ;
9014+ ir_ref if_static = IR_UNUSED, cold_path;
89749015
89759016 ZEND_ASSERT(opline->op2_type == IS_CONST);
89769017 ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
@@ -8988,10 +9029,8 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
89889029 }
89899030
89909031 if (polymorphic_side_trace) {
8991- /* function is passed in r0 from parent_trace */
8992- ZEND_ASSERT(func_reg >= 0 && this_reg >= 0);
8993- func_ref = zend_jit_deopt_rload(jit, IR_ADDR, func_reg);
8994- this_ref = zend_jit_deopt_rload(jit, IR_ADDR, this_reg);
9032+ /* function is passed from parent snapshot */
9033+ ZEND_ASSERT(func_ref != IR_UNUSED && this_ref != IR_UNUSED);
89959034 } else {
89969035 ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
89979036
@@ -9137,8 +9176,8 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
91379176 return 0;
91389177 }
91399178
9140- jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
9141- jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
9179+ jit->trace->exit_info[exit_point].poly_func.ref = func_ref;
9180+ jit->trace->exit_info[exit_point].poly_this.ref = this_ref;
91429181
91439182 func = (zend_function*)trace->func;
91449183
@@ -16991,9 +17030,13 @@ static int zend_jit_trace_start(zend_jit_ctx *jit,
1699117030 }
1699217031
1699317032 if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
16994- ZEND_ASSERT(parent->exit_info[exit_num].poly_func_reg >= 0 && parent->exit_info[exit_num].poly_this_reg >= 0);
16995- ir_RLOAD_A(parent->exit_info[exit_num].poly_func_reg);
16996- ir_RLOAD_A(parent->exit_info[exit_num].poly_this_reg);
17033+ ZEND_ASSERT(parent->exit_info[exit_num].poly_func.reg >= 0 && parent->exit_info[exit_num].poly_this.reg >= 0);
17034+ if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_func.reg)) {
17035+ ir_RLOAD_A(parent->exit_info[exit_num].poly_func.reg);
17036+ }
17037+ if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_this.reg)) {
17038+ ir_RLOAD_A(parent->exit_info[exit_num].poly_this.reg);
17039+ }
1699717040 }
1699817041
1699917042 ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
0 commit comments