Skip to content

Commit d04ae8d

Browse files
Girgiasnikic
authored andcommitted
Export common type checking code for JIT
Also drop the unused scope arg
1 parent 7a43278 commit d04ae8d

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
@@ -963,7 +963,7 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf
963963
return zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES());
964964
}
965965

966-
ZEND_API bool zend_value_instanceof_static(zval *zv) {
966+
static zend_always_inline bool zend_value_instanceof_static(zval *zv) {
967967
if (Z_TYPE_P(zv) != IS_OBJECT) {
968968
return 0;
969969
}
@@ -975,8 +975,48 @@ ZEND_API bool zend_value_instanceof_static(zval *zv) {
975975
return instanceof_function(Z_OBJCE_P(zv), called_scope);
976976
}
977977

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

1075-
return zend_check_type_slow(type, arg, ref, cache_slot, scope, is_return_type, is_internal);
1115+
return zend_check_type_slow(type, arg, ref, cache_slot, is_return_type, is_internal);
10761116
}
10771117

10781118
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
@@ -4225,7 +4225,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
42254225
}
42264226

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

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
}
@@ -27902,7 +27902,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
2790227902
}
2790327903

2790427904
SAVE_OPLINE();
27905-
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) {
27905+
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
2790627906
zend_verify_return_error(EX(func), retval_ptr);
2790727907
HANDLE_EXCEPTION();
2790827908
}
@@ -35052,7 +35052,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
3505235052
}
3505335053

3505435054
SAVE_OPLINE();
35055-
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) {
35055+
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
3505635056
zend_verify_return_error(EX(func), retval_ptr);
3505735057
HANDLE_EXCEPTION();
3505835058
}
@@ -46792,7 +46792,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
4679246792
}
4679346793

4679446794
SAVE_OPLINE();
46795-
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) {
46795+
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
4679646796
zend_verify_return_error(EX(func), retval_ptr);
4679746797
HANDLE_EXCEPTION();
4679846798
}

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)