From 2767cd03993e6d12f65d1db32d5ac80883594aac Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Wed, 1 Dec 2021 18:43:37 -0500 Subject: [PATCH] Cache method overrides of ArrayAccess in zend_class_entry Previously, code such as subclasses of SplFixedArray would check for method overrides when instantiating the objects. This optimization was mentioned as a followup to GH-6552 --- Zend/zend.h | 2 + Zend/zend_API.h | 1 + Zend/zend_compile.c | 1 + Zend/zend_interfaces.c | 23 ++++++++ Zend/zend_iterators.h | 7 +++ Zend/zend_object_handlers.c | 37 ++++++------- Zend/zend_opcode.c | 3 ++ Zend/zend_string.h | 4 -- ext/opcache/zend_file_cache.c | 15 ++++++ ext/opcache/zend_persist.c | 11 ++++ ext/opcache/zend_persist_calc.c | 3 ++ ext/spl/spl_fixedarray.c | 93 +++++++++------------------------ ext/spl/spl_observer.c | 10 ++-- 13 files changed, 112 insertions(+), 98 deletions(-) diff --git a/Zend/zend.h b/Zend/zend.h index 56b5a376f4c12..d58c02f4475b4 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -183,6 +183,8 @@ struct _zend_class_entry { /* allocated only if class implements Iterator or IteratorAggregate interface */ zend_class_iterator_funcs *iterator_funcs_ptr; + /* allocated only if class implements ArrayAccess interface */ + zend_class_arrayaccess_funcs *arrayaccess_funcs_ptr; /* handlers */ union { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index a0d5ebee10282..e31745298d9da 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -292,6 +292,7 @@ typedef struct _zend_fcall_info_cache { class_container.interfaces = NULL; \ class_container.get_iterator = NULL; \ class_container.iterator_funcs_ptr = NULL; \ + class_container.arrayaccess_funcs_ptr = NULL; \ class_container.info.internal.module = NULL; \ class_container.info.internal.builtin_functions = functions; \ } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index a5adfe7def5a7..f2abb634d86d4 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1802,6 +1802,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_hand ce->create_object = NULL; ce->get_iterator = NULL; ce->iterator_funcs_ptr = NULL; + ce->arrayaccess_funcs_ptr = NULL; ce->get_static_method = NULL; ce->parent = NULL; ce->parent_name = NULL; diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index a8cd9b534ed4c..83162d3b46066 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -359,6 +359,28 @@ static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry } /* }}} */ +/* {{{ zend_implement_arrayaccess */ +static int zend_implement_arrayaccess(zend_class_entry *interface, zend_class_entry *class_type) +{ + ZEND_ASSERT(!class_type->arrayaccess_funcs_ptr && "ArrayAccess funcs already set?"); + zend_class_arrayaccess_funcs *funcs_ptr = class_type->type == ZEND_INTERNAL_CLASS + ? pemalloc(sizeof(zend_class_arrayaccess_funcs), 1) + : zend_arena_alloc(&CG(arena), sizeof(zend_class_arrayaccess_funcs)); + class_type->arrayaccess_funcs_ptr = funcs_ptr; + + funcs_ptr->zf_offsetget = zend_hash_str_find_ptr( + &class_type->function_table, "offsetget", sizeof("offsetget") - 1); + funcs_ptr->zf_offsetexists = zend_hash_str_find_ptr( + &class_type->function_table, "offsetexists", sizeof("offsetexists") - 1); + funcs_ptr->zf_offsetset = zend_hash_str_find_ptr( + &class_type->function_table, "offsetset", sizeof("offsetset") - 1); + funcs_ptr->zf_offsetunset = zend_hash_str_find_ptr( + &class_type->function_table, "offsetunset", sizeof("offsetunset") - 1); + + return SUCCESS; +} +/* }}} */ + /* {{{ zend_user_serialize */ ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) { @@ -616,6 +638,7 @@ ZEND_API void zend_register_interfaces(void) zend_ce_serializable->interface_gets_implemented = zend_implement_serializable; zend_ce_arrayaccess = register_class_ArrayAccess(); + zend_ce_arrayaccess->interface_gets_implemented = zend_implement_arrayaccess; zend_ce_countable = register_class_Countable(); diff --git a/Zend/zend_iterators.h b/Zend/zend_iterators.h index bce98a24ac93c..5e7451f7eacc7 100644 --- a/Zend/zend_iterators.h +++ b/Zend/zend_iterators.h @@ -72,6 +72,13 @@ typedef struct _zend_class_iterator_funcs { zend_function *zf_rewind; } zend_class_iterator_funcs; +typedef struct _zend_class_arrayaccess_funcs { + zend_function *zf_offsetget; + zend_function *zf_offsetexists; + zend_function *zf_offsetset; + zend_function *zf_offsetunset; +} zend_class_arrayaccess_funcs; + BEGIN_EXTERN_C() /* given a zval, returns stuff that can be used to iterate it. */ ZEND_API zend_object_iterator* zend_iterator_unwrap(zval *array_ptr); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 85817d1ae7f11..529893b1de882 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -908,7 +908,9 @@ ZEND_API zval *zend_std_read_dimension(zend_object *object, zval *offset, int ty zend_class_entry *ce = object->ce; zval tmp_offset; - if (EXPECTED(zend_class_implements_interface(ce, zend_ce_arrayaccess) != 0)) { + /* arrayaccess_funcs_ptr is set if (and only if) the class implements zend_ce_arrayaccess */ + zend_class_arrayaccess_funcs *funcs = ce->arrayaccess_funcs_ptr; + if (EXPECTED(funcs)) { if (offset == NULL) { /* [] construct */ ZVAL_NULL(&tmp_offset); @@ -918,9 +920,7 @@ ZEND_API zval *zend_std_read_dimension(zend_object *object, zval *offset, int ty GC_ADDREF(object); if (type == BP_VAR_IS) { - zend_function *offsetexists = - zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETEXISTS)); - zend_call_known_instance_method_with_1_params(offsetexists, object, rv, &tmp_offset); + zend_call_known_instance_method_with_1_params(funcs->zf_offsetexists, object, rv, &tmp_offset); if (UNEXPECTED(Z_ISUNDEF_P(rv))) { OBJ_RELEASE(object); zval_ptr_dtor(&tmp_offset); @@ -935,9 +935,7 @@ ZEND_API zval *zend_std_read_dimension(zend_object *object, zval *offset, int ty zval_ptr_dtor(rv); } - zend_function *offsetget = - zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETGET)); - zend_call_known_instance_method_with_1_params(offsetget, object, rv, &tmp_offset); + zend_call_known_instance_method_with_1_params(funcs->zf_offsetget, object, rv, &tmp_offset); OBJ_RELEASE(object); zval_ptr_dtor(&tmp_offset); @@ -961,16 +959,15 @@ ZEND_API void zend_std_write_dimension(zend_object *object, zval *offset, zval * zend_class_entry *ce = object->ce; zval tmp_offset; - if (EXPECTED(zend_class_implements_interface(ce, zend_ce_arrayaccess) != 0)) { + zend_class_arrayaccess_funcs *funcs = ce->arrayaccess_funcs_ptr; + if (EXPECTED(funcs)) { if (!offset) { ZVAL_NULL(&tmp_offset); } else { ZVAL_COPY_DEREF(&tmp_offset, offset); } GC_ADDREF(object); - zend_function *offsetset = - zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETSET)); - zend_call_known_instance_method_with_2_params(offsetset, object, NULL, &tmp_offset, value); + zend_call_known_instance_method_with_2_params(funcs->zf_offsetset, object, NULL, &tmp_offset, value); OBJ_RELEASE(object); zval_ptr_dtor(&tmp_offset); } else { @@ -985,18 +982,15 @@ ZEND_API int zend_std_has_dimension(zend_object *object, zval *offset, int check zval retval, tmp_offset; int result; - if (EXPECTED(zend_class_implements_interface(ce, zend_ce_arrayaccess) != 0)) { + zend_class_arrayaccess_funcs *funcs = ce->arrayaccess_funcs_ptr; + if (EXPECTED(funcs)) { ZVAL_COPY_DEREF(&tmp_offset, offset); GC_ADDREF(object); - zend_function *offsetexists = - zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETEXISTS)); - zend_call_known_instance_method_with_1_params(offsetexists, object, &retval, &tmp_offset); + zend_call_known_instance_method_with_1_params(funcs->zf_offsetexists, object, &retval, &tmp_offset); result = i_zend_is_true(&retval); zval_ptr_dtor(&retval); if (check_empty && result && EXPECTED(!EG(exception))) { - zend_function *offsetget = - zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETGET)); - zend_call_known_instance_method_with_1_params(offsetget, object, &retval, &tmp_offset); + zend_call_known_instance_method_with_1_params(funcs->zf_offsetget, object, &retval, &tmp_offset); result = i_zend_is_true(&retval); zval_ptr_dtor(&retval); } @@ -1170,12 +1164,11 @@ ZEND_API void zend_std_unset_dimension(zend_object *object, zval *offset) /* {{{ zend_class_entry *ce = object->ce; zval tmp_offset; - if (zend_class_implements_interface(ce, zend_ce_arrayaccess)) { + zend_class_arrayaccess_funcs *funcs = ce->arrayaccess_funcs_ptr; + if (EXPECTED(funcs)) { ZVAL_COPY_DEREF(&tmp_offset, offset); GC_ADDREF(object); - zend_function *offsetunset = - zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETUNSET)); - zend_call_known_instance_method_with_1_params(offsetunset, object, NULL, &tmp_offset); + zend_call_known_instance_method_with_1_params(funcs->zf_offsetunset, object, NULL, &tmp_offset); OBJ_RELEASE(object); zval_ptr_dtor(&tmp_offset); } else { diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index ac4fb75e986ae..b215e5120af5b 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -469,6 +469,9 @@ ZEND_API void destroy_zend_class(zval *zv) if (ce->iterator_funcs_ptr) { free(ce->iterator_funcs_ptr); } + if (ce->arrayaccess_funcs_ptr) { + free(ce->arrayaccess_funcs_ptr); + } if (ce->num_interfaces > 0) { free(ce->interfaces); } diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 5a37ada0e47cd..0236bad20cf21 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -571,10 +571,6 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_AUTOGLOBAL_SERVER, "_SERVER") \ _(ZEND_STR_AUTOGLOBAL_ENV, "_ENV") \ _(ZEND_STR_AUTOGLOBAL_REQUEST, "_REQUEST") \ - _(ZEND_STR_OFFSETGET, "offsetget") \ - _(ZEND_STR_OFFSETSET, "offsetset") \ - _(ZEND_STR_OFFSETEXISTS, "offsetexists") \ - _(ZEND_STR_OFFSETUNSET, "offsetunset") \ _(ZEND_STR_COUNT, "count") \ diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 578556b8ef395..ef59254d70937 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -880,6 +880,14 @@ static void zend_file_cache_serialize_class(zval *zv, SERIALIZE_PTR(ce->iterator_funcs_ptr); } + if (ce->arrayaccess_funcs_ptr) { + SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetget); + SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetexists); + SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetset); + SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetunset); + SERIALIZE_PTR(ce->arrayaccess_funcs_ptr); + } + ZEND_MAP_PTR_INIT(ce->static_members_table, NULL); ZEND_MAP_PTR_INIT(ce->mutable_data, NULL); } @@ -1670,6 +1678,13 @@ static void zend_file_cache_unserialize_class(zval *zv, UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_current); UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_next); } + if (ce->arrayaccess_funcs_ptr) { + UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr); + UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetget); + UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetexists); + UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetset); + UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetunset); + } if (!(script->corrupted)) { ce->ce_flags |= ZEND_ACC_IMMUTABLE; diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index c438e6b38b81c..a572f5e3be87e 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -985,6 +985,9 @@ zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce) if (ce->iterator_funcs_ptr) { ce->iterator_funcs_ptr = zend_shared_memdup(ce->iterator_funcs_ptr, sizeof(zend_class_iterator_funcs)); } + if (ce->arrayaccess_funcs_ptr) { + ce->arrayaccess_funcs_ptr = zend_shared_memdup(ce->arrayaccess_funcs_ptr, sizeof(zend_class_arrayaccess_funcs)); + } if (ce->ce_flags & ZEND_ACC_CACHED) { return ce; @@ -1135,6 +1138,14 @@ void zend_update_parent_ce(zend_class_entry *ce) ce->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&ce->function_table, "next", sizeof("next") - 1); } } + + if (ce->arrayaccess_funcs_ptr) { + ZEND_ASSERT(zend_class_implements_interface(ce, zend_ce_arrayaccess)); + ce->arrayaccess_funcs_ptr->zf_offsetget = zend_hash_str_find_ptr(&ce->function_table, "offsetget", sizeof("offsetget") - 1); + ce->arrayaccess_funcs_ptr->zf_offsetexists = zend_hash_str_find_ptr(&ce->function_table, "offsetexists", sizeof("offsetexists") - 1); + ce->arrayaccess_funcs_ptr->zf_offsetset = zend_hash_str_find_ptr(&ce->function_table, "offsetset", sizeof("offsetset") - 1); + ce->arrayaccess_funcs_ptr->zf_offsetunset = zend_hash_str_find_ptr(&ce->function_table, "offsetunset", sizeof("offsetunset") - 1); + } } /* update methods */ diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 1eac4684c58af..06d746218d2ec 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -470,6 +470,9 @@ void zend_persist_class_entry_calc(zend_class_entry *ce) if (ce->iterator_funcs_ptr) { ADD_SIZE(sizeof(zend_class_iterator_funcs)); } + if (ce->arrayaccess_funcs_ptr) { + ADD_SIZE(sizeof(zend_class_arrayaccess_funcs)); + } if (ce->ce_flags & ZEND_ACC_CACHED) { return; diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 9503baeaba87b..dac31fe8c3001 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -40,23 +40,19 @@ PHPAPI zend_class_entry *spl_ce_SplFixedArray; ZEND_GET_MODULE(spl_fixedarray) #endif +/* Check if the object is an instance of a subclass of SplFixedArray that overrides method's implementation. + * Expect subclassing SplFixedArray to be rare and check that first. */ +#define HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, method) UNEXPECTED((object)->ce != spl_ce_SplFixedArray && (object)->ce->arrayaccess_funcs_ptr->method->common.scope != spl_ce_SplFixedArray) + typedef struct _spl_fixedarray { zend_long size; /* It is possible to resize this, so this can't be combined with the object */ zval *elements; } spl_fixedarray; -typedef struct _spl_fixedarray_methods { - zend_function *fptr_offset_get; - zend_function *fptr_offset_set; - zend_function *fptr_offset_has; - zend_function *fptr_offset_del; - zend_function *fptr_count; -} spl_fixedarray_methods; - typedef struct _spl_fixedarray_object { spl_fixedarray array; - spl_fixedarray_methods *methods; + zend_function *fptr_count; zend_object std; } spl_fixedarray_object; @@ -233,9 +229,6 @@ static void spl_fixedarray_object_free_storage(zend_object *object) spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); spl_fixedarray_dtor(&intern->array); zend_object_std_dtor(&intern->std); - if (intern->methods) { - efree(intern->methods); - } } static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, zend_object *orig, bool clone_orig) @@ -267,34 +260,11 @@ static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, z ZEND_ASSERT(parent); if (UNEXPECTED(inherited)) { - spl_fixedarray_methods methods; - methods.fptr_offset_get = zend_hash_str_find_ptr(&class_type->function_table, "offsetget", sizeof("offsetget") - 1); - if (methods.fptr_offset_get->common.scope == parent) { - methods.fptr_offset_get = NULL; - } - methods.fptr_offset_set = zend_hash_str_find_ptr(&class_type->function_table, "offsetset", sizeof("offsetset") - 1); - if (methods.fptr_offset_set->common.scope == parent) { - methods.fptr_offset_set = NULL; - } - methods.fptr_offset_has = zend_hash_str_find_ptr(&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1); - if (methods.fptr_offset_has->common.scope == parent) { - methods.fptr_offset_has = NULL; - } - methods.fptr_offset_del = zend_hash_str_find_ptr(&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1); - if (methods.fptr_offset_del->common.scope == parent) { - methods.fptr_offset_del = NULL; - } - methods.fptr_count = zend_hash_str_find_ptr(&class_type->function_table, "count", sizeof("count") - 1); - if (methods.fptr_count->common.scope == parent) { - methods.fptr_count = NULL; - } - /* Assume that most of the time in performance-sensitive code, SplFixedArray won't be subclassed with overrides for these ArrayAccess methods. */ - /* Save 32 bytes per object on 64-bit systems by combining the 5 null pointers into 1 null pointer */ - /* (This is already looking up 5 functions when any subclass of SplFixedArray is instantiated, which is inefficient) */ - if (methods.fptr_offset_get || methods.fptr_offset_set || methods.fptr_offset_del || methods.fptr_offset_has || methods.fptr_count) { - intern->methods = emalloc(sizeof(spl_fixedarray_methods)); - *intern->methods = methods; + zend_function *fptr_count = zend_hash_str_find_ptr(&class_type->function_table, "count", sizeof("count") - 1); + if (fptr_count->common.scope == parent) { + fptr_count = NULL; } + intern->fptr_count = fptr_count; } return &intern->std; @@ -374,27 +344,24 @@ static int spl_fixedarray_object_has_dimension(zend_object *object, zval *offset static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *offset, int type, zval *rv) { - spl_fixedarray_object *intern; - - intern = spl_fixed_array_from_obj(object); - if (type == BP_VAR_IS && !spl_fixedarray_object_has_dimension(object, offset, 0)) { return &EG(uninitialized_zval); } - if (UNEXPECTED(intern->methods && intern->methods->fptr_offset_get)) { + if (HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetget)) { zval tmp; if (!offset) { ZVAL_NULL(&tmp); offset = &tmp; } - zend_call_method_with_1_params(object, intern->std.ce, &intern->methods->fptr_offset_get, "offsetGet", rv, offset); + zend_call_known_instance_method_with_1_params(object->ce->arrayaccess_funcs_ptr->zf_offsetget, object, rv, offset); if (!Z_ISUNDEF_P(rv)) { return rv; } return &EG(uninitialized_zval); } + spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); return spl_fixedarray_object_read_dimension_helper(intern, offset); } @@ -429,20 +396,18 @@ static void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object * static void spl_fixedarray_object_write_dimension(zend_object *object, zval *offset, zval *value) { - spl_fixedarray_object *intern; - zval tmp; - - intern = spl_fixed_array_from_obj(object); + if (HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetset)) { + zval tmp; - if (UNEXPECTED(intern->methods && intern->methods->fptr_offset_set)) { if (!offset) { ZVAL_NULL(&tmp); offset = &tmp; } - zend_call_method_with_2_params(object, intern->std.ce, &intern->methods->fptr_offset_set, "offsetSet", NULL, offset, value); + zend_call_known_instance_method_with_2_params(object->ce->arrayaccess_funcs_ptr->zf_offsetset, object, NULL, offset, value); return; } + spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); spl_fixedarray_object_write_dimension_helper(intern, offset, value); } @@ -467,15 +432,12 @@ static void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object * static void spl_fixedarray_object_unset_dimension(zend_object *object, zval *offset) { - spl_fixedarray_object *intern; - - intern = spl_fixed_array_from_obj(object); - - if (UNEXPECTED(intern->methods && intern->methods->fptr_offset_del)) { - zend_call_method_with_1_params(object, intern->std.ce, &intern->methods->fptr_offset_del, "offsetUnset", NULL, offset); + if (UNEXPECTED(HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetunset))) { + zend_call_known_instance_method_with_1_params(object->ce->arrayaccess_funcs_ptr->zf_offsetunset, object, NULL, offset); return; } + spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); spl_fixedarray_object_unset_dimension_helper(intern, offset); } @@ -501,20 +463,17 @@ static bool spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *in static int spl_fixedarray_object_has_dimension(zend_object *object, zval *offset, int check_empty) { - spl_fixedarray_object *intern; - - intern = spl_fixed_array_from_obj(object); - - if (UNEXPECTED(intern->methods && intern->methods->fptr_offset_has)) { + if (HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetexists)) { zval rv; - bool result; - zend_call_method_with_1_params(object, intern->std.ce, &intern->methods->fptr_offset_has, "offsetExists", &rv, offset); - result = zend_is_true(&rv); + zend_call_known_instance_method_with_1_params(object->ce->arrayaccess_funcs_ptr->zf_offsetexists, object, &rv, offset); + bool result = zend_is_true(&rv); zval_ptr_dtor(&rv); return result; } + spl_fixedarray_object *intern = spl_fixed_array_from_obj(object); + return spl_fixedarray_object_has_dimension_helper(intern, offset, check_empty); } @@ -523,9 +482,9 @@ static int spl_fixedarray_object_count_elements(zend_object *object, zend_long * spl_fixedarray_object *intern; intern = spl_fixed_array_from_obj(object); - if (UNEXPECTED(intern->methods && intern->methods->fptr_count)) { + if (UNEXPECTED(intern->fptr_count)) { zval rv; - zend_call_method_with_0_params(object, intern->std.ce, &intern->methods->fptr_count, "count", &rv); + zend_call_known_instance_method_with_0_params(intern->fptr_count, object, &rv); if (!Z_ISUNDEF(rv)) { *count = zval_get_long(&rv); zval_ptr_dtor(&rv); diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index f16337673b66f..3ac375c5cd6b5 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -249,7 +249,7 @@ void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorag } /* }}} */ #define SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zstr_method) \ - (((zend_function *)zend_hash_find_ptr(&(class_type)->function_table, ZSTR_KNOWN(zstr_method)))->common.scope != spl_ce_SplObjectStorage) + (class_type->arrayaccess_funcs_ptr && class_type->arrayaccess_funcs_ptr->zstr_method) static zend_object *spl_object_storage_new_ex(zend_class_entry *class_type, zend_object *orig) /* {{{ */ { @@ -277,18 +277,18 @@ static zend_object *spl_object_storage_new_ex(zend_class_entry *class_type, zend intern->fptr_get_hash = get_hash; } if (intern->fptr_get_hash != NULL || - SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, ZEND_STR_OFFSETGET) || - SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, ZEND_STR_OFFSETEXISTS)) { + SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetget) || + SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetexists)) { intern->flags |= SOS_OVERRIDDEN_READ_DIMENSION; } if (intern->fptr_get_hash != NULL || - SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, ZEND_STR_OFFSETSET)) { + SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetset)) { intern->flags |= SOS_OVERRIDDEN_WRITE_DIMENSION; } if (intern->fptr_get_hash != NULL || - SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, ZEND_STR_OFFSETUNSET)) { + SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetunset)) { intern->flags |= SOS_OVERRIDDEN_UNSET_DIMENSION; } }