@@ -44,19 +44,20 @@ PHPAPI zend_class_entry *spl_ce_MultipleIterator;
44
44
45
45
PHPAPI zend_object_handlers spl_handler_SplObjectStorage ;
46
46
47
- typedef struct _spl_SplObjectStorage_fptrs {
48
- zend_function * get_hash ;
49
- bool override_read_dimension ;
50
- bool override_write_dimension ;
51
- } spl_SplObjectStorage_fptrs ;
47
+ typedef enum {
48
+ SOS_OVERRIDDEN_READ_DIMENSION = 1 ,
49
+ SOS_OVERRIDDEN_WRITE_DIMENSION = 2 ,
50
+ } SplObjectStorageBitFlags ;
52
51
53
52
typedef struct _spl_SplObjectStorage { /* {{{ */
54
- HashTable storage ;
55
- zend_long index ;
56
- HashPosition pos ;
57
- zend_long flags ;
58
- spl_SplObjectStorage_fptrs * fptrs ;
59
- zend_object std ;
53
+ HashTable storage ;
54
+ zend_long index ;
55
+ HashPosition pos ;
56
+ /* In SplObjectStorage, flags is a hidden implementation detail to optimize ArrayAccess handlers.
57
+ * In MultipleIterator on a different class hierarchy, flags is a user settable value controlling iteration behavior. */
58
+ zend_long flags ;
59
+ zend_function * fptr_get_hash ;
60
+ zend_object std ;
60
61
} spl_SplObjectStorage ; /* }}} */
61
62
62
63
/* {{{ storage is an assoc array of [zend_object*]=>[zval *obj, zval *inf] */
@@ -79,19 +80,15 @@ void spl_SplObjectStorage_free_storage(zend_object *object) /* {{{ */
79
80
zend_object_std_dtor (& intern -> std );
80
81
81
82
zend_hash_destroy (& intern -> storage );
82
-
83
- if (UNEXPECTED (intern -> fptrs )) {
84
- efree_size (intern -> fptrs , sizeof (spl_SplObjectStorage_fptrs ));
85
- }
86
83
} /* }}} */
87
84
88
85
static int spl_object_storage_get_hash (zend_hash_key * key , spl_SplObjectStorage * intern , zend_object * obj ) {
89
- if (UNEXPECTED (intern -> fptrs ) && intern -> fptrs -> get_hash ) {
86
+ if (UNEXPECTED (intern -> fptr_get_hash ) ) {
90
87
zval param ;
91
88
zval rv ;
92
89
ZVAL_OBJ (& param , obj );
93
90
zend_call_method_with_1_params (
94
- & intern -> std , intern -> std .ce , & intern -> fptrs -> get_hash , "getHash" , & rv , & param );
91
+ & intern -> std , intern -> std .ce , & intern -> fptr_get_hash , "getHash" , & rv , & param );
95
92
if (!Z_ISUNDEF (rv )) {
96
93
if (Z_TYPE (rv ) == IS_STRING ) {
97
94
key -> key = Z_STR (rv );
@@ -154,7 +151,7 @@ static spl_SplObjectStorageElement *spl_object_storage_attach_handle(spl_SplObje
154
151
zval * entry_zv ;
155
152
spl_SplObjectStorageElement * pelement ;
156
153
entry_zv = zend_hash_index_lookup (& intern -> storage , handle );
157
- ZEND_ASSERT (intern -> fptrs == NULL || ! intern -> fptrs -> override_write_dimension );
154
+ ZEND_ASSERT (!( intern -> flags & SOS_OVERRIDDEN_WRITE_DIMENSION ) );
158
155
159
156
if (Z_TYPE_P (entry_zv ) != IS_NULL ) {
160
157
zval zv_inf ;
@@ -179,7 +176,7 @@ static spl_SplObjectStorageElement *spl_object_storage_attach_handle(spl_SplObje
179
176
180
177
spl_SplObjectStorageElement * spl_object_storage_attach (spl_SplObjectStorage * intern , zend_object * obj , zval * inf ) /* {{{ */
181
178
{
182
- if (EXPECTED (intern -> fptrs == NULL || ! intern -> fptrs -> override_write_dimension )) {
179
+ if (EXPECTED (!( intern -> flags & SOS_OVERRIDDEN_WRITE_DIMENSION ) )) {
183
180
return spl_object_storage_attach_handle (intern , obj , inf );
184
181
}
185
182
@@ -269,21 +266,22 @@ static zend_object *spl_object_storage_new_ex(zend_class_entry *class_type, zend
269
266
270
267
while (parent ) {
271
268
if (parent == spl_ce_SplObjectStorage ) {
272
- /* TODO: Make these singletons with a map from class entry to IS_NULL/IS_PTR */
269
+ /* Possible optimization: Cache these results with a map from class entry to IS_NULL/IS_PTR.
270
+ * Or maybe just a single item with the result for the most recently loaded subclass. */
273
271
if (class_type != spl_ce_SplObjectStorage ) {
274
- spl_SplObjectStorage_fptrs fptrs ;
275
- fptrs .get_hash = zend_hash_str_find_ptr (& class_type -> function_table , "gethash" , sizeof ("gethash" ) - 1 );
276
- if (fptrs .get_hash -> common .scope == spl_ce_SplObjectStorage ) {
277
- fptrs .get_hash = NULL ;
272
+ zend_function * get_hash = zend_hash_str_find_ptr (& class_type -> function_table , "gethash" , sizeof ("gethash" ) - 1 );
273
+ if (get_hash -> common .scope != spl_ce_SplObjectStorage ) {
274
+ intern -> fptr_get_hash = get_hash ;
278
275
}
279
- fptrs . override_read_dimension = fptrs . get_hash != NULL ||
276
+ if ( get_hash != NULL ||
280
277
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , "offsetget" ) ||
281
- SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , "offsetexists" );
278
+ SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , "offsetexists" )) {
279
+ intern -> flags |= SOS_OVERRIDDEN_READ_DIMENSION ;
280
+ }
282
281
283
- fptrs .override_write_dimension = fptrs .get_hash != NULL || SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , "offsetset" );
284
- if (fptrs .get_hash || fptrs .override_read_dimension || fptrs .override_write_dimension ) {
285
- intern -> fptrs = emalloc (sizeof (spl_SplObjectStorage_fptrs ));
286
- * intern -> fptrs = fptrs ;
282
+ if (get_hash != NULL ||
283
+ SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , "offsetset" )) {
284
+ intern -> flags |= SOS_OVERRIDDEN_WRITE_DIMENSION ;
287
285
}
288
286
}
289
287
break ;
@@ -437,7 +435,7 @@ PHP_METHOD(SplObjectStorage, attach)
437
435
static zval * spl_object_storage_read_dimension (zend_object * object , zval * offset , int type , zval * rv )
438
436
{
439
437
spl_SplObjectStorage * intern = spl_object_storage_from_obj (object );
440
- if (UNEXPECTED (offset == NULL || Z_TYPE_P (offset ) != IS_OBJECT || (intern -> fptrs && intern -> fptrs -> override_read_dimension ))) {
438
+ if (UNEXPECTED (offset == NULL || Z_TYPE_P (offset ) != IS_OBJECT || (intern -> flags & SOS_OVERRIDDEN_READ_DIMENSION ))) {
441
439
/* Can't optimize it if getHash, offsetExists, or offsetGet is overridden */
442
440
return zend_std_read_dimension (object , offset , type , rv );
443
441
}
@@ -460,7 +458,7 @@ static zval *spl_object_storage_read_dimension(zend_object *object, zval *offset
460
458
static void spl_object_storage_write_dimension (zend_object * object , zval * offset , zval * inf )
461
459
{
462
460
spl_SplObjectStorage * intern = spl_object_storage_from_obj (object );
463
- if (UNEXPECTED (offset == NULL || Z_TYPE_P (offset ) != IS_OBJECT || (intern -> fptrs && intern -> fptrs -> override_write_dimension ))) {
461
+ if (UNEXPECTED (offset == NULL || Z_TYPE_P (offset ) != IS_OBJECT || (intern -> flags & SOS_OVERRIDDEN_WRITE_DIMENSION ))) {
464
462
zend_std_write_dimension (object , offset , inf );
465
463
return ;
466
464
}
0 commit comments