@@ -642,20 +642,53 @@ static int32_t _add_trace_const(zend_jit_trace_info *t, int64_t val)
642
642
return i;
643
643
}
644
644
645
+ uint32_t zend_jit_duplicate_exit_point(ir_ctx *ctx, zend_jit_trace_info *t, uint32_t exit_point, ir_ref snapshot_ref)
646
+ {
647
+ uint32_t stack_size, stack_offset;
648
+ uint32_t new_exit_point = t->exit_count;
649
+
650
+ if (new_exit_point >= ZEND_JIT_TRACE_MAX_EXITS) {
651
+ ZEND_ASSERT(0 && "ZEND_JIT_TRACE_MAX_EXITS");
652
+ }
653
+
654
+ t->exit_count++;
655
+ memcpy(&t->exit_info[new_exit_point], &t->exit_info[exit_point], sizeof(zend_jit_trace_exit_info));
656
+ stack_size = t->exit_info[new_exit_point].stack_size;
657
+ if (stack_size != 0) {
658
+ stack_offset = t->stack_map_size;
659
+ t->stack_map_size += stack_size;
660
+ // TODO: reduce number of reallocations ???
661
+ t->stack_map = erealloc(t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
662
+ memcpy(t->stack_map + stack_offset, t->stack_map + t->exit_info[new_exit_point].stack_offset, stack_size * sizeof(zend_jit_trace_stack));
663
+ t->exit_info[new_exit_point].stack_offset = stack_offset;
664
+ }
665
+ t->exit_info[new_exit_point].flags &= ~ZEND_JIT_EXIT_FIXED;
666
+
667
+ return new_exit_point;
668
+ }
669
+
645
670
void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
646
671
{
647
672
zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
648
- uint32_t exit_point;
673
+ uint32_t exit_point, exit_flags ;
649
674
ir_ref n = snapshot->inputs_count;
650
675
ir_ref i;
651
676
652
677
exit_point = zend_jit_exit_point_by_addr(addr);
653
678
ZEND_ASSERT(exit_point < t->exit_count);
679
+ exit_flags = t->exit_info[exit_point].flags;
654
680
655
- if (t->exit_info[exit_point].flags & ZEND_JIT_EXIT_METHOD_CALL) {
681
+ if (exit_flags & ZEND_JIT_EXIT_METHOD_CALL) {
656
682
int8_t *reg_ops = ctx->regs[snapshot_ref];
657
683
658
684
ZEND_ASSERT(reg_ops[n - 1] != -1 && reg_ops[n] != -1);
685
+ if ((exit_flags & ZEND_JIT_EXIT_FIXED)
686
+ && (t->exit_info[exit_point].poly_func_reg != reg_ops[n - 1]
687
+ || t->exit_info[exit_point].poly_this_reg != reg_ops[n])) {
688
+ exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
689
+ addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
690
+ exit_flags &= ~ZEND_JIT_EXIT_FIXED;
691
+ }
659
692
t->exit_info[exit_point].poly_func_reg = reg_ops[n - 1];
660
693
t->exit_info[exit_point].poly_this_reg = reg_ops[n];
661
694
n -= 2;
@@ -672,6 +705,12 @@ void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snaps
672
705
ZEND_ASSERT(var < t->exit_info[exit_point].stack_size);
673
706
if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags == ZREG_ZVAL_COPY) {
674
707
ZEND_ASSERT(reg != ZREG_NONE);
708
+ if ((exit_flags & ZEND_JIT_EXIT_FIXED)
709
+ && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
710
+ exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
711
+ addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
712
+ exit_flags &= ~ZEND_JIT_EXIT_FIXED;
713
+ }
675
714
t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
676
715
} else if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_CONST) {
677
716
ZEND_ASSERT(t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_LONG ||
@@ -682,26 +721,56 @@ void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snaps
682
721
if (reg & IR_REG_SPILL_LOAD) {
683
722
ZEND_ASSERT(!(reg & IR_REG_SPILL_SPECIAL));
684
723
/* spill slot on a CPU stack */
724
+ if ((exit_flags & ZEND_JIT_EXIT_FIXED)
725
+ && (t->stack_map[t->exit_info[exit_point].stack_offset + var].ref != ref
726
+ || t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
727
+ || !(t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ZREG_SPILL_SLOT))) {
728
+ exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
729
+ addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
730
+ exit_flags &= ~ZEND_JIT_EXIT_FIXED;
731
+ }
685
732
t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = ref;
686
733
t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
687
734
t->stack_map[t->exit_info[exit_point].stack_offset + var].flags |= ZREG_SPILL_SLOT;
688
735
} else if (reg & IR_REG_SPILL_SPECIAL) {
689
736
/* spill slot on a VM stack */
737
+ if ((exit_flags & ZEND_JIT_EXIT_FIXED)
738
+ && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
739
+ || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
740
+ exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
741
+ addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
742
+ exit_flags &= ~ZEND_JIT_EXIT_FIXED;
743
+ }
744
+ t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
690
745
t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
691
746
} else {
747
+ if ((exit_flags & ZEND_JIT_EXIT_FIXED)
748
+ && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
749
+ exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
750
+ addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
751
+ exit_flags &= ~ZEND_JIT_EXIT_FIXED;
752
+ }
692
753
t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
693
754
}
694
755
} else {
756
+ if ((exit_flags & ZEND_JIT_EXIT_FIXED)
757
+ && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
758
+ || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
759
+ exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
760
+ addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
761
+ exit_flags &= ~ZEND_JIT_EXIT_FIXED;
762
+ }
695
763
t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
696
764
}
697
- } else {
765
+ } else if (!(exit_flags & ZEND_JIT_EXIT_FIXED)) {
698
766
int32_t idx = _add_trace_const(t, ctx->ir_base[ref].val.i64);
699
767
t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_CONST;
700
768
t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = idx;
701
769
}
702
770
}
703
771
}
704
772
}
773
+ t->exit_info[exit_point].flags |= ZEND_JIT_EXIT_FIXED;
705
774
return addr;
706
775
}
707
776
0 commit comments