From: Dmitry Stogov Date: Wed, 9 Dec 2020 19:24:03 +0000 (+0300) Subject: Perform early guard type check for result of FETCH_CONSTANT X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e9f9e9f8635085728919636ac291462395227a40;p=php Perform early guard type check for result of FETCH_CONSTANT --- diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 49ff973d1a..b96bcd516d 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -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; diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index 74b3b8a7e8..917fa10f2e 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -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) \ diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 33658f8e86..145388088d 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -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; diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 6952f7532e..d919b59c9e 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -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); } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index ff70f96ba5..404e402ec7 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -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