@@ -44,13 +44,19 @@ 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 ;
52
+
47
53
typedef struct _spl_SplObjectStorage { /* {{{ */
48
- HashTable storage ;
49
- zend_long index ;
50
- HashPosition pos ;
51
- zend_long flags ;
52
- zend_function * fptr_get_hash ;
53
- zend_object std ;
54
+ HashTable storage ;
55
+ zend_long index ;
56
+ HashPosition pos ;
57
+ zend_long flags ;
58
+ spl_SplObjectStorage_fptrs * fptrs ;
59
+ zend_object std ;
54
60
} spl_SplObjectStorage ; /* }}} */
55
61
56
62
/* {{{ storage is an assoc array of [zend_object*]=>[zval *obj, zval *inf] */
@@ -73,15 +79,19 @@ void spl_SplObjectStorage_free_storage(zend_object *object) /* {{{ */
73
79
zend_object_std_dtor (& intern -> std );
74
80
75
81
zend_hash_destroy (& intern -> storage );
82
+
83
+ if (UNEXPECTED (intern -> fptrs )) {
84
+ efree_size (intern -> fptrs , sizeof (spl_SplObjectStorage_fptrs ));
85
+ }
76
86
} /* }}} */
77
87
78
88
static int spl_object_storage_get_hash (zend_hash_key * key , spl_SplObjectStorage * intern , zend_object * obj ) {
79
- if (intern -> fptr_get_hash ) {
89
+ if (UNEXPECTED ( intern -> fptrs ) && intern -> fptrs -> get_hash ) {
80
90
zval param ;
81
91
zval rv ;
82
92
ZVAL_OBJ (& param , obj );
83
93
zend_call_method_with_1_params (
84
- & intern -> std , intern -> std .ce , & intern -> fptr_get_hash , "getHash" , & rv , & param );
94
+ & intern -> std , intern -> std .ce , & intern -> fptrs -> get_hash , "getHash" , & rv , & param );
85
95
if (!Z_ISUNDEF (rv )) {
86
96
if (Z_TYPE (rv ) == IS_STRING ) {
87
97
key -> key = Z_STR (rv );
@@ -125,8 +135,52 @@ static spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage
125
135
}
126
136
} /* }}} */
127
137
138
+ static spl_SplObjectStorageElement * spl_object_storage_create_element (zend_object * obj , zval * inf ) /* {{{ */
139
+ {
140
+ spl_SplObjectStorageElement * pelement = emalloc (sizeof (spl_SplObjectStorageElement ));
141
+ pelement -> obj = obj ;
142
+ GC_ADDREF (obj );
143
+ if (inf ) {
144
+ ZVAL_COPY (& pelement -> inf , inf );
145
+ } else {
146
+ ZVAL_NULL (& pelement -> inf );
147
+ }
148
+ return pelement ;
149
+ } /* }}} */
150
+
151
+ static spl_SplObjectStorageElement * spl_object_storage_attach_handle (spl_SplObjectStorage * intern , zend_object * obj , zval * inf ) /* {{{ */
152
+ {
153
+ uint32_t handle = obj -> handle ;
154
+ zval * entry_zv ;
155
+ spl_SplObjectStorageElement * pelement ;
156
+ entry_zv = zend_hash_index_lookup (& intern -> storage , handle );
157
+ ZEND_ASSERT (intern -> fptrs == NULL || !intern -> fptrs -> override_write_dimension );
158
+
159
+ if (Z_TYPE_P (entry_zv ) != IS_NULL ) {
160
+ ZEND_ASSERT (Z_TYPE_P (entry_zv ) == IS_PTR );
161
+ pelement = Z_PTR_P (entry_zv );
162
+ /* FIXME unsafe if destructor of inf moves/removes this entry */
163
+ zval_ptr_dtor (& pelement -> inf );
164
+ if (inf ) {
165
+ ZVAL_COPY (& pelement -> inf , inf );
166
+ } else {
167
+ ZVAL_NULL (& pelement -> inf );
168
+ }
169
+ return pelement ;
170
+ }
171
+
172
+ ZEND_ASSERT ((GC_FLAGS (& intern -> storage ) & IS_ARRAY_PERSISTENT ) == 0 );
173
+ pelement = spl_object_storage_create_element (obj , inf );
174
+ ZVAL_PTR (entry_zv , pelement );
175
+ return pelement ;
176
+ } /* }}} */
177
+
128
178
spl_SplObjectStorageElement * spl_object_storage_attach (spl_SplObjectStorage * intern , zend_object * obj , zval * inf ) /* {{{ */
129
179
{
180
+ if (EXPECTED (intern -> fptrs == NULL || !intern -> fptrs -> override_write_dimension )) {
181
+ return spl_object_storage_attach_handle (intern , obj , inf );
182
+ }
183
+
130
184
spl_SplObjectStorageElement * pelement , element ;
131
185
zend_hash_key key ;
132
186
if (spl_object_storage_get_hash (& key , intern , obj ) == FAILURE ) {
@@ -136,6 +190,7 @@ spl_SplObjectStorageElement *spl_object_storage_attach(spl_SplObjectStorage *int
136
190
pelement = spl_object_storage_get (intern , & key );
137
191
138
192
if (pelement ) {
193
+ /* FIXME unsafe if destructor of inf moves/removes this entry */
139
194
zval_ptr_dtor (& pelement -> inf );
140
195
if (inf ) {
141
196
ZVAL_COPY (& pelement -> inf , inf );
@@ -189,6 +244,9 @@ void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorag
189
244
intern -> index = 0 ;
190
245
} /* }}} */
191
246
247
+ #define SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , method ) \
248
+ (((zend_function *)zend_hash_str_find_ptr(&(class_type)->function_table, (method), sizeof((method)) - 1))->common.scope != spl_ce_SplObjectStorage)
249
+
192
250
static zend_object * spl_object_storage_new_ex (zend_class_entry * class_type , zend_object * orig ) /* {{{ */
193
251
{
194
252
spl_SplObjectStorage * intern ;
@@ -207,10 +265,21 @@ static zend_object *spl_object_storage_new_ex(zend_class_entry *class_type, zend
207
265
208
266
while (parent ) {
209
267
if (parent == spl_ce_SplObjectStorage ) {
268
+ /* TODO: Make these singletons with a map from class entry to IS_NULL/IS_PTR */
210
269
if (class_type != spl_ce_SplObjectStorage ) {
211
- intern -> fptr_get_hash = zend_hash_str_find_ptr (& class_type -> function_table , "gethash" , sizeof ("gethash" ) - 1 );
212
- if (intern -> fptr_get_hash -> common .scope == spl_ce_SplObjectStorage ) {
213
- intern -> fptr_get_hash = NULL ;
270
+ spl_SplObjectStorage_fptrs fptrs ;
271
+ fptrs .get_hash = zend_hash_str_find_ptr (& class_type -> function_table , "gethash" , sizeof ("gethash" ) - 1 );
272
+ if (fptrs .get_hash -> common .scope == spl_ce_SplObjectStorage ) {
273
+ fptrs .get_hash = NULL ;
274
+ }
275
+ fptrs .override_read_dimension = fptrs .get_hash != NULL ||
276
+ SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , "offsetget" ) ||
277
+ SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , "offsetexists" );
278
+
279
+ fptrs .override_write_dimension = fptrs .get_hash != NULL || SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , "offsetset" );
280
+ if (fptrs .get_hash || fptrs .override_read_dimension || fptrs .override_write_dimension ) {
281
+ intern -> fptrs = emalloc (sizeof (spl_SplObjectStorage_fptrs ));
282
+ * intern -> fptrs = fptrs ;
214
283
}
215
284
}
216
285
break ;
@@ -361,6 +430,39 @@ PHP_METHOD(SplObjectStorage, attach)
361
430
spl_object_storage_attach (intern , obj , inf );
362
431
} /* }}} */
363
432
433
+ static zval * spl_object_storage_read_dimension (zend_object * object , zval * offset , int type , zval * rv )
434
+ {
435
+ spl_SplObjectStorage * intern = spl_object_storage_from_obj (object );
436
+ if (UNEXPECTED (offset == NULL || Z_TYPE_P (offset ) != IS_OBJECT || (intern -> fptrs && intern -> fptrs -> override_read_dimension ))) {
437
+ /* Can't optimize it if getHash, offsetExists, or offsetGet is overridden */
438
+ return zend_std_read_dimension (object , offset , type , rv );
439
+ }
440
+ spl_SplObjectStorageElement * element = zend_hash_index_find_ptr (& intern -> storage , Z_OBJ_HANDLE_P (offset ));
441
+ if (type == BP_VAR_IS ) {
442
+ if (element == NULL ) {
443
+ return & EG (uninitialized_zval );
444
+ }
445
+ }
446
+
447
+ if (!element ) {
448
+ zend_throw_exception_ex (spl_ce_UnexpectedValueException , 0 , "Object not found" );
449
+ return NULL ;
450
+ } else {
451
+ ZVAL_COPY_DEREF (rv , & element -> inf );
452
+ return rv ;
453
+ }
454
+ }
455
+
456
+ static void spl_object_storage_write_dimension (zend_object * object , zval * offset , zval * inf )
457
+ {
458
+ spl_SplObjectStorage * intern = spl_object_storage_from_obj (object );
459
+ if (UNEXPECTED (offset == NULL || Z_TYPE_P (offset ) != IS_OBJECT || (intern -> fptrs && intern -> fptrs -> override_write_dimension ))) {
460
+ zend_std_write_dimension (object , offset , inf );
461
+ return ;
462
+ }
463
+ spl_object_storage_attach_handle (intern , Z_OBJ_P (offset ), inf );
464
+ }
465
+
364
466
/* {{{ Detaches an object from the storage */
365
467
PHP_METHOD (SplObjectStorage , detach )
366
468
{
@@ -1201,6 +1303,8 @@ PHP_MINIT_FUNCTION(spl_observer)
1201
1303
spl_handler_SplObjectStorage .clone_obj = spl_object_storage_clone ;
1202
1304
spl_handler_SplObjectStorage .get_gc = spl_object_storage_get_gc ;
1203
1305
spl_handler_SplObjectStorage .free_obj = spl_SplObjectStorage_free_storage ;
1306
+ spl_handler_SplObjectStorage .read_dimension = spl_object_storage_read_dimension ;
1307
+ spl_handler_SplObjectStorage .write_dimension = spl_object_storage_write_dimension ;
1204
1308
1205
1309
spl_ce_MultipleIterator = register_class_MultipleIterator (zend_ce_iterator );
1206
1310
spl_ce_MultipleIterator -> create_object = spl_SplObjectStorage_new ;
0 commit comments