@@ -642,20 +642,53 @@ static int32_t _add_trace_const(zend_jit_trace_info *t, int64_t val)
642642 return i;
643643}
644644
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+
645670void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
646671{
647672 zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
648- uint32_t exit_point;
673+ uint32_t exit_point, exit_flags ;
649674 ir_ref n = snapshot->inputs_count;
650675 ir_ref i;
651676
652677 exit_point = zend_jit_exit_point_by_addr(addr);
653678 ZEND_ASSERT(exit_point < t->exit_count);
679+ exit_flags = t->exit_info[exit_point].flags;
654680
655- if (t->exit_info[exit_point].flags & ZEND_JIT_EXIT_METHOD_CALL) {
681+ if (exit_flags & ZEND_JIT_EXIT_METHOD_CALL) {
656682 int8_t *reg_ops = ctx->regs[snapshot_ref];
657683
658684 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+ }
659692 t->exit_info[exit_point].poly_func_reg = reg_ops[n - 1];
660693 t->exit_info[exit_point].poly_this_reg = reg_ops[n];
661694 n -= 2;
@@ -672,6 +705,12 @@ void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snaps
672705 ZEND_ASSERT(var < t->exit_info[exit_point].stack_size);
673706 if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags == ZREG_ZVAL_COPY) {
674707 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+ }
675714 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
676715 } else if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_CONST) {
677716 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
682721 if (reg & IR_REG_SPILL_LOAD) {
683722 ZEND_ASSERT(!(reg & IR_REG_SPILL_SPECIAL));
684723 /* 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+ }
685732 t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = ref;
686733 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
687734 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags |= ZREG_SPILL_SLOT;
688735 } else if (reg & IR_REG_SPILL_SPECIAL) {
689736 /* 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;
690745 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
691746 } 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+ }
692753 t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
693754 }
694755 } 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+ }
695763 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
696764 }
697- } else {
765+ } else if (!(exit_flags & ZEND_JIT_EXIT_FIXED)) {
698766 int32_t idx = _add_trace_const(t, ctx->ir_base[ref].val.i64);
699767 t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_CONST;
700768 t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = idx;
701769 }
702770 }
703771 }
704772 }
773+ t->exit_info[exit_point].flags |= ZEND_JIT_EXIT_FIXED;
705774 return addr;
706775}
707776
0 commit comments