@@ -277,6 +277,8 @@ typedef struct _zend_jit_ctx {
277
277
ir_ref tls;
278
278
#endif
279
279
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 */
280
282
ir_ref trace_loop_ref;
281
283
ir_ref return_inputs;
282
284
const zend_op_array *op_array;
@@ -624,12 +626,12 @@ static void jit_SNAPSHOT(zend_jit_ctx *jit, ir_ref addr)
624
626
uint32_t exit_point = 0, n = 0;
625
627
626
628
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;
633
635
}
634
636
}
635
637
@@ -660,8 +662,8 @@ static void jit_SNAPSHOT(zend_jit_ctx *jit, ir_ref addr)
660
662
ir_SNAPSHOT_SET_OP(snapshot, i + 1, ref);
661
663
}
662
664
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 );
665
667
}
666
668
}
667
669
}
@@ -710,6 +712,31 @@ uint32_t zend_jit_duplicate_exit_point(ir_ctx *ctx, zend_jit_trace_info *t, uint
710
712
return new_exit_point;
711
713
}
712
714
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
+
713
740
void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
714
741
{
715
742
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
722
749
exit_flags = t->exit_info[exit_point].flags;
723
750
724
751
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);
726
755
727
- ZEND_ASSERT(reg_ops[n - 1] != -1 && reg_ops[n] != -1);
728
756
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) )) {
731
759
exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
732
760
addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
733
761
exit_flags &= ~ZEND_JIT_EXIT_FIXED;
734
762
}
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 ;
737
765
n -= 2;
738
766
}
739
767
@@ -2751,6 +2779,8 @@ static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
2751
2779
jit->tls = IR_UNUSED;
2752
2780
#endif
2753
2781
jit->fp = IR_UNUSED;
2782
+ jit->poly_func_ref = IR_UNUSED;
2783
+ jit->poly_this_ref = IR_UNUSED;
2754
2784
jit->trace_loop_ref = IR_UNUSED;
2755
2785
jit->return_inputs = IR_UNUSED;
2756
2786
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)
4423
4453
return ir_RLOAD(type, reg);
4424
4454
}
4425
4455
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
+
4426
4468
static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
4427
4469
{
4428
4470
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
8477
8519
return 1;
8478
8520
}
8479
8521
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 )
8481
8523
{
8482
8524
// JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8483
- ir_ref func = ir_RLOAD_A(func_reg);
8484
8525
ir_ref if_trampoline = ir_IF(ir_AND_U32(
8485
8526
ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, common.fn_flags))),
8486
8527
ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE)));
@@ -8962,15 +9003,15 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
8962
9003
zend_class_entry *trace_ce,
8963
9004
zend_jit_trace_rec *trace,
8964
9005
int checked_stack,
8965
- int8_t func_reg ,
8966
- int8_t this_reg ,
9006
+ ir_ref func_ref ,
9007
+ ir_ref this_ref ,
8967
9008
bool polymorphic_side_trace)
8968
9009
{
8969
9010
zend_func_info *info = ZEND_FUNC_INFO(op_array);
8970
9011
zend_call_info *call_info = NULL;
8971
9012
zend_function *func = NULL;
8972
9013
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;
8974
9015
8975
9016
ZEND_ASSERT(opline->op2_type == IS_CONST);
8976
9017
ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
@@ -8988,10 +9029,8 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
8988
9029
}
8989
9030
8990
9031
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);
8995
9034
} else {
8996
9035
ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
8997
9036
@@ -9137,8 +9176,8 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
9137
9176
return 0;
9138
9177
}
9139
9178
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;
9142
9181
9143
9182
func = (zend_function*)trace->func;
9144
9183
@@ -16991,9 +17030,13 @@ static int zend_jit_trace_start(zend_jit_ctx *jit,
16991
17030
}
16992
17031
16993
17032
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
+ }
16997
17040
}
16998
17041
16999
17042
ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
0 commit comments