mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Basic JIT support for verify return
This commit is contained in:
parent
e9b991d6a0
commit
bc6bab6cb4
5 changed files with 103 additions and 10 deletions
|
@ -1224,7 +1224,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *
|
|||
}
|
||||
}
|
||||
|
||||
static ZEND_COLD void zend_verify_return_error(
|
||||
ZEND_API ZEND_COLD void zend_verify_return_error(
|
||||
const zend_function *zf, void **cache_slot, zval *value)
|
||||
{
|
||||
const zend_arg_info *arg_info = &zf->common.arg_info[-1];
|
||||
|
|
|
@ -64,6 +64,8 @@ ZEND_API zend_bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, z
|
|||
ZEND_API ZEND_COLD void zend_verify_arg_error(
|
||||
const zend_function *zf, const zend_arg_info *arg_info,
|
||||
int arg_num, void **cache_slot, zval *value);
|
||||
ZEND_API ZEND_COLD void zend_verify_return_error(
|
||||
const zend_function *zf, void **cache_slot, zval *value);
|
||||
ZEND_API zend_bool zend_verify_ref_array_assignable(zend_reference *ref);
|
||||
|
||||
#define ZEND_REF_TYPE_SOURCES(ref) \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
zend_verify_arg_error((zend_function*)op_array, arg_info, arg_num, cache_slot, arg);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue