Remove cache slot from ZEND_VERIFY_TYPE and arg RECV opcodes (#18258)

This commit is contained in:
Niels Dossche 2025-04-07 19:50:48 +02:00 committed by GitHub
parent bd4333447e
commit a32f491855
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 57 additions and 190 deletions

View file

@ -25,6 +25,8 @@ PHP 8.5 INTERNALS UPGRADE NOTES
char* instead of zend_string*-based smart strings. char* instead of zend_string*-based smart strings.
. Added php_build_provider() to retrieve the value of PHP_BUILD_PROVIDER at . Added php_build_provider() to retrieve the value of PHP_BUILD_PROVIDER at
runtime. runtime.
. Removed the cache_slot argument of zend_check_user_type_slow() because
now it only relies on the CE cache.
======================== ========================
2. Build system changes 2. Build system changes

View file

@ -43,50 +43,6 @@ typedef struct _literal_info {
info[n].num_related = (related); \ info[n].num_related = (related); \
} while (0) } while (0)
static size_t type_num_classes(const zend_op_array *op_array, uint32_t arg_num)
{
zend_arg_info *arg_info;
if (arg_num > 0) {
if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
return 0;
}
if (EXPECTED(arg_num <= op_array->num_args)) {
arg_info = &op_array->arg_info[arg_num-1];
} else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
arg_info = &op_array->arg_info[op_array->num_args];
} else {
return 0;
}
} else {
arg_info = op_array->arg_info - 1;
}
if (ZEND_TYPE_IS_COMPLEX(arg_info->type)) {
if (ZEND_TYPE_HAS_LIST(arg_info->type)) {
/* Intersection types cannot have nested list types */
if (ZEND_TYPE_IS_INTERSECTION(arg_info->type)) {
return ZEND_TYPE_LIST(arg_info->type)->num_types;
}
ZEND_ASSERT(ZEND_TYPE_IS_UNION(arg_info->type));
size_t count = 0;
const zend_type *list_type;
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), list_type) {
if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
count += ZEND_TYPE_LIST(*list_type)->num_types;
} else {
ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
count += 1;
}
} ZEND_TYPE_LIST_FOREACH_END();
return count;
}
return 1;
}
return 0;
}
static uint32_t add_static_slot(HashTable *hash, static uint32_t add_static_slot(HashTable *hash,
zend_op_array *op_array, zend_op_array *op_array,
uint32_t op1, uint32_t op1,
@ -504,26 +460,6 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
opline->op2.constant = map[opline->op2.constant]; opline->op2.constant = map[opline->op2.constant];
} }
switch (opline->opcode) { switch (opline->opcode) {
case ZEND_RECV_INIT:
case ZEND_RECV:
case ZEND_RECV_VARIADIC:
{
size_t num_classes = type_num_classes(op_array, opline->op1.num);
if (num_classes) {
opline->extended_value = cache_size;
cache_size += num_classes * sizeof(void *);
}
break;
}
case ZEND_VERIFY_RETURN_TYPE:
{
size_t num_classes = type_num_classes(op_array, 0);
if (num_classes) {
opline->op2.num = cache_size;
cache_size += num_classes * sizeof(void *);
}
break;
}
case ZEND_ASSIGN_STATIC_PROP_OP: case ZEND_ASSIGN_STATIC_PROP_OP:
if (opline->op1_type == IS_CONST) { if (opline->op1_type == IS_CONST) {
// op1 static property // op1 static property

View file

@ -2620,33 +2620,6 @@ static void zend_compile_memoized_expr(znode *result, zend_ast *expr) /* {{{ */
} }
/* }}} */ /* }}} */
/* Remember to update type_num_classes() in compact_literals.c when changing this function */
static size_t zend_type_get_num_classes(const zend_type type) {
if (!ZEND_TYPE_IS_COMPLEX(type)) {
return 0;
}
if (ZEND_TYPE_HAS_LIST(type)) {
/* Intersection types cannot have nested list types */
if (ZEND_TYPE_IS_INTERSECTION(type)) {
return ZEND_TYPE_LIST(type)->num_types;
}
ZEND_ASSERT(ZEND_TYPE_IS_UNION(type));
size_t count = 0;
const zend_type *list_type;
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
count += ZEND_TYPE_LIST(*list_type)->num_types;
} else {
ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
count += 1;
}
} ZEND_TYPE_LIST_FOREACH_END();
return count;
}
return 1;
}
static void zend_emit_return_type_check( static void zend_emit_return_type_check(
znode *expr, zend_arg_info *return_info, bool implicit) /* {{{ */ znode *expr, zend_arg_info *return_info, bool implicit) /* {{{ */
{ {
@ -2708,8 +2681,6 @@ static void zend_emit_return_type_check(
opline->result_type = expr->op_type = IS_TMP_VAR; opline->result_type = expr->op_type = IS_TMP_VAR;
opline->result.var = expr->u.op.var = get_temporary_variable(); opline->result.var = expr->u.op.var = get_temporary_variable();
} }
opline->op2.num = zend_alloc_cache_slots(zend_type_get_num_classes(return_info->type));
} }
} }
/* }}} */ /* }}} */
@ -7754,12 +7725,6 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
SET_NODE(opline->result, &var_node); SET_NODE(opline->result, &var_node);
opline->op1.num = i + 1; opline->op1.num = i + 1;
if (type_ast) {
/* Allocate cache slot to speed-up run-time class resolution */
opline->extended_value =
zend_alloc_cache_slots(zend_type_get_num_classes(arg_info->type));
}
uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic, /* is_tentative */ 0) uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic, /* is_tentative */ 0)
| (is_promoted ? _ZEND_IS_PROMOTED_BIT : 0); | (is_promoted ? _ZEND_IS_PROMOTED_BIT : 0);
ZEND_TYPE_FULL_MASK(arg_info->type) |= arg_info_flags; ZEND_TYPE_FULL_MASK(arg_info->type) |= arg_info_flags;

View file

@ -1099,23 +1099,9 @@ static zend_always_inline bool zend_value_instanceof_static(const zval *zv) {
return instanceof_function(Z_OBJCE_P(zv), called_scope); return instanceof_function(Z_OBJCE_P(zv), called_scope);
} }
/* The cache_slot may only be NULL in debug builds, where arginfo verification of static zend_always_inline zend_class_entry *zend_fetch_ce_from_type(
* internal functions is enabled. Avoid unnecessary checks in release builds. */ const zend_type *type)
#if ZEND_DEBUG
# define HAVE_CACHE_SLOT (cache_slot != NULL)
#else
# define HAVE_CACHE_SLOT 1
#endif
#define PROGRESS_CACHE_SLOT() if (HAVE_CACHE_SLOT) {cache_slot++;}
static zend_always_inline zend_class_entry *zend_fetch_ce_from_cache_slot(
void **cache_slot, const zend_type *type)
{ {
if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) {
return (zend_class_entry *) *cache_slot;
}
zend_string *name = ZEND_TYPE_NAME(*type); zend_string *name = ZEND_TYPE_NAME(*type);
zend_class_entry *ce; zend_class_entry *ce;
if (ZSTR_HAS_CE_CACHE(name)) { if (ZSTR_HAS_CE_CACHE(name)) {
@ -1134,68 +1120,54 @@ static zend_always_inline zend_class_entry *zend_fetch_ce_from_cache_slot(
return NULL; return NULL;
} }
} }
if (HAVE_CACHE_SLOT) {
*cache_slot = (void *) ce;
}
return ce; return ce;
} }
static bool zend_check_intersection_type_from_cache_slot( static bool zend_check_intersection_type_from_list(
const zend_type_list *intersection_type_list, const zend_type_list *intersection_type_list,
const zend_class_entry *arg_ce, zend_class_entry *arg_ce)
void ***cache_slot_ptr)
{ {
void **cache_slot = *cache_slot_ptr; zend_class_entry *ce;
const zend_type *list_type; const zend_type *list_type;
bool status = true;
ZEND_TYPE_LIST_FOREACH(intersection_type_list, list_type) { ZEND_TYPE_LIST_FOREACH(intersection_type_list, list_type) {
/* Only check classes if the type might be valid */ ce = zend_fetch_ce_from_type(list_type);
if (status) {
zend_class_entry *ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type);
/* If type is not an instance of one of the types taking part in the /* If type is not an instance of one of the types taking part in the
* intersection it cannot be a valid instance of the whole intersection type. */ * intersection it cannot be a valid instance of the whole intersection type. */
if (!ce || !instanceof_function(arg_ce, ce)) { if (!ce || !instanceof_function(arg_ce, ce)) {
status = false; return false;
} }
}
PROGRESS_CACHE_SLOT();
} ZEND_TYPE_LIST_FOREACH_END(); } ZEND_TYPE_LIST_FOREACH_END();
if (HAVE_CACHE_SLOT) { return true;
*cache_slot_ptr = cache_slot;
}
return status;
} }
static zend_always_inline bool zend_check_type_slow( static zend_always_inline bool zend_check_type_slow(
const zend_type *type, zval *arg, const zend_reference *ref, void **cache_slot, const zend_type *type, zval *arg, const zend_reference *ref,
bool is_return_type, bool is_internal) bool is_return_type, bool is_internal)
{ {
if (ZEND_TYPE_IS_COMPLEX(*type) && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { if (ZEND_TYPE_IS_COMPLEX(*type) && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
zend_class_entry *ce; zend_class_entry *ce;
if (UNEXPECTED(ZEND_TYPE_HAS_LIST(*type))) { if (UNEXPECTED(ZEND_TYPE_HAS_LIST(*type))) {
if (ZEND_TYPE_IS_INTERSECTION(*type)) { if (ZEND_TYPE_IS_INTERSECTION(*type)) {
return zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*type), Z_OBJCE_P(arg), &cache_slot); return zend_check_intersection_type_from_list(ZEND_TYPE_LIST(*type), Z_OBJCE_P(arg));
} else { } else {
const zend_type *list_type; const zend_type *list_type;
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) { ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) {
if (ZEND_TYPE_IS_INTERSECTION(*list_type)) { if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
if (zend_check_intersection_type_from_cache_slot(ZEND_TYPE_LIST(*list_type), Z_OBJCE_P(arg), &cache_slot)) { if (zend_check_intersection_type_from_list(ZEND_TYPE_LIST(*list_type), Z_OBJCE_P(arg))) {
return true; return true;
} }
/* The cache_slot is progressed in zend_check_intersection_type_from_cache_slot() */
} else { } else {
ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type); ce = zend_fetch_ce_from_type(list_type);
/* Instance of a single type part of a union is sufficient to pass the type check */ /* Instance of a single type part of a union is sufficient to pass the type check */
if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) { if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) {
return true; return true;
} }
PROGRESS_CACHE_SLOT();
} }
} ZEND_TYPE_LIST_FOREACH_END(); } ZEND_TYPE_LIST_FOREACH_END();
} }
} else { } else {
ce = zend_fetch_ce_from_cache_slot(cache_slot, type); ce = zend_fetch_ce_from_type(type);
/* If we have a CE we check if it satisfies the type constraint, /* If we have a CE we check if it satisfies the type constraint,
* otherwise it will check if a standard type satisfies it. */ * otherwise it will check if a standard type satisfies it. */
if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) { if (ce && instanceof_function(Z_OBJCE_P(arg), ce)) {
@ -1232,7 +1204,7 @@ static zend_always_inline bool zend_check_type_slow(
} }
static zend_always_inline bool zend_check_type( static zend_always_inline bool zend_check_type(
const zend_type *type, zval *arg, void **cache_slot, zend_class_entry *scope, const zend_type *type, zval *arg, zend_class_entry *scope,
bool is_return_type, bool is_internal) bool is_return_type, bool is_internal)
{ {
const zend_reference *ref = NULL; const zend_reference *ref = NULL;
@ -1247,17 +1219,17 @@ static zend_always_inline bool zend_check_type(
return 1; return 1;
} }
return zend_check_type_slow(type, arg, ref, cache_slot, is_return_type, is_internal); return zend_check_type_slow(type, arg, ref, is_return_type, is_internal);
} }
ZEND_API bool zend_check_user_type_slow( ZEND_API bool zend_check_user_type_slow(
const zend_type *type, zval *arg, const zend_reference *ref, void **cache_slot, bool is_return_type) const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type)
{ {
return zend_check_type_slow( return zend_check_type_slow(
type, arg, ref, cache_slot, is_return_type, /* is_internal */ false); type, arg, ref, is_return_type, /* is_internal */ false);
} }
static zend_always_inline bool zend_verify_recv_arg_type(const zend_function *zf, uint32_t arg_num, zval *arg, void **cache_slot) static zend_always_inline bool zend_verify_recv_arg_type(const zend_function *zf, uint32_t arg_num, zval *arg)
{ {
const zend_arg_info *cur_arg_info; const zend_arg_info *cur_arg_info;
@ -1265,7 +1237,7 @@ static zend_always_inline bool zend_verify_recv_arg_type(const zend_function *zf
cur_arg_info = &zf->common.arg_info[arg_num-1]; cur_arg_info = &zf->common.arg_info[arg_num-1];
if (ZEND_TYPE_IS_SET(cur_arg_info->type) if (ZEND_TYPE_IS_SET(cur_arg_info->type)
&& UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) { && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, zf->common.scope, 0, 0))) {
zend_verify_arg_error(zf, cur_arg_info, arg_num, arg); zend_verify_arg_error(zf, cur_arg_info, arg_num, arg);
return 0; return 0;
} }
@ -1274,10 +1246,10 @@ static zend_always_inline bool zend_verify_recv_arg_type(const zend_function *zf
} }
static zend_always_inline bool zend_verify_variadic_arg_type( static zend_always_inline bool zend_verify_variadic_arg_type(
const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, zval *arg, void **cache_slot) const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, zval *arg)
{ {
ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type)); ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
if (UNEXPECTED(!zend_check_type(&arg_info->type, arg, cache_slot, zf->common.scope, 0, 0))) { if (UNEXPECTED(!zend_check_type(&arg_info->type, arg, zf->common.scope, 0, 0))) {
zend_verify_arg_error(zf, arg_info, arg_num, arg); zend_verify_arg_error(zf, arg_info, arg_num, arg);
return 0; return 0;
} }
@ -1302,7 +1274,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ
} }
if (ZEND_TYPE_IS_SET(cur_arg_info->type) if (ZEND_TYPE_IS_SET(cur_arg_info->type)
&& UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, /* cache_slot */ NULL, fbc->common.scope, 0, /* is_internal */ 1))) { && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, fbc->common.scope, 0, /* is_internal */ 1))) {
return 0; return 0;
} }
arg++; arg++;
@ -1508,7 +1480,7 @@ ZEND_API bool zend_verify_internal_return_type(const zend_function *zf, zval *re
return 1; return 1;
} }
if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) { if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, NULL, 1, /* is_internal */ 1))) {
zend_verify_internal_return_error(zf, ret); zend_verify_internal_return_error(zf, ret);
return 0; return 0;
} }

View file

@ -106,7 +106,7 @@ ZEND_API ZEND_COLD void zend_verify_never_error(
const zend_function *zf); const zend_function *zf);
ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref); ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref);
ZEND_API bool zend_check_user_type_slow( ZEND_API bool zend_check_user_type_slow(
const zend_type *type, zval *arg, const zend_reference *ref, void **cache_slot, bool is_return_type); const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type);
#if ZEND_DEBUG #if ZEND_DEBUG
ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_execute_data *call); ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_execute_data *call);

View file

@ -4423,7 +4423,7 @@ ZEND_VM_C_LABEL(fcall_end):
ZEND_VM_CONTINUE(); ZEND_VM_CONTINUE();
} }
ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED|CACHE_SLOT) ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
{ {
if (OP1_TYPE == IS_UNUSED) { if (OP1_TYPE == IS_UNUSED) {
SAVE_OPLINE(); SAVE_OPLINE();
@ -4465,7 +4465,6 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
} }
zend_reference *ref = NULL; zend_reference *ref = NULL;
void *cache_slot = CACHE_ADDR(opline->op2.num);
if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(retval_ref != retval_ptr)) {
if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
ref = Z_REF_P(retval_ref); ref = Z_REF_P(retval_ref);
@ -4482,7 +4481,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
} }
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) {
zend_verify_return_error(EX(func), retval_ptr); zend_verify_return_error(EX(func), retval_ptr);
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
@ -5671,14 +5670,14 @@ ZEND_VM_HELPER(zend_verify_recv_arg_type_helper, ANY, ANY, zval *op_1)
USE_OPLINE USE_OPLINE
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), opline->op1.num, op_1, CACHE_ADDR(opline->extended_value)))) { if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), opline->op1.num, op_1))) {
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
ZEND_VM_NEXT_OPCODE(); ZEND_VM_NEXT_OPCODE();
} }
ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED, CACHE_SLOT) ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED)
{ {
USE_OPLINE USE_OPLINE
uint32_t arg_num = opline->op1.num; uint32_t arg_num = opline->op1.num;
@ -5697,7 +5696,7 @@ ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED, CACHE_SLOT)
ZEND_VM_NEXT_OPCODE(); ZEND_VM_NEXT_OPCODE();
} }
ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_RECV, op->op2.num == MAY_BE_ANY, ZEND_RECV_NOTYPE, NUM, NUM, CACHE_SLOT) ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_RECV, op->op2.num == MAY_BE_ANY, ZEND_RECV_NOTYPE, NUM, NUM)
{ {
USE_OPLINE USE_OPLINE
uint32_t arg_num = opline->op1.num; uint32_t arg_num = opline->op1.num;
@ -5709,7 +5708,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_RECV, op->op2.num == MAY_BE_ANY, ZEND_RECV_NO
ZEND_VM_NEXT_OPCODE(); ZEND_VM_NEXT_OPCODE();
} }
ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT) ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST)
{ {
USE_OPLINE USE_OPLINE
uint32_t arg_num; uint32_t arg_num;
@ -5749,7 +5748,7 @@ ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT)
ZEND_VM_C_LABEL(recv_init_check_type): ZEND_VM_C_LABEL(recv_init_check_type):
if ((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) { if ((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->extended_value)))) { if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param))) {
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
} }
@ -5759,7 +5758,7 @@ ZEND_VM_C_LABEL(recv_init_check_type):
ZEND_VM_NEXT_OPCODE(); ZEND_VM_NEXT_OPCODE();
} }
ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED, CACHE_SLOT) ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED)
{ {
USE_OPLINE USE_OPLINE
uint32_t arg_num = opline->op1.num; uint32_t arg_num = opline->op1.num;
@ -5782,7 +5781,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED, CACHE_SLOT)
if (ZEND_TYPE_IS_SET(arg_info->type)) { if (ZEND_TYPE_IS_SET(arg_info->type)) {
ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS); ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS);
do { do {
if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param, CACHE_ADDR(opline->extended_value)))) { if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param))) {
ZEND_HASH_FILL_FINISH(); ZEND_HASH_FILL_FINISH();
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
@ -5810,7 +5809,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED, CACHE_SLOT)
if (ZEND_TYPE_IS_SET(arg_info->type)) { if (ZEND_TYPE_IS_SET(arg_info->type)) {
SEPARATE_ARRAY(params); SEPARATE_ARRAY(params);
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EX(extra_named_params), name, param) { ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EX(extra_named_params), name, param) {
if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param, CACHE_ADDR(opline->extended_value)))) { if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param))) {
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
Z_TRY_ADDREF_P(param); Z_TRY_ADDREF_P(param);

23
Zend/zend_vm_execute.h generated
View file

@ -2757,7 +2757,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_verify_recv_
USE_OPLINE USE_OPLINE
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), opline->op1.num, op_1, CACHE_ADDR(opline->extended_value)))) { if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), opline->op1.num, op_1))) {
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
@ -4190,7 +4190,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CON
recv_init_check_type: recv_init_check_type:
if ((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) { if ((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->extended_value)))) { if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param))) {
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
} }
@ -4295,7 +4295,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_UNUSED_HAND
if (ZEND_TYPE_IS_SET(arg_info->type)) { if (ZEND_TYPE_IS_SET(arg_info->type)) {
ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS); ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS);
do { do {
if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param, CACHE_ADDR(opline->extended_value)))) { if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param))) {
ZEND_HASH_FILL_FINISH(); ZEND_HASH_FILL_FINISH();
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
@ -4323,7 +4323,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_UNUSED_HAND
if (ZEND_TYPE_IS_SET(arg_info->type)) { if (ZEND_TYPE_IS_SET(arg_info->type)) {
SEPARATE_ARRAY(params); SEPARATE_ARRAY(params);
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EX(extra_named_params), name, param) { ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EX(extra_named_params), name, param) {
if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param, CACHE_ADDR(opline->extended_value)))) { if (UNEXPECTED(!zend_verify_variadic_arg_type(EX(func), arg_info, arg_num, param))) {
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
Z_TRY_ADDREF_P(param); Z_TRY_ADDREF_P(param);
@ -10869,7 +10869,6 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYP
} }
zend_reference *ref = NULL; zend_reference *ref = NULL;
void *cache_slot = CACHE_ADDR(opline->op2.num);
if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(retval_ref != retval_ptr)) {
if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
ref = Z_REF_P(retval_ref); ref = Z_REF_P(retval_ref);
@ -10886,7 +10885,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYP
} }
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) {
zend_verify_return_error(EX(func), retval_ptr); zend_verify_return_error(EX(func), retval_ptr);
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
@ -21606,7 +21605,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
} }
zend_reference *ref = NULL; zend_reference *ref = NULL;
void *cache_slot = CACHE_ADDR(opline->op2.num);
if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(retval_ref != retval_ptr)) {
if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
ref = Z_REF_P(retval_ref); ref = Z_REF_P(retval_ref);
@ -21623,7 +21621,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
} }
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) {
zend_verify_return_error(EX(func), retval_ptr); zend_verify_return_error(EX(func), retval_ptr);
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
@ -30086,7 +30084,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
} }
zend_reference *ref = NULL; zend_reference *ref = NULL;
void *cache_slot = CACHE_ADDR(opline->op2.num);
if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(retval_ref != retval_ptr)) {
if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
ref = Z_REF_P(retval_ref); ref = Z_REF_P(retval_ref);
@ -30103,7 +30100,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
} }
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) {
zend_verify_return_error(EX(func), retval_ptr); zend_verify_return_error(EX(func), retval_ptr);
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
@ -37880,7 +37877,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
} }
zend_reference *ref = NULL; zend_reference *ref = NULL;
void *cache_slot = CACHE_ADDR(opline->op2.num);
if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(retval_ref != retval_ptr)) {
if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
ref = Z_REF_P(retval_ref); ref = Z_REF_P(retval_ref);
@ -37897,7 +37893,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
} }
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) {
zend_verify_return_error(EX(func), retval_ptr); zend_verify_return_error(EX(func), retval_ptr);
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }
@ -50681,7 +50677,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
} }
zend_reference *ref = NULL; zend_reference *ref = NULL;
void *cache_slot = CACHE_ADDR(opline->op2.num);
if (UNEXPECTED(retval_ref != retval_ptr)) { if (UNEXPECTED(retval_ref != retval_ptr)) {
if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
ref = Z_REF_P(retval_ref); ref = Z_REF_P(retval_ref);
@ -50698,7 +50693,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
} }
SAVE_OPLINE(); SAVE_OPLINE();
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) { if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) {
zend_verify_return_error(EX(func), retval_ptr); zend_verify_return_error(EX(func), retval_ptr);
HANDLE_EXCEPTION(); HANDLE_EXCEPTION();
} }

View file

@ -299,8 +299,8 @@ static uint32_t zend_vm_opcodes_flags[210] = {
0x00000000, 0x00000000,
0x01040310, 0x01040310,
0x00000003, 0x00000003,
0x00040110, 0x00000110,
0x00040310, 0x00000310,
0x00001307, 0x00001307,
0x00001301, 0x00001301,
0x00001301, 0x00001301,
@ -360,7 +360,7 @@ static uint32_t zend_vm_opcodes_flags[210] = {
0x00000007, 0x00000007,
0x00040003, 0x00040003,
0x09000007, 0x09000007,
0x0000a103, 0x00000103,
0x00002003, 0x00002003,
0x03000001, 0x03000001,
0x00000005, 0x00000005,
@ -400,7 +400,7 @@ static uint32_t zend_vm_opcodes_flags[210] = {
0x00000003, 0x00000003,
0x00000020, 0x00000020,
0x00003000, 0x00003000,
0x00040110, 0x00000110,
0x00000000, 0x00000000,
0x00000007, 0x00000007,
0x00000105, 0x00000105,

View file

@ -1900,9 +1900,8 @@ static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg
{ {
zend_execute_data *execute_data = EG(current_execute_data); zend_execute_data *execute_data = EG(current_execute_data);
const zend_op *opline = EX(opline); const zend_op *opline = EX(opline);
void **cache_slot = CACHE_ADDR(opline->extended_value);
bool ret = zend_check_user_type_slow( bool ret = zend_check_user_type_slow(
&arg_info->type, arg, /* ref */ NULL, cache_slot, /* is_return_type */ false); &arg_info->type, arg, /* ref */ NULL, /* is_return_type */ false);
if (UNEXPECTED(!ret)) { if (UNEXPECTED(!ret)) {
zend_verify_arg_error(EX(func), arg_info, opline->op1.num, arg); zend_verify_arg_error(EX(func), arg_info, opline->op1.num, arg);
return 0; return 0;
@ -1910,7 +1909,7 @@ static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg
return ret; return ret;
} }
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) static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info)
{ {
if (Z_TYPE_P(arg) == IS_NULL) { if (Z_TYPE_P(arg) == IS_NULL) {
ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type)); ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
@ -1919,7 +1918,7 @@ static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_a
} }
} }
if (UNEXPECTED(!zend_check_user_type_slow( if (UNEXPECTED(!zend_check_user_type_slow(
&arg_info->type, arg, /* ref */ NULL, cache_slot, /* is_return_type */ true))) { &arg_info->type, arg, /* ref */ NULL, /* is_return_type */ true))) {
zend_verify_return_error((zend_function*)op_array, arg); zend_verify_return_error((zend_function*)op_array, arg);
} }
} }

View file

@ -11031,11 +11031,10 @@ static bool zend_jit_verify_return_type(zend_jit_ctx *jit, const zend_op *opline
ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, 1); ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, 1);
} }
ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow), ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow),
ref, ref,
ir_LOAD_A(jit_EX(func)), ir_LOAD_A(jit_EX(func)),
ir_CONST_ADDR(arg_info), ir_CONST_ADDR(arg_info));
ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->op2.num));
zend_jit_check_exception(jit); zend_jit_check_exception(jit);