@@ -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
@@ -2709,6 +2737,8 @@ static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
2709
2737
jit->tls = IR_UNUSED;
2710
2738
#endif
2711
2739
jit->fp = IR_UNUSED;
2740
+ jit->poly_func_ref = IR_UNUSED;
2741
+ jit->poly_this_ref = IR_UNUSED;
2712
2742
jit->trace_loop_ref = IR_UNUSED;
2713
2743
jit->return_inputs = IR_UNUSED;
2714
2744
jit->bb_start_ref = NULL;
@@ -4386,6 +4416,18 @@ static ir_ref zend_jit_deopt_rload(zend_jit_ctx *jit, ir_type type, int32_t reg)
4386
4416
return ir_RLOAD(type, reg);
4387
4417
}
4388
4418
4419
+ /* Same as zend_jit_deopt_rload(), but 'reg' may be spilled on C stack */
4420
+ static ir_ref zend_jit_deopt_rload_spilled(zend_jit_ctx *jit, ir_type type, int8_t reg, int32_t offset)
4421
+ {
4422
+ ZEND_ASSERT(reg >= 0);
4423
+
4424
+ if (IR_REG_SPILLED(reg)) {
4425
+ return ir_LOAD(type, ir_ADD_OFFSET(zend_jit_deopt_rload(jit, type, IR_REG_NUM(reg)), offset));
4426
+ } else {
4427
+ return zend_jit_deopt_rload(jit, type, reg);
4428
+ }
4429
+ }
4430
+
4389
4431
static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
4390
4432
{
4391
4433
zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
@@ -8440,10 +8482,9 @@ static int zend_jit_stack_check(zend_jit_ctx *jit, const zend_op *opline, uint32
8440
8482
return 1;
8441
8483
}
8442
8484
8443
- static int zend_jit_free_trampoline(zend_jit_ctx *jit, int8_t func_reg )
8485
+ static int zend_jit_free_trampoline(zend_jit_ctx *jit, ir_ref func )
8444
8486
{
8445
8487
// JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8446
- ir_ref func = ir_RLOAD_A(func_reg);
8447
8488
ir_ref if_trampoline = ir_IF(ir_AND_U32(
8448
8489
ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, common.fn_flags))),
8449
8490
ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE)));
@@ -8537,8 +8578,8 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
8537
8578
}
8538
8579
8539
8580
if (may_be_trampoline) {
8540
- jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
8541
- jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
8581
+ jit->trace->exit_info[exit_point].poly_func.ref = func_ref;
8582
+ jit->trace->exit_info[exit_point].poly_this.ref = this_ref;
8542
8583
}
8543
8584
8544
8585
ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
@@ -8936,15 +8977,15 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
8936
8977
zend_class_entry *trace_ce,
8937
8978
zend_jit_trace_rec *trace,
8938
8979
int checked_stack,
8939
- int8_t func_reg ,
8940
- int8_t this_reg ,
8980
+ ir_ref func_ref ,
8981
+ ir_ref this_ref ,
8941
8982
bool polymorphic_side_trace)
8942
8983
{
8943
8984
zend_func_info *info = ZEND_FUNC_INFO(op_array);
8944
8985
zend_call_info *call_info = NULL;
8945
8986
zend_function *func = NULL;
8946
8987
zval *function_name;
8947
- ir_ref if_static = IR_UNUSED, cold_path, this_ref = IR_NULL, func_ref = IR_NULL ;
8988
+ ir_ref if_static = IR_UNUSED, cold_path;
8948
8989
8949
8990
ZEND_ASSERT(opline->op2_type == IS_CONST);
8950
8991
ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
@@ -8962,10 +9003,8 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
8962
9003
}
8963
9004
8964
9005
if (polymorphic_side_trace) {
8965
- /* function is passed in r0 from parent_trace */
8966
- ZEND_ASSERT(func_reg >= 0 && this_reg >= 0);
8967
- func_ref = zend_jit_deopt_rload(jit, IR_ADDR, func_reg);
8968
- this_ref = zend_jit_deopt_rload(jit, IR_ADDR, this_reg);
9006
+ /* function is passed from parent snapshot */
9007
+ ZEND_ASSERT(func_ref != IR_UNUSED && this_ref != IR_UNUSED);
8969
9008
} else {
8970
9009
ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
8971
9010
@@ -9111,8 +9150,8 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
9111
9150
return 0;
9112
9151
}
9113
9152
9114
- jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
9115
- jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
9153
+ jit->trace->exit_info[exit_point].poly_func.ref = func_ref;
9154
+ jit->trace->exit_info[exit_point].poly_this.ref = this_ref;
9116
9155
9117
9156
func = (zend_function*)trace->func;
9118
9157
@@ -17319,9 +17358,13 @@ static int zend_jit_trace_start(zend_jit_ctx *jit,
17319
17358
}
17320
17359
17321
17360
if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
17322
- ZEND_ASSERT(parent->exit_info[exit_num].poly_func_reg >= 0 && parent->exit_info[exit_num].poly_this_reg >= 0);
17323
- ir_RLOAD_A(parent->exit_info[exit_num].poly_func_reg);
17324
- ir_RLOAD_A(parent->exit_info[exit_num].poly_this_reg);
17361
+ ZEND_ASSERT(parent->exit_info[exit_num].poly_func.reg >= 0 && parent->exit_info[exit_num].poly_this.reg >= 0);
17362
+ if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_func.reg)) {
17363
+ ir_RLOAD_A(parent->exit_info[exit_num].poly_func.reg);
17364
+ }
17365
+ if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_this.reg)) {
17366
+ ir_RLOAD_A(parent->exit_info[exit_num].poly_this.reg);
17367
+ }
17325
17368
}
17326
17369
17327
17370
ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
0 commit comments