diff --git a/Zend/zend_weakrefs.c b/Zend/zend_weakrefs.c index 04c50432103cf..8efa4130054f7 100644 --- a/Zend/zend_weakrefs.c +++ b/Zend/zend_weakrefs.c @@ -63,8 +63,7 @@ static inline void zend_weakref_unref_single( wr->referent = NULL; } else { ZEND_ASSERT(tag == ZEND_WEAKREF_TAG_MAP); - zend_weakmap *wm = ptr; - zend_hash_index_del(&wm->ht, obj_addr); + zend_hash_index_del((HashTable *) ptr, obj_addr); } } @@ -144,6 +143,23 @@ static void zend_weakref_unregister(zend_object *object, void *payload) { ZEND_WEAKREF_GET_PTR(payload), ZEND_WEAKREF_GET_TAG(payload), obj_addr); } +ZEND_API zval *zend_weakrefs_hash_add(HashTable *ht, zend_object *key, zval *pData) { + zval *zv = zend_hash_index_add(ht, (zend_ulong) key, pData); + if (zv) { + zend_weakref_register(key, ZEND_WEAKREF_ENCODE(ht, ZEND_WEAKREF_TAG_MAP)); + } + return zv; +} + +ZEND_API zend_result zend_weakrefs_hash_del(HashTable *ht, zend_object *key) { + zval *zv = zend_hash_index_find(ht, (zend_ulong) key); + if (zv) { + zend_weakref_unregister(key, ZEND_WEAKREF_ENCODE(ht, ZEND_WEAKREF_TAG_MAP)); + return SUCCESS; + } + return FAILURE; +} + void zend_weakrefs_init(void) { zend_hash_init(&EG(weakrefs), 8, NULL, NULL, 0); } @@ -281,7 +297,7 @@ static void zend_weakmap_free_obj(zend_object *object) zend_ulong obj_addr; ZEND_HASH_FOREACH_NUM_KEY(&wm->ht, obj_addr) { zend_weakref_unregister( - (zend_object *) obj_addr, ZEND_WEAKREF_ENCODE(wm, ZEND_WEAKREF_TAG_MAP)); + (zend_object *) obj_addr, ZEND_WEAKREF_ENCODE(&wm->ht, ZEND_WEAKREF_TAG_MAP)); } ZEND_HASH_FOREACH_END(); zend_hash_destroy(&wm->ht); zend_object_std_dtor(&wm->std); @@ -340,7 +356,7 @@ static void zend_weakmap_write_dimension(zend_object *object, zval *offset, zval return; } - zend_weakref_register(obj_key, ZEND_WEAKREF_ENCODE(wm, ZEND_WEAKREF_TAG_MAP)); + zend_weakref_register(obj_key, ZEND_WEAKREF_ENCODE(&wm->ht, ZEND_WEAKREF_TAG_MAP)); zend_hash_index_add_new(&wm->ht, (zend_ulong) obj_key, value); } @@ -378,7 +394,7 @@ static void zend_weakmap_unset_dimension(zend_object *object, zval *offset) return; } - zend_weakref_unregister(obj_key, ZEND_WEAKREF_ENCODE(wm, ZEND_WEAKREF_TAG_MAP)); + zend_weakref_unregister(obj_key, ZEND_WEAKREF_ENCODE(&wm->ht, ZEND_WEAKREF_TAG_MAP)); } static int zend_weakmap_count_elements(zend_object *object, zend_long *count) diff --git a/Zend/zend_weakrefs.h b/Zend/zend_weakrefs.h index 2cce74524fad0..3c391b02158f9 100644 --- a/Zend/zend_weakrefs.h +++ b/Zend/zend_weakrefs.h @@ -28,6 +28,18 @@ void zend_weakrefs_shutdown(void); ZEND_API void zend_weakrefs_notify(zend_object *object); +ZEND_API zval *zend_weakrefs_hash_add(HashTable *ht, zend_object *key, zval *pData); +ZEND_API zend_result zend_weakrefs_hash_del(HashTable *ht, zend_object *key); +static zend_always_inline void *zend_weakrefs_hash_add_ptr(HashTable *ht, zend_object *key, void *ptr) { + zval tmp, *zv; + ZVAL_PTR(&tmp, ptr); + if ((zv = zend_weakrefs_hash_add(ht, key, &tmp))) { + return Z_PTR_P(zv); + } else { + return NULL; + } +} + END_EXTERN_C() #endif diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 64c0cb2df258e..4bddcbddb2ee2 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -27,6 +27,7 @@ #include "zend_attributes.h" #include "zend_observer.h" #include "zend_smart_str.h" +#include "zend_weakrefs.h" ZEND_BEGIN_MODULE_GLOBALS(zend_test) int observer_enabled; @@ -41,6 +42,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test) int observer_show_opcode; int observer_nesting_depth; int replace_zend_execute_ex; + HashTable global_weakmap; ZEND_END_MODULE_GLOBALS(zend_test) ZEND_DECLARE_MODULE_GLOBALS(zend_test) @@ -225,6 +227,40 @@ static ZEND_FUNCTION(zend_string_or_stdclass_or_null) } /* }}} */ +static ZEND_FUNCTION(zend_weakmap_attach) +{ + zval *value; + zend_object *obj; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_OBJ(obj) + Z_PARAM_ZVAL(value) + ZEND_PARSE_PARAMETERS_END(); + + if (zend_weakrefs_hash_add(&ZT_G(global_weakmap), obj, value)) { + Z_TRY_ADDREF_P(value); + RETURN_TRUE; + } + RETURN_FALSE; +} + +static ZEND_FUNCTION(zend_weakmap_remove) +{ + zend_object *obj; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ(obj) + ZEND_PARSE_PARAMETERS_END(); + + RETURN_BOOL(zend_weakrefs_hash_del(&ZT_G(global_weakmap), obj) == SUCCESS); +} + +static ZEND_FUNCTION(zend_weakmap_dump) +{ + ZEND_PARSE_PARAMETERS_NONE(); + RETURN_ARR(zend_array_dup(&ZT_G(global_weakmap))); +} + /* TESTS Z_PARAM_ITERABLE and Z_PARAM_ITERABLE_OR_NULL */ static ZEND_FUNCTION(zend_iterable) { @@ -622,11 +658,13 @@ static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execu PHP_RINIT_FUNCTION(zend_test) { + zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0); return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(zend_test) { + zend_hash_destroy(&ZT_G(global_weakmap)); return SUCCESS; } diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index d9db786cee048..d73d37be051e1 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -59,6 +59,10 @@ function zend_string_or_stdclass_or_null($param): stdClass|string|null {} function zend_iterable(iterable $arg1, ?iterable $arg2 = null): void {} +function zend_weakmap_attach(object $object, mixed $value): bool {} +function zend_weakmap_remove(object $object): bool {} +function zend_weakmap_dump(): array {} + } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index c58d53b4570d6..8641040957269 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3240b7fa3461b40a211371250c4975802f44185b */ + * Stub hash: 49b9abbc5ce826e749861fd511e98f1add001368 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -51,6 +51,17 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_iterable, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg2, IS_ITERABLE, 1, "null") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_weakmap_attach, 0, 2, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_weakmap_remove, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) +ZEND_END_ARG_INFO() + +#define arginfo_zend_weakmap_dump arginfo_zend_test_array_return + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_ZendSubNS_namespaced_func, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() @@ -83,6 +94,9 @@ static ZEND_FUNCTION(zend_string_or_object_or_null); static ZEND_FUNCTION(zend_string_or_stdclass); static ZEND_FUNCTION(zend_string_or_stdclass_or_null); static ZEND_FUNCTION(zend_iterable); +static ZEND_FUNCTION(zend_weakmap_attach); +static ZEND_FUNCTION(zend_weakmap_remove); +static ZEND_FUNCTION(zend_weakmap_dump); static ZEND_FUNCTION(namespaced_func); static ZEND_METHOD(_ZendTestClass, is_object); static ZEND_METHOD(_ZendTestClass, __toString); @@ -106,6 +120,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_string_or_stdclass, arginfo_zend_string_or_stdclass) ZEND_FE(zend_string_or_stdclass_or_null, arginfo_zend_string_or_stdclass_or_null) ZEND_FE(zend_iterable, arginfo_zend_iterable) + ZEND_FE(zend_weakmap_attach, arginfo_zend_weakmap_attach) + ZEND_FE(zend_weakmap_remove, arginfo_zend_weakmap_remove) + ZEND_FE(zend_weakmap_dump, arginfo_zend_weakmap_dump) ZEND_NS_FE("ZendTestNS2\\ZendSubNS", namespaced_func, arginfo_ZendTestNS2_ZendSubNS_namespaced_func) ZEND_FE_END }; diff --git a/ext/zend_test/tests/zend_weakmap.phpt b/ext/zend_test/tests/zend_weakmap.phpt new file mode 100644 index 0000000000000..4c5954a55aa37 --- /dev/null +++ b/ext/zend_test/tests/zend_weakmap.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test internal weakmap API +--FILE-- + +--EXPECTF-- +bool(true) +bool(false) +bool(true) +array(2) { + [%d]=> + int(1) + [%d]=> + int(2) +} +bool(true) +bool(false) +array(1) { + [%d]=> + int(1) +} \ No newline at end of file