1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

zend_weakrefs: Remove layer of indirection in zend_weakrefs_hash_clean() (#19580)

* zend_weakrefs: Remove layer of indirection in `zend_weakrefs_hash_clean()`

Following php/php-src#16439.

* zend_weakrefs: Include `zend_weakmap_free_obj()` optimization in `zend_weakrefs_hash_clean()`
This commit is contained in:
Tim Düsterhus
2025-08-26 16:52:29 +02:00
committed by GitHub
parent b7d66189cb
commit e18ef6caea

View File

@@ -138,8 +138,8 @@ static void zend_weakref_unregister(zend_object *object, void *payload, bool wea
if (weakref_free) {
zend_weakref_unref_single(ptr, tag, object);
} else {
/* The optimization of skipping unref is only used in the destructor of WeakMap */
ZEND_ASSERT(ZEND_WEAKREF_GET_TAG(payload) == ZEND_WEAKREF_TAG_MAP);
/* The optimization of skipping unref is used for zend_weakrefs_hash_clean_ex() */
ZEND_ASSERT(ZEND_WEAKREF_GET_TAG(payload) == ZEND_WEAKREF_TAG_MAP || ZEND_WEAKREF_GET_TAG(payload) == ZEND_WEAKREF_TAG_BARE_HT);
}
return;
}
@@ -163,8 +163,8 @@ static void zend_weakref_unregister(zend_object *object, void *payload, bool wea
zend_weakref_unref_single(
ZEND_WEAKREF_GET_PTR(payload), ZEND_WEAKREF_GET_TAG(payload), object);
} else {
/* The optimization of skipping unref is only used in the destructor of WeakMap */
ZEND_ASSERT(ZEND_WEAKREF_GET_TAG(payload) == ZEND_WEAKREF_TAG_MAP);
/* The optimization of skipping unref is used for zend_weakrefs_hash_clean_ex() */
ZEND_ASSERT(ZEND_WEAKREF_GET_TAG(payload) == ZEND_WEAKREF_TAG_MAP || ZEND_WEAKREF_GET_TAG(payload) == ZEND_WEAKREF_TAG_BARE_HT);
}
}
@@ -187,11 +187,20 @@ ZEND_API zend_result zend_weakrefs_hash_del(HashTable *ht, zend_object *key) {
return FAILURE;
}
ZEND_API void zend_weakrefs_hash_clean(HashTable *ht) {
static void zend_weakrefs_hash_clean_ex(HashTable *ht, int type) {
zend_ulong obj_key;
ZEND_HASH_FOREACH_NUM_KEY(ht, obj_key) {
zend_weakrefs_hash_del(ht, zend_weakref_key_to_object(obj_key));
ZEND_HASH_MAP_FOREACH_NUM_KEY(ht, obj_key) {
/* Optimization: Don't call zend_weakref_unref_single to free individual entries from ht when unregistering (which would do a hash table lookup, call zend_hash_index_del, and skip over any bucket collisions).
* Let freeing the corresponding values for WeakMap entries be done in zend_hash_clean, freeing objects sequentially.
* The performance difference is notable for larger WeakMaps with worse cache locality. */
zend_weakref_unregister(
zend_weakref_key_to_object(obj_key), ZEND_WEAKREF_ENCODE(ht, type), 0);
} ZEND_HASH_FOREACH_END();
zend_hash_clean(ht);
}
ZEND_API void zend_weakrefs_hash_clean(HashTable *ht) {
zend_weakrefs_hash_clean_ex(ht, ZEND_WEAKREF_TAG_BARE_HT);
}
void zend_weakrefs_init(void) {
@@ -340,14 +349,7 @@ static zend_object *zend_weakmap_create_object(zend_class_entry *ce)
static void zend_weakmap_free_obj(zend_object *object)
{
zend_weakmap *wm = zend_weakmap_from(object);
zend_ulong obj_key;
ZEND_HASH_MAP_FOREACH_NUM_KEY(&wm->ht, obj_key) {
/* 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).
* Let freeing the corresponding values for WeakMap entries be done in zend_hash_destroy, freeing objects sequentially.
* The performance difference is notable for larger WeakMaps with worse cache locality. */
zend_weakref_unregister(
zend_weakref_key_to_object(obj_key), ZEND_WEAKREF_ENCODE(&wm->ht, ZEND_WEAKREF_TAG_MAP), 0);
} ZEND_HASH_FOREACH_END();
zend_weakrefs_hash_clean_ex(&wm->ht, ZEND_WEAKREF_TAG_MAP);
zend_hash_destroy(&wm->ht);
zend_object_std_dtor(&wm->std);
}