Skip to content

Commit

Permalink
Add ZEND_API for weakmap functionality via zend_weakrefs_hash_add/del
Browse files Browse the repository at this point in the history
Closes GH-7600.
  • Loading branch information
bwoebi committed Oct 21, 2021
1 parent decf906 commit 471102e
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 6 deletions.
26 changes: 21 additions & 5 deletions Zend/zend_weakrefs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions Zend/zend_weakrefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
42 changes: 42 additions & 0 deletions ext/zend_test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -622,11 +658,17 @@ 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_ulong objptr;
ZEND_HASH_FOREACH_NUM_KEY(&ZT_G(global_weakmap), objptr) {
zend_weakrefs_hash_del(&ZT_G(global_weakmap), (zend_object *)(uintptr_t)objptr);
} ZEND_HASH_FOREACH_END();
zend_hash_destroy(&ZT_G(global_weakmap));
return SUCCESS;
}

Expand Down
4 changes: 4 additions & 0 deletions ext/zend_test/test.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
19 changes: 18 additions & 1 deletion ext/zend_test/test_arginfo.h
Original file line number Diff line number Diff line change
@@ -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()
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -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);
Expand All @@ -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
};
Expand Down
54 changes: 54 additions & 0 deletions ext/zend_test/tests/zend_weakmap.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
--TEST--
Test internal weakmap API
--SKIPIF--
<?php if (!extension_loaded('zend-test')) die('skip: zend-test extension required'); ?>
--FILE--
<?php

$id1 = new \stdClass;
$id2 = new \stdClass;

var_dump(zend_weakmap_attach($id1, 1));
var_dump(zend_weakmap_attach($id1, 3));
var_dump(zend_weakmap_attach($id2, 2));

var_dump(zend_weakmap_dump());

unset($id1);

var_dump(zend_weakmap_dump());

var_dump(zend_weakmap_remove($id2));
var_dump(zend_weakmap_remove($id2));

var_dump(zend_weakmap_dump());

var_dump(zend_weakmap_attach($id2, $id2));

var_dump(zend_weakmap_dump());

?>
--EXPECTF--
bool(true)
bool(false)
bool(true)
array(2) {
[%d]=>
int(1)
[%d]=>
int(2)
}
array(1) {
[%d]=>
int(2)
}
bool(true)
bool(false)
array(0) {
}
bool(true)
array(1) {
[%d]=>
object(stdClass)#2 (0) {
}
}

0 comments on commit 471102e

Please sign in to comment.