From: Dmitry Stogov Date: Mon, 31 Aug 2020 12:25:23 +0000 (+0300) Subject: Perform type guard checks before IS_UNDEF checks (check IS_UNDEF during deoptimization) X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5828d547ba4f284d5e5d050ba28c18ec27397365;p=php Perform type guard checks before IS_UNDEF checks (check IS_UNDEF during deoptimization) --- diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index a9c5d5b83b..a4b6810f31 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -2874,6 +2874,10 @@ static int zend_jit_trace_deoptimization(dasm_State **Dst, return 0; } } else { + if (reg == ZREG_ZVAL_COPY_R0 + &&!zend_jit_escape_if_undef_r0(Dst, i, flags, opline)) { + return 0; + } if (!zend_jit_store_const(Dst, i, reg)) { return 0; } @@ -6020,7 +6024,22 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf } else if (STACK_REG(stack, i) == ZREG_ZVAL_COPY_R0) { zval *val = (zval*)regs->r[0]; - ZVAL_COPY(EX_VAR_NUM(i), val); + if (UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) { + /* Undefined array index or property */ + if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT) { + fprintf(stderr, " TRACE %d exit %d %s() %s:%d\n", + trace_num, + exit_num, + EX(func)->op_array.function_name ? + ZSTR_VAL(EX(func)->op_array.function_name) : "$main", + ZSTR_VAL(EX(func)->op_array.filename), + EX(opline)->lineno); + } + EX(opline) = t->exit_info[exit_num].opline - 1; + return 0; + } else { + ZVAL_COPY(EX_VAR_NUM(i), val); + } } else { ZEND_UNREACHABLE(); } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 4ba9b00c08..dc01ce0c8d 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -3654,6 +3654,27 @@ static int zend_jit_update_regs(dasm_State **Dst, zend_jit_addr src, zend_jit_ad return 1; } +static int zend_jit_escape_if_undef_r0(dasm_State **Dst, int var, uint32_t flags, const zend_op *opline) +{ + zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0); + + | IF_NOT_ZVAL_TYPE val_addr, IS_UNDEF, >1 + + if (flags & ZEND_JIT_EXIT_RESTORE_CALL) { + if (!zend_jit_save_call_chain(Dst, -1)) { + return 0; + } + } + + ZEND_ASSERT(opline); + zend_jit_set_ip(Dst, opline - 1); + + | jmp ->trace_escape + |1: + + return 1; +} + static int zend_jit_store_const(dasm_State **Dst, int var, zend_reg reg) { 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 if (op1_info & MAY_BE_ARRAY_HASH) { | IF_NOT_Z_TYPE r0, IS_UNDEF, >8 } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { - | IF_Z_TYPE r0, IS_UNDEF, &exit_addr + /* perform IS_UNDEF check only after result type guard (during deoptimization) */ + if (!found_exit_addr || (op1_info & MAY_BE_ARRAY_HASH)) { + | IF_Z_TYPE r0, IS_UNDEF, &exit_addr + } } else if (type == BP_VAR_IS && not_found_exit_addr) { | IF_Z_TYPE r0, IS_UNDEF, ¬_found_exit_addr } else if (type == BP_VAR_IS && found_exit_addr) { @@ -11457,6 +11481,7 @@ static int zend_jit_fetch_obj(dasm_State **Dst, zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This)); zend_jit_addr prop_addr; + uint32_t res_info = RES_INFO(); ZEND_ASSERT(opline->op2_type == IS_CONST); ZEND_ASSERT(op1_info & MAY_BE_OBJECT); @@ -11570,13 +11595,16 @@ static int zend_jit_fetch_obj(dasm_State **Dst, prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, prop_info->offset); | mov edx, dword [FCARG1a + prop_info->offset + 8] if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); + if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) { + /* perform IS_UNDEF check only after result type guard (during deoptimization) */ + int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); + const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; + if (!exit_addr) { + return 0; + } + | IF_UNDEF dl, &exit_addr } - | IF_UNDEF dl, &exit_addr } else { | IF_UNDEF dl, >5 } @@ -11634,7 +11662,6 @@ static int zend_jit_fetch_obj(dasm_State **Dst, | SET_ZVAL_PTR res_addr, FCARG1a | SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT } else { - uint32_t res_info = RES_INFO(); zend_bool result_avoid_refcounting = 0; if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {