Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions ext/opcache/jit/zend_jit_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -7589,6 +7589,39 @@ static int zend_jit_identical(zend_jit_ctx *jit,
return 1;
}

/* This is only for the tracing JIT.
* `taken` is used for the recorded direction in the tracing jit. */
static int zend_jit_coalesce(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, bool taken, const void *exit_addr)
{
ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);

ZEND_ASSERT(opline->op1_type & (IS_TMP_VAR|IS_CV));

if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
ref = jit_ZVAL_DEREF_ref(jit, ref);
op1_info &= ~MAY_BE_REF;
}

if (exit_addr) {
// JIT: if (Z_TYPE_P(value) > IS_NULL)
ir_ref cond = ir_GT(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_NULL));

if (taken) {
ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
} else {
ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
}
}

if (taken) {
// JIT: ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
// JIT: Z_ADDREF_P(EX_VAR(opline->result.var)) for CV
jit_ZVAL_COPY(jit, res_addr, -1, ZEND_ADDR_REF_ZVAL(ref), op1_info & ~(MAY_BE_UNDEF|MAY_BE_NULL), opline->op1_type == IS_CV);
}

return 1;
}

static int zend_jit_bool_jmpznz(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, uint8_t branch_opcode, const void *exit_addr, bool warn_undef)
{
uint32_t true_label = -1;
Expand Down
40 changes: 40 additions & 0 deletions ext/opcache/jit/zend_jit_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -5761,6 +5761,46 @@ static zend_vm_opcode_handler_t zend_jit_trace(zend_jit_trace_rec *trace_buffer,
goto jit_failure;
}
goto done;
case ZEND_COALESCE:
if (!(opline->op1_type & (IS_TMP_VAR|IS_CV))
/* COALESCE may have two identical successors due to DCE edge case.
* In that case we cannot tell the branch directions apart. */
|| OP_JMP_ADDR(opline, opline->op2) == opline + 1) {
break;
}
op1_info = OP1_INFO();
CHECK_OP1_TRACE_TYPE();
if ((p+1)->op == ZEND_JIT_TRACE_VM || (p+1)->op == ZEND_JIT_TRACE_END) {
bool taken;
uint32_t refined_type_mask;

if ((p+1)->opline == OP_JMP_ADDR(opline, opline->op2)) {
taken = true;
refined_type_mask = op1_info & (MAY_BE_UNDEF|MAY_BE_NULL);
} else if ((p+1)->opline == opline + 1) {
taken = false;
refined_type_mask = op1_info & ((MAY_BE_ANY|MAY_BE_REF) - MAY_BE_NULL);
} else {
ZEND_UNREACHABLE();
}
if (!refined_type_mask) {
/* unconditional branch */
exit_addr = NULL;
} else {
/* Execute the other direction in VM or side trace. */
uint32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
if (!exit_addr) {
goto jit_failure;
}
}
if (!zend_jit_coalesce(&ctx, opline, op1_info, OP1_ADDR(), RES_ADDR(), taken, exit_addr)) {
goto jit_failure;
}
goto done;
} else {
ZEND_UNREACHABLE();
}
case ZEND_JMP_FRAMELESS:
op1_info = OP1_INFO();
ZEND_ASSERT((p+1)->op == ZEND_JIT_TRACE_VM);
Expand Down
Loading