Skip to content

Commit 5828d54

Browse files
committed
Perform type guard checks before IS_UNDEF checks (check IS_UNDEF during deoptimization)
1 parent b4196ae commit 5828d54

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

ext/opcache/jit/zend_jit_trace.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2874,6 +2874,10 @@ static int zend_jit_trace_deoptimization(dasm_State **Dst,
28742874
return 0;
28752875
}
28762876
} else {
2877+
if (reg == ZREG_ZVAL_COPY_R0
2878+
&&!zend_jit_escape_if_undef_r0(Dst, i, flags, opline)) {
2879+
return 0;
2880+
}
28772881
if (!zend_jit_store_const(Dst, i, reg)) {
28782882
return 0;
28792883
}
@@ -6020,7 +6024,22 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf
60206024
} else if (STACK_REG(stack, i) == ZREG_ZVAL_COPY_R0) {
60216025
zval *val = (zval*)regs->r[0];
60226026

6023-
ZVAL_COPY(EX_VAR_NUM(i), val);
6027+
if (UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) {
6028+
/* Undefined array index or property */
6029+
if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT) {
6030+
fprintf(stderr, " TRACE %d exit %d %s() %s:%d\n",
6031+
trace_num,
6032+
exit_num,
6033+
EX(func)->op_array.function_name ?
6034+
ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
6035+
ZSTR_VAL(EX(func)->op_array.filename),
6036+
EX(opline)->lineno);
6037+
}
6038+
EX(opline) = t->exit_info[exit_num].opline - 1;
6039+
return 0;
6040+
} else {
6041+
ZVAL_COPY(EX_VAR_NUM(i), val);
6042+
}
60246043
} else {
60256044
ZEND_UNREACHABLE();
60266045
}

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3654,6 +3654,27 @@ static int zend_jit_update_regs(dasm_State **Dst, zend_jit_addr src, zend_jit_ad
36543654
return 1;
36553655
}
36563656

3657+
static int zend_jit_escape_if_undef_r0(dasm_State **Dst, int var, uint32_t flags, const zend_op *opline)
3658+
{
3659+
zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
3660+
3661+
| IF_NOT_ZVAL_TYPE val_addr, IS_UNDEF, >1
3662+
3663+
if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
3664+
if (!zend_jit_save_call_chain(Dst, -1)) {
3665+
return 0;
3666+
}
3667+
}
3668+
3669+
ZEND_ASSERT(opline);
3670+
zend_jit_set_ip(Dst, opline - 1);
3671+
3672+
| jmp ->trace_escape
3673+
|1:
3674+
3675+
return 1;
3676+
}
3677+
36573678
static int zend_jit_store_const(dasm_State **Dst, int var, zend_reg reg)
36583679
{
36593680
zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
@@ -5116,7 +5137,10 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
51165137
if (op1_info & MAY_BE_ARRAY_HASH) {
51175138
| IF_NOT_Z_TYPE r0, IS_UNDEF, >8
51185139
} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
5119-
| IF_Z_TYPE r0, IS_UNDEF, &exit_addr
5140+
/* perform IS_UNDEF check only after result type guard (during deoptimization) */
5141+
if (!found_exit_addr || (op1_info & MAY_BE_ARRAY_HASH)) {
5142+
| IF_Z_TYPE r0, IS_UNDEF, &exit_addr
5143+
}
51205144
} else if (type == BP_VAR_IS && not_found_exit_addr) {
51215145
| IF_Z_TYPE r0, IS_UNDEF, &not_found_exit_addr
51225146
} else if (type == BP_VAR_IS && found_exit_addr) {
@@ -11457,6 +11481,7 @@ static int zend_jit_fetch_obj(dasm_State **Dst,
1145711481
zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
1145811482
zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
1145911483
zend_jit_addr prop_addr;
11484+
uint32_t res_info = RES_INFO();
1146011485

1146111486
ZEND_ASSERT(opline->op2_type == IS_CONST);
1146211487
ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
@@ -11570,13 +11595,16 @@ static int zend_jit_fetch_obj(dasm_State **Dst,
1157011595
prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, prop_info->offset);
1157111596
| mov edx, dword [FCARG1a + prop_info->offset + 8]
1157211597
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11573-
int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
11574-
const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11598+
if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
11599+
/* perform IS_UNDEF check only after result type guard (during deoptimization) */
11600+
int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
11601+
const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
1157511602

11576-
if (!exit_addr) {
11577-
return 0;
11603+
if (!exit_addr) {
11604+
return 0;
11605+
}
11606+
| IF_UNDEF dl, &exit_addr
1157811607
}
11579-
| IF_UNDEF dl, &exit_addr
1158011608
} else {
1158111609
| IF_UNDEF dl, >5
1158211610
}
@@ -11634,7 +11662,6 @@ static int zend_jit_fetch_obj(dasm_State **Dst,
1163411662
| SET_ZVAL_PTR res_addr, FCARG1a
1163511663
| SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT
1163611664
} else {
11637-
uint32_t res_info = RES_INFO();
1163811665
zend_bool result_avoid_refcounting = 0;
1163911666

1164011667
if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {

0 commit comments

Comments
 (0)