@@ -41,17 +41,22 @@ ZEND_GET_MODULE(spl_fixedarray)
4141
4242typedef struct _spl_fixedarray {
4343 zend_long size ;
44+ /* It is possible to resize this, so this can't be combined with the object */
4445 zval * elements ;
4546} spl_fixedarray ;
4647
47- typedef struct _spl_fixedarray_object {
48- spl_fixedarray array ;
48+ typedef struct _spl_fixedarray_methods {
4949 zend_function * fptr_offset_get ;
5050 zend_function * fptr_offset_set ;
5151 zend_function * fptr_offset_has ;
5252 zend_function * fptr_offset_del ;
5353 zend_function * fptr_count ;
54- zend_object std ;
54+ } spl_fixedarray_methods ;
55+
56+ typedef struct _spl_fixedarray_object {
57+ spl_fixedarray array ;
58+ spl_fixedarray_methods * methods ;
59+ zend_object std ;
5560} spl_fixedarray_object ;
5661
5762typedef struct _spl_fixedarray_it {
@@ -222,6 +227,9 @@ static void spl_fixedarray_object_free_storage(zend_object *object)
222227 spl_fixedarray_object * intern = spl_fixed_array_from_obj (object );
223228 spl_fixedarray_dtor (& intern -> array );
224229 zend_object_std_dtor (& intern -> std );
230+ if (intern -> methods ) {
231+ efree (intern -> methods );
232+ }
225233}
226234
227235static zend_object * spl_fixedarray_object_new_ex (zend_class_entry * class_type , zend_object * orig , bool clone_orig )
@@ -252,26 +260,34 @@ static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, z
252260
253261 ZEND_ASSERT (parent );
254262
255- if (inherited ) {
256- intern -> fptr_offset_get = zend_hash_str_find_ptr (& class_type -> function_table , "offsetget" , sizeof ("offsetget" ) - 1 );
257- if (intern -> fptr_offset_get -> common .scope == parent ) {
258- intern -> fptr_offset_get = NULL ;
263+ if (UNEXPECTED (inherited )) {
264+ spl_fixedarray_methods methods ;
265+ methods .fptr_offset_get = zend_hash_str_find_ptr (& class_type -> function_table , "offsetget" , sizeof ("offsetget" ) - 1 );
266+ if (methods .fptr_offset_get -> common .scope == parent ) {
267+ methods .fptr_offset_get = NULL ;
268+ }
269+ methods .fptr_offset_set = zend_hash_str_find_ptr (& class_type -> function_table , "offsetset" , sizeof ("offsetset" ) - 1 );
270+ if (methods .fptr_offset_set -> common .scope == parent ) {
271+ methods .fptr_offset_set = NULL ;
259272 }
260- intern -> fptr_offset_set = zend_hash_str_find_ptr (& class_type -> function_table , "offsetset " , sizeof ("offsetset " ) - 1 );
261- if (intern -> fptr_offset_set -> common .scope == parent ) {
262- intern -> fptr_offset_set = NULL ;
273+ methods . fptr_offset_has = zend_hash_str_find_ptr (& class_type -> function_table , "offsetexists " , sizeof ("offsetexists " ) - 1 );
274+ if (methods . fptr_offset_has -> common .scope == parent ) {
275+ methods . fptr_offset_has = NULL ;
263276 }
264- intern -> fptr_offset_has = zend_hash_str_find_ptr (& class_type -> function_table , "offsetexists " , sizeof ("offsetexists " ) - 1 );
265- if (intern -> fptr_offset_has -> common .scope == parent ) {
266- intern -> fptr_offset_has = NULL ;
277+ methods . fptr_offset_del = zend_hash_str_find_ptr (& class_type -> function_table , "offsetunset " , sizeof ("offsetunset " ) - 1 );
278+ if (methods . fptr_offset_del -> common .scope == parent ) {
279+ methods . fptr_offset_del = NULL ;
267280 }
268- intern -> fptr_offset_del = zend_hash_str_find_ptr (& class_type -> function_table , "offsetunset " , sizeof ("offsetunset " ) - 1 );
269- if (intern -> fptr_offset_del -> common .scope == parent ) {
270- intern -> fptr_offset_del = NULL ;
281+ methods . fptr_count = zend_hash_str_find_ptr (& class_type -> function_table , "count " , sizeof ("count " ) - 1 );
282+ if (methods . fptr_count -> common .scope == parent ) {
283+ methods . fptr_count = NULL ;
271284 }
272- intern -> fptr_count = zend_hash_str_find_ptr (& class_type -> function_table , "count" , sizeof ("count" ) - 1 );
273- if (intern -> fptr_count -> common .scope == parent ) {
274- intern -> fptr_count = NULL ;
285+ /* Assume that most of the time in performance-sensitive code, SplFixedArray won't be subclassed with overrides for these ArrayAccess methods. */
286+ /* Save 32 bytes per object on 64-bit systems by combining the 5 null pointers into 1 null pointer */
287+ /* (This is already looking up 5 functions when any subclass of SplFixedArray is instantiated, which is inefficient) */
288+ if (methods .fptr_offset_get || methods .fptr_offset_set || methods .fptr_offset_del || methods .fptr_offset_has || methods .fptr_count ) {
289+ intern -> methods = emalloc (sizeof (spl_fixedarray_methods ));
290+ * intern -> methods = methods ;
275291 }
276292 }
277293
@@ -329,15 +345,15 @@ static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *off
329345 return & EG (uninitialized_zval );
330346 }
331347
332- if (intern -> fptr_offset_get ) {
348+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_offset_get ) ) {
333349 zval tmp ;
334350 if (!offset ) {
335351 ZVAL_NULL (& tmp );
336352 offset = & tmp ;
337353 } else {
338354 SEPARATE_ARG_IF_REF (offset );
339355 }
340- zend_call_method_with_1_params (object , intern -> std .ce , & intern -> fptr_offset_get , "offsetGet" , rv , offset );
356+ zend_call_method_with_1_params (object , intern -> std .ce , & intern -> methods -> fptr_offset_get , "offsetGet" , rv , offset );
341357 zval_ptr_dtor (offset );
342358 if (!Z_ISUNDEF_P (rv )) {
343359 return rv ;
@@ -380,15 +396,15 @@ static void spl_fixedarray_object_write_dimension(zend_object *object, zval *off
380396
381397 intern = spl_fixed_array_from_obj (object );
382398
383- if (intern -> fptr_offset_set ) {
399+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_offset_set ) ) {
384400 if (!offset ) {
385401 ZVAL_NULL (& tmp );
386402 offset = & tmp ;
387403 } else {
388404 SEPARATE_ARG_IF_REF (offset );
389405 }
390406 SEPARATE_ARG_IF_REF (value );
391- zend_call_method_with_2_params (object , intern -> std .ce , & intern -> fptr_offset_set , "offsetSet" , NULL , offset , value );
407+ zend_call_method_with_2_params (object , intern -> std .ce , & intern -> methods -> fptr_offset_set , "offsetSet" , NULL , offset , value );
392408 zval_ptr_dtor (value );
393409 zval_ptr_dtor (offset );
394410 return ;
@@ -422,9 +438,9 @@ static void spl_fixedarray_object_unset_dimension(zend_object *object, zval *off
422438
423439 intern = spl_fixed_array_from_obj (object );
424440
425- if (intern -> fptr_offset_del ) {
441+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_offset_del ) ) {
426442 SEPARATE_ARG_IF_REF (offset );
427- zend_call_method_with_1_params (object , intern -> std .ce , & intern -> fptr_offset_del , "offsetUnset" , NULL , offset );
443+ zend_call_method_with_1_params (object , intern -> std .ce , & intern -> methods -> fptr_offset_del , "offsetUnset" , NULL , offset );
428444 zval_ptr_dtor (offset );
429445 return ;
430446 }
@@ -462,12 +478,12 @@ static int spl_fixedarray_object_has_dimension(zend_object *object, zval *offset
462478
463479 intern = spl_fixed_array_from_obj (object );
464480
465- if (intern -> fptr_offset_has ) {
481+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_offset_has ) ) {
466482 zval rv ;
467483 zend_bool result ;
468484
469485 SEPARATE_ARG_IF_REF (offset );
470- zend_call_method_with_1_params (object , intern -> std .ce , & intern -> fptr_offset_has , "offsetExists" , & rv , offset );
486+ zend_call_method_with_1_params (object , intern -> std .ce , & intern -> methods -> fptr_offset_has , "offsetExists" , & rv , offset );
471487 zval_ptr_dtor (offset );
472488 result = zend_is_true (& rv );
473489 zval_ptr_dtor (& rv );
@@ -482,9 +498,9 @@ static int spl_fixedarray_object_count_elements(zend_object *object, zend_long *
482498 spl_fixedarray_object * intern ;
483499
484500 intern = spl_fixed_array_from_obj (object );
485- if (intern -> fptr_count ) {
501+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_count ) ) {
486502 zval rv ;
487- zend_call_method_with_0_params (object , intern -> std .ce , & intern -> fptr_count , "count" , & rv );
503+ zend_call_method_with_0_params (object , intern -> std .ce , & intern -> methods -> fptr_count , "count" , & rv );
488504 if (!Z_ISUNDEF (rv )) {
489505 * count = zval_get_long (& rv );
490506 zval_ptr_dtor (& rv );
0 commit comments