Skip to content

Commit 18be07f

Browse files
committed
Allow exit_point duplication, when the deoptimization info differs because of spilling
1 parent e862cc8 commit 18be07f

File tree

4 files changed

+77
-4
lines changed

4 files changed

+77
-4
lines changed

ext/opcache/jit/ir

Submodule ir updated 1 file

ext/opcache/jit/zend_jit_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,8 @@ typedef enum _zend_jit_trace_stop {
466466
#define ZEND_JIT_EXIT_METHOD_CALL (1<<9) /* exit because of polymorphic INIT_METHOD_CALL call */
467467
#define ZEND_JIT_EXIT_INVALIDATE (1<<10) /* invalidate current trace */
468468

469+
#define ZEND_JIT_EXIT_FIXED (1U<<31) /* the exit_info can't be changed by zend_jit_snapshot_handler() */
470+
469471
typedef union _zend_op_trace_info {
470472
zend_op dummy; /* the size of this structure must be the same as zend_op */
471473
struct {

ext/opcache/jit/zend_jit_ir.c

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
645670
void *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

ext/opcache/jit/zend_jit_trace.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,9 @@ static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t
237237
if (stack_size == 0
238238
|| (t->exit_info[i].stack_size >= stack_size
239239
&& memcmp(t->stack_map + t->exit_info[i].stack_offset, stack, stack_size * sizeof(zend_jit_trace_stack)) == 0)) {
240+
#ifndef ZEND_JIT_IR
240241
stack_offset = t->exit_info[i].stack_offset;
242+
#endif
241243
if (t->exit_info[i].opline == to_opline
242244
&& t->exit_info[i].flags == flags
243245
&& t->exit_info[i].stack_size == stack_size) {

0 commit comments

Comments
 (0)