From 225cd9da865ea66d49f24d5c8f98bdf05efa0592 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 2 Sep 2020 12:55:16 +0300 Subject: [PATCH] Improved JIT for VERIFY_RETURN_TYPE --- ext/opcache/jit/zend_jit_trace.c | 38 +++++++++++ ext/opcache/jit/zend_jit_x86.dasc | 101 +++++++++++++++++------------- 2 files changed, 97 insertions(+), 42 deletions(-) diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 3203339d02..c3c7dbab22 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1447,6 +1447,21 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin case ZEND_QM_ASSIGN: ADD_OP1_TRACE_GUARD(); break; + case ZEND_VERIFY_RETURN_TYPE: + if (opline->op1_type == IS_UNUSED) { + /* Always throws */ + break; + } + if (opline->op1_type == IS_CONST) { + /* TODO Different instruction format, has return value */ + break; + } + if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + /* Not worth bothering with */ + break; + } + ADD_OP1_TRACE_GUARD(); + break; case ZEND_FETCH_DIM_FUNC_ARG: if (!frame || !frame->call @@ -4502,6 +4517,29 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par goto jit_failure; } goto done; + case ZEND_VERIFY_RETURN_TYPE: + if (opline->op1_type == IS_UNUSED) { + /* Always throws */ + break; + } + if (opline->op1_type == IS_CONST) { + /* TODO Different instruction format, has return value */ + break; + } + if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + /* Not worth bothering with */ + break; + } + op1_info = OP1_INFO(); + CHECK_OP1_TRACE_TYPE(); + if (op1_info & MAY_BE_REF) { + /* TODO May need reference unwrapping. */ + break; + } + if (!zend_jit_verify_return_type(&dasm_state, opline, op_array, op1_info)) { + goto jit_failure; + } + goto done; case ZEND_INIT_METHOD_CALL: case ZEND_INIT_DYNAMIC_CALL: if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) { diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 39fd42e263..09cea05354 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -483,6 +483,11 @@ static void* dasm_labels[zend_lb_MAX]; | mov dword [zv+offsetof(zval,u1.type_info)], type |.endmacro +|.macro GET_ZVAL_TYPE, reg, addr +|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); +| mov reg, byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.v.type)] +|.endmacro + |.macro GET_ZVAL_TYPE_INFO, reg, addr || ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); | mov reg, dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.type_info)] @@ -12393,53 +12398,65 @@ static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *op zend_arg_info *arg_info = &op_array->arg_info[-1]; ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type)); zend_jit_addr op1_addr = OP1_ADDR(); - - | LOAD_ZVAL_ADDR r0, op1_addr - + zend_bool needs_slow_check = 1; + zend_bool slow_check_in_cold = 1; uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY; + if (type_mask == 0) { - | jmp >7 - } else if (is_power_of_two(type_mask)) { - uint32_t type_code = concrete_type(type_mask); - | cmp byte [r0 + 8], type_code - | jne >7 + slow_check_in_cold = 0; } else { - | mov edx, 1 - | mov cl, byte [r0 + 8] - | shl edx, cl - | test edx, type_mask - | je >7 - } - |.cold_code - |7: - | SAVE_VALID_OPLINE opline, r1 - if (op1_info & MAY_BE_UNDEF) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >8 - | mov FCARG1a, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, FCARG2a - | LOAD_ADDR_ZTS r0, executor_globals, uninitialized_zval + if (((op1_info & MAY_BE_ANY) & type_mask) == 0) { + slow_check_in_cold = 0; + } else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) { + needs_slow_check = 0; + } else if (is_power_of_two(type_mask)) { + uint32_t type_code = concrete_type(type_mask); + | IF_NOT_ZVAL_TYPE op1_addr, type_code, >7 + } else { + | mov edx, 1 + | GET_ZVAL_TYPE cl, op1_addr + | shl edx, cl + | test edx, type_mask + | je >7 + } } - |8: - | mov FCARG1a, r0 - | mov r0, EX->run_time_cache - | add r0, opline->op2.num - | mov FCARG2a, EX->func - |.if X64 - | LOAD_ADDR CARG3, (ptrdiff_t)arg_info - | mov CARG4, r0 - | EXT_CALL zend_jit_verify_return_slow, r0 - |.else - | sub r4, 8 - | push r0 - | push (ptrdiff_t)arg_info - | EXT_CALL zend_jit_verify_return_slow, r0 - | add r4, 8 - |.endif - if (!zend_jit_check_exception(Dst)) { - return 0; + if (needs_slow_check) { + if (slow_check_in_cold) { + |.cold_code + |7: + } + | SAVE_VALID_OPLINE opline, r1 + if (op1_info & MAY_BE_UNDEF) { + | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >8 + | mov FCARG1a, opline->op1.var + | EXT_CALL zend_jit_undefined_op_helper, FCARG2a + | LOAD_ADDR_ZTS r0, executor_globals, uninitialized_zval + } + |8: + | LOAD_ZVAL_ADDR FCARG1a, op1_addr + | mov FCARG2a, EX->func + |.if X64 + | LOAD_ADDR CARG3, (ptrdiff_t)arg_info + | mov r0, EX->run_time_cache + | lea CARG4, aword [r0+opline->op2.num] + | EXT_CALL zend_jit_verify_return_slow, r0 + |.else + | sub r4, 8 + | mov r0, EX->run_time_cache + | add r0, opline->op2.num + | push r0 + | push (ptrdiff_t)arg_info + | EXT_CALL zend_jit_verify_return_slow, r0 + | add r4, 8 + |.endif + if (!zend_jit_check_exception(Dst)) { + return 0; + } + if (slow_check_in_cold) { + | jmp >9 + |.code + } } - | jmp >9 - |.code |9: return 1; } -- 2.50.1