Skip to content

Commit 9508af7

Browse files
committed
Export common type checking code for JIT
Also drop the unused scope arg
1 parent a02eb62 commit 9508af7

File tree

5 files changed

+56
-120
lines changed

5 files changed

+56
-120
lines changed

Zend/zend_execute.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf
961961
return zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES());
962962
}
963963

964-
ZEND_API bool zend_value_instanceof_static(zval *zv) {
964+
static zend_always_inline bool zend_value_instanceof_static(zval *zv) {
965965
if (Z_TYPE_P(zv) != IS_OBJECT) {
966966
return 0;
967967
}
@@ -973,8 +973,48 @@ ZEND_API bool zend_value_instanceof_static(zval *zv) {
973973
return instanceof_function(Z_OBJCE_P(zv), called_scope);
974974
}
975975

976-
static zend_always_inline bool zend_check_type_slow(
977-
zend_type *type, zval *arg, zend_reference *ref, void **cache_slot, zend_class_entry *scope,
976+
/* The cache_slot may only be NULL in debug builds, where arginfo verification of
977+
* internal functions is enabled. Avoid unnecessary checks in release builds. */
978+
#if ZEND_DEBUG
979+
# define HAVE_CACHE_SLOT (cache_slot != NULL)
980+
#else
981+
# define HAVE_CACHE_SLOT 1
982+
#endif
983+
984+
static zend_always_inline zend_class_entry* zend_fetch_ce_from_cache_slot(void **cache_slot, zend_type *type)
985+
{
986+
zend_class_entry *ce;
987+
988+
if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) {
989+
ce = (zend_class_entry *) *cache_slot;
990+
} else {
991+
zend_string *name = ZEND_TYPE_NAME(*type);
992+
993+
if (ZSTR_HAS_CE_CACHE(name)) {
994+
ce = ZSTR_GET_CE_CACHE(name);
995+
if (!ce) {
996+
ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
997+
if (UNEXPECTED(!ce)) {
998+
/* Cannot resolve */
999+
return NULL;
1000+
}
1001+
}
1002+
} else {
1003+
ce = zend_fetch_class(name,
1004+
ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT);
1005+
if (UNEXPECTED(!ce)) {
1006+
return NULL;
1007+
}
1008+
}
1009+
if (HAVE_CACHE_SLOT) {
1010+
*cache_slot = (void *) ce;
1011+
}
1012+
}
1013+
return ce;
1014+
}
1015+
1016+
ZEND_API bool zend_check_type_slow(
1017+
zend_type *type, zval *arg, zend_reference *ref, void **cache_slot,
9781018
bool is_return_type, bool is_internal)
9791019
{
9801020
uint32_t type_mask;
@@ -1070,7 +1110,7 @@ static zend_always_inline bool zend_check_type(
10701110
return 1;
10711111
}
10721112

1073-
return zend_check_type_slow(type, arg, ref, cache_slot, scope, is_return_type, is_internal);
1113+
return zend_check_type_slow(type, arg, ref, cache_slot, is_return_type, is_internal);
10741114
}
10751115

10761116
static zend_always_inline bool zend_verify_recv_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, void **cache_slot)

Zend/zend_execute.h

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ ZEND_API ZEND_COLD void zend_verify_return_error(
7676
ZEND_API ZEND_COLD void zend_verify_never_error(
7777
const zend_function *zf);
7878
ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref);
79-
ZEND_API bool zend_value_instanceof_static(zval *zv);
79+
ZEND_API bool zend_check_type_slow(zend_type *type, zval *arg, zend_reference *ref, void **cache_slot,
80+
bool is_return_type, bool is_internal);
8081

8182

8283
#define ZEND_REF_TYPE_SOURCES(ref) \
@@ -459,46 +460,6 @@ ZEND_COLD void zend_verify_property_type_error(zend_property_info *info, zval *p
459460
} \
460461
} while (0)
461462

462-
/* The cache_slot may only be NULL in debug builds, where arginfo verification of
463-
* internal functions is enabled. Avoid unnecessary checks in release builds. */
464-
#if ZEND_DEBUG
465-
# define HAVE_CACHE_SLOT (cache_slot != NULL)
466-
#else
467-
# define HAVE_CACHE_SLOT 1
468-
#endif
469-
470-
static zend_always_inline zend_class_entry* zend_fetch_ce_from_cache_slot(void **cache_slot, zend_type *type)
471-
{
472-
zend_class_entry *ce;
473-
474-
if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) {
475-
ce = (zend_class_entry *) *cache_slot;
476-
} else {
477-
zend_string *name = ZEND_TYPE_NAME(*type);
478-
479-
if (ZSTR_HAS_CE_CACHE(name)) {
480-
ce = ZSTR_GET_CE_CACHE(name);
481-
if (!ce) {
482-
ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
483-
if (UNEXPECTED(!ce)) {
484-
/* Cannot resolve */
485-
return NULL;
486-
}
487-
}
488-
} else {
489-
ce = zend_fetch_class(name,
490-
ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT);
491-
if (UNEXPECTED(!ce)) {
492-
return NULL;
493-
}
494-
}
495-
if (HAVE_CACHE_SLOT) {
496-
*cache_slot = (void *) ce;
497-
}
498-
}
499-
return ce;
500-
}
501-
502463
END_EXTERN_C()
503464

504465
#endif /* ZEND_EXECUTE_H */

Zend/zend_vm_def.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4224,7 +4224,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
42244224
}
42254225

42264226
SAVE_OPLINE();
4227-
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) {
4227+
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
42284228
zend_verify_return_error(EX(func), retval_ptr);
42294229
HANDLE_EXCEPTION();
42304230
}

Zend/zend_vm_execute.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9995,7 +9995,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYP
99959995
}
99969996

99979997
SAVE_OPLINE();
9998-
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) {
9998+
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
99999999
zend_verify_return_error(EX(func), retval_ptr);
1000010000
HANDLE_EXCEPTION();
1000110001
}
@@ -20370,7 +20370,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
2037020370
}
2037120371

2037220372
SAVE_OPLINE();
20373-
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) {
20373+
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
2037420374
zend_verify_return_error(EX(func), retval_ptr);
2037520375
HANDLE_EXCEPTION();
2037620376
}
@@ -27901,7 +27901,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
2790127901
}
2790227902

2790327903
SAVE_OPLINE();
27904-
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) {
27904+
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
2790527905
zend_verify_return_error(EX(func), retval_ptr);
2790627906
HANDLE_EXCEPTION();
2790727907
}
@@ -35050,7 +35050,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
3505035050
}
3505135051

3505235052
SAVE_OPLINE();
35053-
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) {
35053+
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
3505435054
zend_verify_return_error(EX(func), retval_ptr);
3505535055
HANDLE_EXCEPTION();
3505635056
}
@@ -46789,7 +46789,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
4678946789
}
4679046790

4679146791
SAVE_OPLINE();
46792-
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) {
46792+
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
4679346793
zend_verify_return_error(EX(func), retval_ptr);
4679446794
HANDLE_EXCEPTION();
4679546795
}

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 4 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,81 +1320,15 @@ static zend_reference* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_string *v
13201320
return ref;
13211321
}
13221322

1323-
static zend_always_inline bool zend_jit_verify_type_common(zval *arg, zend_arg_info *arg_info, void **cache_slot)
1324-
{
1325-
uint32_t type_mask;
1326-
1327-
if (ZEND_TYPE_IS_COMPLEX(arg_info->type) && Z_TYPE_P(arg) == IS_OBJECT) {
1328-
zend_class_entry *ce;
1329-
if (ZEND_TYPE_HAS_LIST(arg_info->type)) {
1330-
zend_type *list_type;
1331-
if (ZEND_TYPE_IS_INTERSECTION(arg_info->type)) {
1332-
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), list_type) {
1333-
ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type);
1334-
/* If we cannot resolve the CE we cannot check if it satisfies
1335-
* the type constraint, fail. */
1336-
if (ce == NULL) {
1337-
return false;
1338-
}
1339-
if (!instanceof_function(Z_OBJCE_P(arg), ce)) {
1340-
return false;
1341-
}
1342-
cache_slot++;
1343-
} ZEND_TYPE_LIST_FOREACH_END();
1344-
return true;
1345-
} else {
1346-
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), list_type) {
1347-
ce = zend_fetch_ce_from_cache_slot(cache_slot, list_type);
1348-
/* If we cannot resolve the CE we cannot check if it satisfies
1349-
* the type constraint, check the next one. */
1350-
if (ce == NULL) {
1351-
cache_slot++;
1352-
continue;
1353-
}
1354-
if (instanceof_function(Z_OBJCE_P(arg), ce)) {
1355-
return 1;
1356-
}
1357-
cache_slot++;
1358-
} ZEND_TYPE_LIST_FOREACH_END();
1359-
}
1360-
} else {
1361-
ce = zend_fetch_ce_from_cache_slot(cache_slot, &arg_info->type);
1362-
/* If we cannot resolve the CE we cannot check if it satisfies
1363-
* the type constraint, check if a standard type satisfies it. */
1364-
if (ce == NULL) {
1365-
goto builtin_types;
1366-
}
1367-
if (instanceof_function(Z_OBJCE_P(arg), ce)) {
1368-
return 1;
1369-
}
1370-
}
1371-
}
1372-
1373-
builtin_types:
1374-
type_mask = ZEND_TYPE_FULL_MASK(arg_info->type);
1375-
if ((type_mask & MAY_BE_CALLABLE) && zend_is_callable(arg, 0, NULL)) {
1376-
return 1;
1377-
}
1378-
if ((type_mask & MAY_BE_ITERABLE) && zend_is_iterable(arg)) {
1379-
return 1;
1380-
}
1381-
if ((type_mask & MAY_BE_STATIC) && zend_value_instanceof_static(arg)) {
1382-
return 1;
1383-
}
1384-
if (zend_verify_scalar_type_hint(type_mask, arg, ZEND_ARG_USES_STRICT_TYPES(), /* is_internal */ 0)) {
1385-
return 1;
1386-
}
1387-
return 0;
1388-
}
1389-
13901323
static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg_info)
13911324
{
13921325
zend_execute_data *execute_data = EG(current_execute_data);
13931326
const zend_op *opline = EX(opline);
13941327
void **cache_slot = CACHE_ADDR(opline->extended_value);
13951328
bool ret;
13961329

1397-
ret = zend_jit_verify_type_common(arg, arg_info, cache_slot);
1330+
ret = zend_check_type_slow(&arg_info->type, arg, /* ref */ NULL, cache_slot,
1331+
/* is_return_type */ false, /* is_internal */ false);
13981332
if (UNEXPECTED(!ret)) {
13991333
zend_verify_arg_error(EX(func), arg_info, opline->op1.num, arg);
14001334
return 0;
@@ -1404,7 +1338,8 @@ static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg
14041338

14051339
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)
14061340
{
1407-
if (UNEXPECTED(!zend_jit_verify_type_common(arg, arg_info, cache_slot))) {
1341+
if (UNEXPECTED(!zend_check_type_slow(&arg_info->type, arg, /* ref */ NULL, cache_slot,
1342+
/* is_return_type */ true, /* is_internal */ false))) {
14081343
zend_verify_return_error((zend_function*)op_array, arg);
14091344
}
14101345
}

0 commit comments

Comments
 (0)