diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-12-06 15:02:15 +0100 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2020-02-07 12:59:48 +0300 |
commit | bc6bab6cb40e35774ca7ca51b6ee408a36b19826 (patch) | |
tree | d439dfbb2ee8d061129679031d0fe0b6b9b393dc /ext/opcache | |
parent | e9b991d6a01235cc60ec2b98bce6afd7f24d98df (diff) | |
download | php-git-bc6bab6cb40e35774ca7ca51b6ee408a36b19826.tar.gz |
Basic JIT support for verify return
Diffstat (limited to 'ext/opcache')
-rw-r--r-- | ext/opcache/jit/zend_jit.c | 21 | ||||
-rw-r--r-- | ext/opcache/jit/zend_jit_helpers.c | 27 | ||||
-rw-r--r-- | ext/opcache/jit/zend_jit_x86.dasc | 61 |
3 files changed, 100 insertions, 9 deletions
diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 8b113de4bb..07d82b89de 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2739,6 +2739,27 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op 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; + } + 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; default: break; } diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 054e63300d..d0caabe5da 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1141,7 +1141,7 @@ static zval* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_execute_data *execu return value; } -static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, const zend_op_array *op_array, uint32_t arg_num, zend_arg_info *arg_info, void **cache_slot) +static zend_always_inline zend_bool zend_jit_verify_type_common(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info, void **cache_slot) { uint32_t type_mask; @@ -1162,7 +1162,7 @@ static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, const zend_op_arra *cache_slot = ce; } if (instanceof_function(Z_OBJCE_P(arg), ce)) { - return; + return 1; } cache_slot++; } ZEND_TYPE_LIST_FOREACH_END(); @@ -1177,7 +1177,7 @@ static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, const zend_op_arra *cache_slot = (void *) ce; } if (instanceof_function(Z_OBJCE_P(arg), ce)) { - return; + return 1; } } } @@ -1185,16 +1185,29 @@ static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, const zend_op_arra builtin_types: type_mask = ZEND_TYPE_FULL_MASK(arg_info->type); if ((type_mask & MAY_BE_CALLABLE) && zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) { - return; + return 1; } if ((type_mask & MAY_BE_ITERABLE) && zend_is_iterable(arg)) { - return; + return 1; } if (zend_verify_scalar_type_hint(type_mask, arg, ZEND_ARG_USES_STRICT_TYPES(), /* is_internal */ 0)) { - return; + return 1; + } + return 0; +} + +static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, const zend_op_array *op_array, uint32_t arg_num, zend_arg_info *arg_info, void **cache_slot) +{ + if (UNEXPECTED(!zend_jit_verify_type_common(arg, op_array, arg_info, cache_slot))) { + zend_verify_arg_error((zend_function*)op_array, arg_info, arg_num, cache_slot, arg); } +} - zend_verify_arg_error((zend_function*)op_array, arg_info, arg_num, cache_slot, arg); +static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info, void **cache_slot) +{ + if (UNEXPECTED(!zend_jit_verify_type_common(arg, op_array, arg_info, cache_slot))) { + zend_verify_return_error((zend_function*)op_array, cache_slot, arg); + } } static void ZEND_FASTCALL zend_jit_zval_copy_deref_helper(zval *dst, zval *src) diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index ab833d1b06..6b972650c4 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -8647,7 +8647,9 @@ static int zend_jit_recv(dasm_State **Dst, const zend_op *opline, const zend_op_ } uint32_t type_mask = ZEND_TYPE_PURE_MASK(type); - if (is_power_of_two(type_mask)) { + if (type_mask == 0) { + | jmp >8 + } else if (is_power_of_two(type_mask)) { uint32_t type_code = concrete_type(type_mask); | cmp byte [r0 + 8], type_code | jne >8 @@ -8765,7 +8767,9 @@ static int zend_jit_recv_init(dasm_State **Dst, const zend_op *opline, const zen | ZVAL_DEREF r0, MAY_BE_REF uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type); - if (is_power_of_two(type_mask)) { + if (type_mask == 0) { + | jmp >8 + } else if (is_power_of_two(type_mask)) { uint32_t type_code = concrete_type(type_mask); | cmp byte [r0 + 8], type_code | jne >8 @@ -9341,6 +9345,59 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o return 1; } +static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info) +{ + 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 + + uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type); + if (type_mask == 0) { + | jmp >8 + } else if (is_power_of_two(type_mask)) { + uint32_t type_code = concrete_type(type_mask); + | cmp byte [r0 + 8], type_code + | jne >8 + } else { + | mov edx, 1 + | mov cl, byte [r0 + 8] + | shl edx, cl + | test edx, type_mask + | je >8 + } + |.cold_code + |8: + | mov FCARG1a, r0 + | mov r0, EX->run_time_cache + | add r0, opline->op2.num + | LOAD_ADDR FCARG2a, (ptrdiff_t)op_array + |.if X64WIN + | LOAD_ADDR CARG3, (ptrdiff_t)arg_info + | mov aword A4, r0 + | SAVE_VALID_OPLINE opline + | EXT_CALL zend_jit_verify_return_slow, r0 + |.elif X64 + | LOAD_ADDR CARG3, (ptrdiff_t)arg_info + | mov CARG4, r0 + | SAVE_VALID_OPLINE opline + | EXT_CALL zend_jit_verify_return_slow, r0 + |.else + | push r0 + | push (ptrdiff_t)arg_info + | SAVE_VALID_OPLINE opline + | EXT_CALL zend_jit_verify_return_slow, r0 + |.endif + if (!zend_jit_check_exception(Dst)) { + return 0; + } + | jmp >9 + |.code + |9: + return 1; +} + static zend_bool zend_jit_may_reuse_reg(const zend_op_array *op_array, zend_ssa *ssa, uint32_t position, int def_var, int use_var) { if (ssa->var_info[def_var].type != ssa->var_info[use_var].type) { |