@@ -63,6 +63,7 @@ typedef struct _zend_weakmap_iterator {
63
63
*/
64
64
static zend_always_inline zend_ulong zend_object_ptr_to_weakref_key (const zend_object * object )
65
65
{
66
+ ZEND_ASSERT (((uintptr_t )object ) % ZEND_MM_ALIGNMENT == 0 );
66
67
return ((uintptr_t ) object ) >> ZEND_MM_ALIGNMENT_LOG2 ;
67
68
}
68
69
@@ -86,11 +87,13 @@ static inline void zend_weakref_unref_single(
86
87
void * ptr , uintptr_t tag , zend_object * object )
87
88
{
88
89
if (tag == ZEND_WEAKREF_TAG_REF ) {
90
+ /* Unreferencing WeakReference (at ptr) singleton that pointed to object. */
89
91
zend_weakref * wr = ptr ;
90
92
wr -> referent = NULL ;
91
93
} else {
94
+ /* unreferencing WeakMap entry (at ptr) with a key of object. */
92
95
ZEND_ASSERT (tag == ZEND_WEAKREF_TAG_MAP );
93
- zend_hash_index_del ((HashTable * ) ptr , ( zend_ulong ) ( uintptr_t ) object );
96
+ zend_hash_index_del ((HashTable * ) ptr , zend_object_ptr_to_weakref_key ( object ) );
94
97
}
95
98
}
96
99
@@ -132,6 +135,7 @@ static void zend_weakref_register(zend_object *object, void *payload) {
132
135
zend_hash_init (ht , 0 , NULL , NULL , 0 );
133
136
zend_hash_index_add_new_ptr (ht , (zend_ulong ) tagged_ptr , tagged_ptr );
134
137
zend_hash_index_add_new_ptr (ht , (zend_ulong ) payload , payload );
138
+ /* Replace the single WeakMap or WeakReference entry in EG(weakrefs) with a HashTable with 2 entries in place. */
135
139
ZVAL_PTR (zv , ZEND_WEAKREF_ENCODE (ht , ZEND_WEAKREF_TAG_HT ));
136
140
}
137
141
@@ -151,7 +155,7 @@ static void zend_weakref_unregister(zend_object *object, void *payload, bool wea
151
155
if (weakref_free ) {
152
156
zend_weakref_unref_single (ptr , tag , object );
153
157
} else {
154
- /* This optimization is only used in the destructor of WeakMap */
158
+ /* The optimization of skipping unref is only used in the destructor of WeakMap */
155
159
ZEND_ASSERT (ZEND_WEAKREF_GET_TAG (payload ) == ZEND_WEAKREF_TAG_MAP );
156
160
}
157
161
return ;
@@ -176,20 +180,21 @@ static void zend_weakref_unregister(zend_object *object, void *payload, bool wea
176
180
zend_weakref_unref_single (
177
181
ZEND_WEAKREF_GET_PTR (payload ), ZEND_WEAKREF_GET_TAG (payload ), object );
178
182
} else {
183
+ /* The optimization of skipping unref is only used in the destructor of WeakMap */
179
184
ZEND_ASSERT (ZEND_WEAKREF_GET_TAG (payload ) == ZEND_WEAKREF_TAG_MAP );
180
185
}
181
186
}
182
187
183
188
ZEND_API zval * zend_weakrefs_hash_add (HashTable * ht , zend_object * key , zval * pData ) {
184
- zval * zv = zend_hash_index_add (ht , ( zend_ulong ) key , pData );
189
+ zval * zv = zend_hash_index_add (ht , zend_object_ptr_to_weakref_key ( key ) , pData );
185
190
if (zv ) {
186
191
zend_weakref_register (key , ZEND_WEAKREF_ENCODE (ht , ZEND_WEAKREF_TAG_MAP ));
187
192
}
188
193
return zv ;
189
194
}
190
195
191
196
ZEND_API zend_result zend_weakrefs_hash_del (HashTable * ht , zend_object * key ) {
192
- zval * zv = zend_hash_index_find (ht , ( zend_ulong ) key );
197
+ zval * zv = zend_hash_index_find (ht , zend_object_ptr_to_weakref_key ( key ) );
193
198
if (zv ) {
194
199
zend_weakref_unregister (key , ZEND_WEAKREF_ENCODE (ht , ZEND_WEAKREF_TAG_MAP ), 1 );
195
200
return SUCCESS ;
@@ -201,6 +206,8 @@ void zend_weakrefs_init(void) {
201
206
zend_hash_init (& EG (weakrefs ), 8 , NULL , NULL , 0 );
202
207
}
203
208
209
+ /* This is called when the object is garbage collected
210
+ * to remove all WeakReference and WeakMap entries weakly referencing that object. */
204
211
void zend_weakrefs_notify (zend_object * object ) {
205
212
/* Annoyingly we can't use the HT destructor here, because we need access to the key (which
206
213
* is the object address), which is not provided to the dtor. */
@@ -326,13 +333,13 @@ static zend_object *zend_weakmap_create_object(zend_class_entry *ce)
326
333
static void zend_weakmap_free_obj (zend_object * object )
327
334
{
328
335
zend_weakmap * wm = zend_weakmap_from (object );
329
- zend_ulong obj_addr ;
330
- ZEND_HASH_MAP_FOREACH_NUM_KEY (& wm -> ht , obj_addr ) {
336
+ zend_ulong obj_key ;
337
+ ZEND_HASH_MAP_FOREACH_NUM_KEY (& wm -> ht , obj_key ) {
331
338
/* Optimization: Don't call zend_weakref_unref_single to free individual entries from wm->ht when unregistering (which would do a hash table lookup, call zend_hash_index_del, and skip over any bucket collisions).
332
339
* Let freeing the corresponding values for WeakMap entries be done in zend_hash_destroy, freeing objects sequentially.
333
340
* The performance difference is notable for larger WeakMaps with worse cache locality. */
334
341
zend_weakref_unregister (
335
- ( zend_object * ) obj_addr , ZEND_WEAKREF_ENCODE (& wm -> ht , ZEND_WEAKREF_TAG_MAP ), 0 );
342
+ zend_weakref_key_to_zend_object_ptr ( obj_key ) , ZEND_WEAKREF_ENCODE (& wm -> ht , ZEND_WEAKREF_TAG_MAP ), 0 );
336
343
} ZEND_HASH_FOREACH_END ();
337
344
zend_hash_destroy (& wm -> ht );
338
345
zend_object_std_dtor (& wm -> std );
@@ -352,7 +359,7 @@ static zval *zend_weakmap_read_dimension(zend_object *object, zval *offset, int
352
359
353
360
zend_weakmap * wm = zend_weakmap_from (object );
354
361
zend_object * obj_addr = Z_OBJ_P (offset );
355
- zval * zv = zend_hash_index_find (& wm -> ht , ( zend_ulong ) obj_addr );
362
+ zval * zv = zend_hash_index_find (& wm -> ht , zend_object_ptr_to_weakref_key ( obj_addr ) );
356
363
if (zv == NULL ) {
357
364
if (type != BP_VAR_IS ) {
358
365
zend_throw_error (NULL ,
@@ -382,9 +389,10 @@ static void zend_weakmap_write_dimension(zend_object *object, zval *offset, zval
382
389
383
390
zend_weakmap * wm = zend_weakmap_from (object );
384
391
zend_object * obj_addr = Z_OBJ_P (offset );
392
+ zend_ulong obj_key = zend_object_ptr_to_weakref_key (obj_addr );
385
393
Z_TRY_ADDREF_P (value );
386
394
387
- zval * zv = zend_hash_index_find (& wm -> ht , ( zend_ulong ) obj_addr );
395
+ zval * zv = zend_hash_index_find (& wm -> ht , obj_key );
388
396
if (zv ) {
389
397
/* Because the destructors can have side effects such as resizing or rehashing the WeakMap storage,
390
398
* free the zval only after overwriting the original value. */
@@ -396,7 +404,7 @@ static void zend_weakmap_write_dimension(zend_object *object, zval *offset, zval
396
404
}
397
405
398
406
zend_weakref_register (obj_addr , ZEND_WEAKREF_ENCODE (& wm -> ht , ZEND_WEAKREF_TAG_MAP ));
399
- zend_hash_index_add_new (& wm -> ht , ( zend_ulong ) obj_addr , value );
407
+ zend_hash_index_add_new (& wm -> ht , obj_key , value );
400
408
}
401
409
402
410
/* int return and check_empty due to Object Handler API */
@@ -408,7 +416,7 @@ static int zend_weakmap_has_dimension(zend_object *object, zval *offset, int che
408
416
}
409
417
410
418
zend_weakmap * wm = zend_weakmap_from (object );
411
- zval * zv = zend_hash_index_find (& wm -> ht , ( zend_ulong ) Z_OBJ_P (offset ));
419
+ zval * zv = zend_hash_index_find (& wm -> ht , zend_object_ptr_to_weakref_key ( Z_OBJ_P (offset ) ));
412
420
if (!zv ) {
413
421
return 0 ;
414
422
}
@@ -428,7 +436,7 @@ static void zend_weakmap_unset_dimension(zend_object *object, zval *offset)
428
436
429
437
zend_weakmap * wm = zend_weakmap_from (object );
430
438
zend_object * obj_addr = Z_OBJ_P (offset );
431
- if (!zend_hash_index_exists (& wm -> ht , ( zend_ulong ) Z_OBJ_P ( offset ))) {
439
+ if (!zend_hash_index_exists (& wm -> ht , zend_object_ptr_to_weakref_key ( obj_addr ))) {
432
440
/* Object not in WeakMap, do nothing. */
433
441
return ;
434
442
}
@@ -454,10 +462,10 @@ static HashTable *zend_weakmap_get_properties_for(zend_object *object, zend_prop
454
462
ALLOC_HASHTABLE (ht );
455
463
zend_hash_init (ht , zend_hash_num_elements (& wm -> ht ), NULL , ZVAL_PTR_DTOR , 0 );
456
464
457
- zend_ulong obj_addr ;
465
+ zend_ulong obj_key ;
458
466
zval * val ;
459
- ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL (& wm -> ht , obj_addr , val ) {
460
- zend_object * obj = ( zend_object * ) obj_addr ;
467
+ ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL (& wm -> ht , obj_key , val ) {
468
+ zend_object * obj = zend_weakref_key_to_zend_object_ptr ( obj_key ) ;
461
469
zval pair ;
462
470
array_init (& pair );
463
471
@@ -491,11 +499,11 @@ static zend_object *zend_weakmap_clone_obj(zend_object *old_object)
491
499
zend_weakmap * new_wm = zend_weakmap_from (new_object );
492
500
zend_hash_copy (& new_wm -> ht , & old_wm -> ht , NULL );
493
501
494
- zend_ulong obj_addr ;
502
+ zend_ulong obj_key ;
495
503
zval * val ;
496
- ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL (& new_wm -> ht , obj_addr , val ) {
504
+ ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL (& new_wm -> ht , obj_key , val ) {
497
505
zend_weakref_register (
498
- ( zend_object * ) obj_addr , ZEND_WEAKREF_ENCODE (new_wm , ZEND_WEAKREF_TAG_MAP ));
506
+ zend_weakref_key_to_zend_object_ptr ( obj_key ) , ZEND_WEAKREF_ENCODE (new_wm , ZEND_WEAKREF_TAG_MAP ));
499
507
zval_add_ref (val );
500
508
} ZEND_HASH_FOREACH_END ();
501
509
return new_object ;
@@ -542,7 +550,7 @@ static void zend_weakmap_iterator_get_current_key(zend_object_iterator *obj_iter
542
550
ZEND_ASSERT (0 && "Must have integer key" );
543
551
}
544
552
545
- ZVAL_OBJ_COPY (key , ( zend_object * ) num_key );
553
+ ZVAL_OBJ_COPY (key , zend_weakref_key_to_zend_object_ptr ( num_key ) );
546
554
}
547
555
548
556
static void zend_weakmap_iterator_move_forward (zend_object_iterator * obj_iter )
0 commit comments