summaryrefslogtreecommitdiff
path: root/ext/opcache
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-12-06 15:02:15 +0100
committerDmitry Stogov <dmitry@zend.com>2020-02-07 12:59:48 +0300
commitbc6bab6cb40e35774ca7ca51b6ee408a36b19826 (patch)
treed439dfbb2ee8d061129679031d0fe0b6b9b393dc /ext/opcache
parente9b991d6a01235cc60ec2b98bce6afd7f24d98df (diff)
downloadphp-git-bc6bab6cb40e35774ca7ca51b6ee408a36b19826.tar.gz
Basic JIT support for verify return
Diffstat (limited to 'ext/opcache')
-rw-r--r--ext/opcache/jit/zend_jit.c21
-rw-r--r--ext/opcache/jit/zend_jit_helpers.c27
-rw-r--r--ext/opcache/jit/zend_jit_x86.dasc61
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) {