]> granicus.if.org Git - php/commitdiff
Perform early guard type check for result of FETCH_CONSTANT
authorDmitry Stogov <dmitry@zend.com>
Wed, 9 Dec 2020 19:24:03 +0000 (22:24 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 9 Dec 2020 19:24:03 +0000 (22:24 +0300)
ext/opcache/jit/zend_jit.c
ext/opcache/jit/zend_jit_internal.h
ext/opcache/jit/zend_jit_trace.c
ext/opcache/jit/zend_jit_vm_helpers.c
ext/opcache/jit/zend_jit_x86.dasc

index 49ff973d1a77512e297c6cbcc981f7179c7f8db6..b96bcd516d293aa6b3f1ffa3f3415afc4297521e 100644 (file)
@@ -3263,7 +3263,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
                                                }
                                                goto done;
                                        case ZEND_FETCH_CONSTANT:
-                                               if (!zend_jit_fetch_constant(&dasm_state, opline)) {
+                                               if (!zend_jit_fetch_constant(&dasm_state, opline, op_array, ssa, ssa_op)) {
                                                        goto jit_failure;
                                                }
                                                goto done;
index 74b3b8a7e80cf015ca35b7d948f1b8a1e147cf04..917fa10f2e04469f1bf00f20c6f2dc22b42d7a80 100644 (file)
@@ -130,8 +130,8 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_H
 void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D);
 zend_bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D);
 
-int ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags);
-int ZEND_FASTCALL zend_jit_check_constant(const zval *key);
+zend_constant* ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags);
+zend_constant* ZEND_FASTCALL zend_jit_check_constant(const zval *key);
 
 /* Tracer */
 #define zend_jit_opline_hash(opline) \
index 33658f8e860408fee6759f7a1277ace635a831a1..145388088d625aaa2d7f2080e85ccb96dde19346 100644 (file)
@@ -5452,7 +5452,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                                }
                                                goto done;
                                        case ZEND_FETCH_CONSTANT:
-                                               if (!zend_jit_fetch_constant(&dasm_state, opline)) {
+                                               if (!zend_jit_fetch_constant(&dasm_state, opline, op_array, ssa, ssa_op)) {
                                                        goto jit_failure;
                                                }
                                                goto done;
index 6952f7532ec441d9623dacd0fe793b35e5e19057..d919b59c9e8750dedafb023f91e6a0a2540e9b7a 100644 (file)
@@ -239,7 +239,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_H
        }
 }
 
-static zend_always_inline int _zend_quick_get_constant(
+static zend_always_inline zend_constant* _zend_quick_get_constant(
                const zval *key, uint32_t flags, int check_defined_only)
 {
 #ifndef HAVE_GCC_GLOBAL_REGS
@@ -267,30 +267,29 @@ static zend_always_inline int _zend_quick_get_constant(
                        ZVAL_UNDEF(EX_VAR(opline->result.var));
                }
                CACHE_PTR(opline->extended_value, ENCODE_SPECIAL_CACHE_NUM(zend_hash_num_elements(EG(zend_constants))));
-               return FAILURE;
+               return NULL;
        }
 
        if (!check_defined_only) {
-               ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
                if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) {
                        zend_error(E_DEPRECATED, "Constant %s is deprecated", ZSTR_VAL(c->name));
                        if (EG(exception)) {
-                               return FAILURE;
+                               return NULL;
                        }
-                       return SUCCESS;
+                       return c;
                }
        }
 
        CACHE_PTR(opline->extended_value, c);
-       return SUCCESS;
+       return c;
 }
 
-int ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags)
+zend_constant* ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags)
 {
        return _zend_quick_get_constant(key, flags, 0);
 }
 
-int ZEND_FASTCALL zend_jit_check_constant(const zval *key)
+zend_constant* ZEND_FASTCALL zend_jit_check_constant(const zval *key)
 {
        return _zend_quick_get_constant(key, 0, 1);
 }
index ff70f96ba5f977b74a1f1d3ef71426b4f15c24fa..404e402ec7e6697b675320c9765f6f9d461e8178 100644 (file)
@@ -10814,16 +10814,16 @@ static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, zend_uchar
        |       test r0, r0
        if (exit_addr) {
                if (smart_branch_opcode == ZEND_JMPNZ) {
-                       |       jnz >3
-               } else {
                        |       jz >3
+               } else {
+                       |       jnz >3
                }
                |       jmp &exit_addr
        } else if (smart_branch_opcode) {
                if (undefined_label != (uint32_t)-1) {
-                       |       jnz =>undefined_label
+                       |       jz =>undefined_label
                } else {
-                       |       jnz >3
+                       |       jz >3
                }
                if (defined_label != (uint32_t)-1) {
                        |       jmp =>defined_label
@@ -10832,7 +10832,7 @@ static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, zend_uchar
                }
        } else {
                res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
-               |       jz >1
+               |       jnz >1
                |2:
                |       SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
                |       jmp >3
@@ -14946,26 +14946,66 @@ static int zend_jit_fe_fetch(dasm_State **Dst, const zend_op *opline, uint32_t o
        return 1;
 }
 
-static int zend_jit_fetch_constant(dasm_State **Dst, const zend_op *opline)
+static int zend_jit_fetch_constant(dasm_State          **Dst,
+                                   const zend_op        *opline,
+                                   const zend_op_array  *op_array,
+                                   zend_ssa             *ssa,
+                                   const zend_ssa_op    *ssa_op)
 {
        zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
        zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
-       zend_jit_addr const_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+       zend_jit_addr const_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
+       uint32_t res_info = RES_INFO();
 
        |       // c = CACHED_PTR(opline->extended_value);
        |       mov FCARG1a, EX->run_time_cache
-       |       mov FCARG1a, aword [FCARG1a + opline->extended_value]
+       |       mov r0, aword [FCARG1a + opline->extended_value]
        |       // if (c != NULL)
-       |       test FCARG1a, FCARG1a
+       |       test r0, r0
        |       jz >9
        |       // if (!IS_SPECIAL_CACHE_VAL(c))
-       |       test FCARG1a, CACHE_SPECIAL
+       |       test r0, CACHE_SPECIAL
        |       jnz >9
-       |       // ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
-       |       ZVAL_COPY_VALUE res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, ZREG_R0, ZREG_FCARG2a
-       |       TRY_ADDREF MAY_BE_ANY, ah, FCARG2a
        |8:
 
+       if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
+               zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
+               uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
+               int32_t exit_point;
+               const void *exit_addr = NULL;
+
+               SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
+               SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_R0);
+               exit_point = zend_jit_trace_get_exit_point(opline+1, 0);
+               SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
+               exit_addr = zend_jit_trace_get_exit_addr(exit_point);
+               if (!exit_addr) {
+                       return 0;
+               }
+               res_info &= ~MAY_BE_GUARD;
+               ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
+
+               zend_uchar type = concrete_type(res_info);
+
+               if (type < IS_STRING) {
+                       |       IF_NOT_ZVAL_TYPE const_addr, type, &exit_addr
+               } else {
+                       |       GET_ZVAL_TYPE_INFO edx, const_addr
+                       |       IF_NOT_TYPE dl, type, &exit_addr
+               }
+               |       ZVAL_COPY_VALUE_V res_addr, -1, const_addr, res_info, ZREG_R0, ZREG_R1
+               if (type < IS_STRING) {
+                       |       SET_ZVAL_TYPE_INFO res_addr, type
+               } else {
+                       |       SET_ZVAL_TYPE_INFO res_addr, edx
+                       |       TRY_ADDREF res_info, dh, r1
+               }
+       } else {
+               |       // ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
+               |       ZVAL_COPY_VALUE res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, ZREG_R0, ZREG_R1
+               |       TRY_ADDREF MAY_BE_ANY, ah, r1
+       }
+
        |.cold_code
        |9:
        |       // SAVE_OPLINE();
@@ -14976,7 +15016,7 @@ static int zend_jit_fetch_constant(dasm_State **Dst, const zend_op *opline)
        |       EXT_CALL zend_jit_get_constant, r0
        |       // ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
        |       test r0, r0
-       |       jz <8
+       |       jnz <8
        |       jmp ->exception_handler
        |.code