@@ -41,17 +41,22 @@ ZEND_GET_MODULE(spl_fixedarray)
41
41
42
42
typedef struct _spl_fixedarray {
43
43
zend_long size ;
44
+ /* It is possible to resize this, so this can't be combined with the object */
44
45
zval * elements ;
45
46
} spl_fixedarray ;
46
47
47
- typedef struct _spl_fixedarray_object {
48
- spl_fixedarray array ;
48
+ typedef struct _spl_fixedarray_methods {
49
49
zend_function * fptr_offset_get ;
50
50
zend_function * fptr_offset_set ;
51
51
zend_function * fptr_offset_has ;
52
52
zend_function * fptr_offset_del ;
53
53
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 ;
55
60
} spl_fixedarray_object ;
56
61
57
62
typedef struct _spl_fixedarray_it {
@@ -222,6 +227,9 @@ static void spl_fixedarray_object_free_storage(zend_object *object)
222
227
spl_fixedarray_object * intern = spl_fixed_array_from_obj (object );
223
228
spl_fixedarray_dtor (& intern -> array );
224
229
zend_object_std_dtor (& intern -> std );
230
+ if (intern -> methods ) {
231
+ efree (intern -> methods );
232
+ }
225
233
}
226
234
227
235
static 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
252
260
253
261
ZEND_ASSERT (parent );
254
262
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 ;
259
272
}
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 ;
263
276
}
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 ;
267
280
}
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 ;
271
284
}
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 ;
275
291
}
276
292
}
277
293
@@ -329,15 +345,15 @@ static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *off
329
345
return & EG (uninitialized_zval );
330
346
}
331
347
332
- if (intern -> fptr_offset_get ) {
348
+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_offset_get ) ) {
333
349
zval tmp ;
334
350
if (!offset ) {
335
351
ZVAL_NULL (& tmp );
336
352
offset = & tmp ;
337
353
} else {
338
354
SEPARATE_ARG_IF_REF (offset );
339
355
}
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 );
341
357
zval_ptr_dtor (offset );
342
358
if (!Z_ISUNDEF_P (rv )) {
343
359
return rv ;
@@ -380,15 +396,15 @@ static void spl_fixedarray_object_write_dimension(zend_object *object, zval *off
380
396
381
397
intern = spl_fixed_array_from_obj (object );
382
398
383
- if (intern -> fptr_offset_set ) {
399
+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_offset_set ) ) {
384
400
if (!offset ) {
385
401
ZVAL_NULL (& tmp );
386
402
offset = & tmp ;
387
403
} else {
388
404
SEPARATE_ARG_IF_REF (offset );
389
405
}
390
406
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 );
392
408
zval_ptr_dtor (value );
393
409
zval_ptr_dtor (offset );
394
410
return ;
@@ -422,9 +438,9 @@ static void spl_fixedarray_object_unset_dimension(zend_object *object, zval *off
422
438
423
439
intern = spl_fixed_array_from_obj (object );
424
440
425
- if (intern -> fptr_offset_del ) {
441
+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_offset_del ) ) {
426
442
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 );
428
444
zval_ptr_dtor (offset );
429
445
return ;
430
446
}
@@ -462,12 +478,12 @@ static int spl_fixedarray_object_has_dimension(zend_object *object, zval *offset
462
478
463
479
intern = spl_fixed_array_from_obj (object );
464
480
465
- if (intern -> fptr_offset_has ) {
481
+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_offset_has ) ) {
466
482
zval rv ;
467
483
zend_bool result ;
468
484
469
485
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 );
471
487
zval_ptr_dtor (offset );
472
488
result = zend_is_true (& rv );
473
489
zval_ptr_dtor (& rv );
@@ -482,9 +498,9 @@ static int spl_fixedarray_object_count_elements(zend_object *object, zend_long *
482
498
spl_fixedarray_object * intern ;
483
499
484
500
intern = spl_fixed_array_from_obj (object );
485
- if (intern -> fptr_count ) {
501
+ if (UNEXPECTED ( intern -> methods && intern -> methods -> fptr_count ) ) {
486
502
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 );
488
504
if (!Z_ISUNDEF (rv )) {
489
505
* count = zval_get_long (& rv );
490
506
zval_ptr_dtor (& rv );
0 commit comments