]> granicus.if.org Git - php/commitdiff
Perform type guard checks before IS_UNDEF checks (check IS_UNDEF during deoptimization)
authorDmitry Stogov <dmitry@zend.com>
Mon, 31 Aug 2020 12:25:23 +0000 (15:25 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 31 Aug 2020 12:25:23 +0000 (15:25 +0300)
ext/opcache/jit/zend_jit_trace.c
ext/opcache/jit/zend_jit_x86.dasc

index a9c5d5b83bf341c3e9c98a1e2a844df7dee03a76..a4b6810f311ba648e6e567b50398c8b7ea6bee18 100644 (file)
@@ -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();
                        }
index 4ba9b00c080e138933e3c42afa78dd9747c1cbe0..dc01ce0c8d9d825b491c05c893d5a4bfa0647803 100644 (file)
@@ -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, &not_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) {