Skip to content

Commit c858d17

Browse files
committed
Optimize instanceof_function
Split out the simple equality check into an inline function -- this is one of the common cases. Replace instanceof_function_ex with zend_class_implements_interface. There are a few more places where it may be used.
1 parent bd7b1af commit c858d17

9 files changed

+51
-51
lines changed

Zend/zend_API.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -4282,7 +4282,7 @@ ZEND_API zend_bool zend_is_iterable(zval *iterable) /* {{{ */
42824282
case IS_ARRAY:
42834283
return 1;
42844284
case IS_OBJECT:
4285-
return instanceof_function(Z_OBJCE_P(iterable), zend_ce_traversable);
4285+
return zend_class_implements_interface(Z_OBJCE_P(iterable), zend_ce_traversable);
42864286
default:
42874287
return 0;
42884288
}
@@ -4299,7 +4299,7 @@ ZEND_API zend_bool zend_is_countable(zval *countable) /* {{{ */
42994299
return 1;
43004300
}
43014301

4302-
return instanceof_function(Z_OBJCE_P(countable), zend_ce_countable);
4302+
return zend_class_implements_interface(Z_OBJCE_P(countable), zend_ce_countable);
43034303
default:
43044304
return 0;
43054305
}

Zend/zend_interfaces.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ static int zend_implement_serializable(zend_class_entry *interface, zend_class_e
512512
{
513513
if (class_type->parent
514514
&& (class_type->parent->serialize || class_type->parent->unserialize)
515-
&& !instanceof_function_ex(class_type->parent, zend_ce_serializable, 1)) {
515+
&& !zend_class_implements_interface(class_type->parent, zend_ce_serializable)) {
516516
return FAILURE;
517517
}
518518
if (!class_type->serialize) {

Zend/zend_object_handlers.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,7 @@ ZEND_API zval *zend_std_read_dimension(zend_object *object, zval *offset, int ty
898898
zend_class_entry *ce = object->ce;
899899
zval tmp_offset;
900900

901-
if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
901+
if (EXPECTED(zend_class_implements_interface(ce, zend_ce_arrayaccess) != 0)) {
902902
if (offset == NULL) {
903903
/* [] construct */
904904
ZVAL_NULL(&tmp_offset);
@@ -947,7 +947,7 @@ ZEND_API void zend_std_write_dimension(zend_object *object, zval *offset, zval *
947947
zend_class_entry *ce = object->ce;
948948
zval tmp_offset;
949949

950-
if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
950+
if (EXPECTED(zend_class_implements_interface(ce, zend_ce_arrayaccess) != 0)) {
951951
if (!offset) {
952952
ZVAL_NULL(&tmp_offset);
953953
} else {
@@ -969,7 +969,7 @@ ZEND_API int zend_std_has_dimension(zend_object *object, zval *offset, int check
969969
zval retval, tmp_offset;
970970
int result;
971971

972-
if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
972+
if (EXPECTED(zend_class_implements_interface(ce, zend_ce_arrayaccess) != 0)) {
973973
ZVAL_COPY_DEREF(&tmp_offset, offset);
974974
GC_ADDREF(object);
975975
zend_call_method_with_1_params(object, ce, NULL, "offsetexists", &retval, &tmp_offset);
@@ -1112,7 +1112,7 @@ ZEND_API void zend_std_unset_dimension(zend_object *object, zval *offset) /* {{{
11121112
zend_class_entry *ce = object->ce;
11131113
zval tmp_offset;
11141114

1115-
if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1)) {
1115+
if (zend_class_implements_interface(ce, zend_ce_arrayaccess)) {
11161116
ZVAL_COPY_DEREF(&tmp_offset, offset);
11171117
GC_ADDREF(object);
11181118
zend_call_method_with_1_params(object, ce, NULL, "offsetunset", NULL, &tmp_offset);

Zend/zend_operators.c

+30-34
Original file line numberDiff line numberDiff line change
@@ -2175,53 +2175,49 @@ ZEND_API int ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1,
21752175
}
21762176
/* }}} */
21772177

2178-
static zend_always_inline zend_bool instanceof_class(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2179-
{
2180-
do {
2181-
if (instance_ce == ce) {
2182-
return 1;
2183-
}
2184-
instance_ce = instance_ce->parent;
2185-
} while (instance_ce);
2186-
return 0;
2187-
}
2188-
/* }}} */
2189-
2190-
static zend_bool ZEND_FASTCALL instanceof_interface(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2178+
ZEND_API zend_bool ZEND_FASTCALL zend_class_implements_interface(const zend_class_entry *class_ce, const zend_class_entry *interface_ce) /* {{{ */
21912179
{
21922180
uint32_t i;
2181+
ZEND_ASSERT(!(class_ce->ce_flags & ZEND_ACC_INTERFACE));
2182+
ZEND_ASSERT(interface_ce->ce_flags & ZEND_ACC_INTERFACE);
21932183

2194-
if (instance_ce->num_interfaces) {
2195-
ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2196-
for (i = 0; i < instance_ce->num_interfaces; i++) {
2197-
if (instance_ce->interfaces[i] == ce) {
2184+
if (class_ce->num_interfaces) {
2185+
ZEND_ASSERT(class_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2186+
for (i = 0; i < class_ce->num_interfaces; i++) {
2187+
if (class_ce->interfaces[i] == interface_ce) {
21982188
return 1;
21992189
}
22002190
}
22012191
}
2202-
return instance_ce == ce;
2203-
}
2204-
/* }}} */
2205-
2206-
// TODO: It would make more sense to expose instanceof_class + instanceof_interface instead
2207-
ZEND_API zend_bool ZEND_FASTCALL instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool is_interface) /* {{{ */
2208-
{
2209-
if (is_interface) {
2210-
ZEND_ASSERT(ce->ce_flags & ZEND_ACC_INTERFACE);
2211-
return instanceof_interface(instance_ce, ce);
2212-
} else {
2213-
ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_INTERFACE));
2214-
return instanceof_class(instance_ce, ce);
2215-
}
2192+
return 0;
22162193
}
22172194
/* }}} */
22182195

2219-
ZEND_API zend_bool ZEND_FASTCALL instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2196+
ZEND_API zend_bool ZEND_FASTCALL instanceof_function_slow(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
22202197
{
2198+
ZEND_ASSERT(instance_ce != ce && "Should have been checked already");
22212199
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2222-
return instanceof_interface(instance_ce, ce);
2200+
uint32_t i;
2201+
2202+
if (instance_ce->num_interfaces) {
2203+
ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2204+
for (i = 0; i < instance_ce->num_interfaces; i++) {
2205+
if (instance_ce->interfaces[i] == ce) {
2206+
return 1;
2207+
}
2208+
}
2209+
}
2210+
return 0;
22232211
} else {
2224-
return instanceof_class(instance_ce, ce);
2212+
while (1) {
2213+
instance_ce = instance_ce->parent;
2214+
if (instance_ce == ce) {
2215+
return 1;
2216+
}
2217+
if (instance_ce == NULL) {
2218+
return 0;
2219+
}
2220+
}
22252221
}
22262222
}
22272223
/* }}} */

Zend/zend_operators.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@ ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *
6363
ZEND_API int ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2);
6464
ZEND_API int ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2);
6565

66-
ZEND_API zend_bool ZEND_FASTCALL instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool is_interface);
67-
ZEND_API zend_bool ZEND_FASTCALL instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce);
66+
ZEND_API zend_bool ZEND_FASTCALL zend_class_implements_interface(const zend_class_entry *class_ce, const zend_class_entry *interface_ce);
67+
ZEND_API zend_bool ZEND_FASTCALL instanceof_function_slow(const zend_class_entry *instance_ce, const zend_class_entry *ce);
68+
69+
static zend_always_inline zend_bool instanceof_function(
70+
const zend_class_entry *instance_ce, const zend_class_entry *ce) {
71+
return instance_ce == ce || instanceof_function_slow(instance_ce, ce);
72+
}
6873

6974
/**
7075
* Checks whether the string "str" with length "length" is numeric. The value

Zend/zend_vm_def.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -8424,7 +8424,7 @@ ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMPVAR|CV, UNUSED)
84248424
}
84258425

84268426
/* if not and the object implements Countable we call its count() method */
8427-
if (instanceof_function(zobj->ce, zend_ce_countable)) {
8427+
if (zend_class_implements_interface(zobj->ce, zend_ce_countable)) {
84288428
zval retval;
84298429

84308430
zend_call_method_with_0_params(zobj, NULL, NULL, "count", &retval);

Zend/zend_vm_execute.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -9254,7 +9254,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CONST_
92549254
}
92559255

92569256
/* if not and the object implements Countable we call its count() method */
9257-
if (instanceof_function(zobj->ce, zend_ce_countable)) {
9257+
if (zend_class_implements_interface(zobj->ce, zend_ce_countable)) {
92589258
zval retval;
92599259

92609260
zend_call_method_with_0_params(zobj, NULL, NULL, "count", &retval);
@@ -16319,7 +16319,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_TMPVAR_UNUSED_HANDL
1631916319
}
1632016320

1632116321
/* if not and the object implements Countable we call its count() method */
16322-
if (instanceof_function(zobj->ce, zend_ce_countable)) {
16322+
if (zend_class_implements_interface(zobj->ce, zend_ce_countable)) {
1632316323
zval retval;
1632416324

1632516325
zend_call_method_with_0_params(zobj, NULL, NULL, "count", &retval);
@@ -45446,7 +45446,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CV_UNUSED_HANDLER(Z
4544645446
}
4544745447

4544845448
/* if not and the object implements Countable we call its count() method */
45449-
if (instanceof_function(zobj->ce, zend_ce_countable)) {
45449+
if (zend_class_implements_interface(zobj->ce, zend_ce_countable)) {
4545045450
zval retval;
4545145451

4545245452
zend_call_method_with_0_params(zobj, NULL, NULL, "count", &retval);

ext/intl/dateformat/dateformat_helpers.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@ int datefmt_process_calendar_arg(zval* calendar_zv,
6969
cal_int_type = Z_LVAL_P(calendar_zv);
7070

7171
} else if (Z_TYPE_P(calendar_zv) == IS_OBJECT &&
72-
instanceof_function_ex(Z_OBJCE_P(calendar_zv),
73-
Calendar_ce_ptr, 0)) {
72+
instanceof_function(Z_OBJCE_P(calendar_zv), Calendar_ce_ptr)) {
7473

7574
cal = calendar_fetch_native_calendar(calendar_zv);
7675
if (cal == NULL) {

ext/opcache/zend_persist.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -923,10 +923,10 @@ static void zend_update_parent_ce(zend_class_entry *ce)
923923

924924
if (ce->iterator_funcs_ptr) {
925925
memset(ce->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
926-
if (instanceof_function_ex(ce, zend_ce_aggregate, 1)) {
926+
if (zend_class_implements_interface(ce, zend_ce_aggregate)) {
927927
ce->iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&ce->function_table, "getiterator", sizeof("getiterator") - 1);
928928
}
929-
if (instanceof_function_ex(ce, zend_ce_iterator, 1)) {
929+
if (zend_class_implements_interface(ce, zend_ce_iterator)) {
930930
ce->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&ce->function_table, "rewind", sizeof("rewind") - 1);
931931
ce->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&ce->function_table, "valid", sizeof("valid") - 1);
932932
ce->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&ce->function_table, "key", sizeof("key") - 1);

0 commit comments

Comments
 (0)