Implement wasm_externref_objdel and wasm_externref_set_cleanup (#2455)

## Context

Some native libraries may want to explicitly delete an externref object without
waiting for the module instance to be deleted.
In addition, it may want to add a cleanup function.

## Proposed Changes

Implement:
* `wasm_externref_objdel` to explicitly delete an externeref'd object. 
* `wasm_externref_set_cleanup` to set a cleanup function that is called when
  the externref'd object is deleted.
This commit is contained in:
tonibofarull 2023-08-14 10:45:30 +02:00 committed by GitHub
parent 5c6613b2b1
commit 8d1cf46f02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 4 deletions

View File

@ -4681,6 +4681,8 @@ typedef struct ExternRefMapNode {
bool retained; bool retained;
/* Whether it is marked by runtime */ /* Whether it is marked by runtime */
bool marked; bool marked;
/* cleanup function called when the externref is freed */
void (*cleanup)(void *);
} ExternRefMapNode; } ExternRefMapNode;
static uint32 static uint32
@ -4743,6 +4745,81 @@ lookup_extobj_callback(void *key, void *value, void *user_data)
} }
} }
static void
delete_externref(void *key, ExternRefMapNode *node)
{
bh_hash_map_remove(externref_map, key, NULL, NULL);
if (node->cleanup) {
(*node->cleanup)(node->extern_obj);
}
wasm_runtime_free(node);
}
static void
delete_extobj_callback(void *key, void *value, void *user_data)
{
ExternRefMapNode *node = (ExternRefMapNode *)value;
LookupExtObj_UserData *lookup_user_data =
(LookupExtObj_UserData *)user_data;
if (node->extern_obj == lookup_user_data->node.extern_obj
&& node->module_inst == lookup_user_data->node.module_inst) {
lookup_user_data->found = true;
delete_externref(key, node);
}
}
bool
wasm_externref_objdel(WASMModuleInstanceCommon *module_inst, void *extern_obj)
{
LookupExtObj_UserData lookup_user_data = { 0 };
bool ok = false;
/* in a wrapper, extern_obj could be any value */
lookup_user_data.node.extern_obj = extern_obj;
lookup_user_data.node.module_inst = module_inst;
lookup_user_data.found = false;
os_mutex_lock(&externref_lock);
/* Lookup hashmap firstly */
bh_hash_map_traverse(externref_map, delete_extobj_callback,
(void *)&lookup_user_data);
if (lookup_user_data.found) {
ok = true;
}
os_mutex_unlock(&externref_lock);
return ok;
}
bool
wasm_externref_set_cleanup(WASMModuleInstanceCommon *module_inst,
void *extern_obj, void (*extern_obj_cleanup)(void *))
{
LookupExtObj_UserData lookup_user_data = { 0 };
bool ok = false;
/* in a wrapper, extern_obj could be any value */
lookup_user_data.node.extern_obj = extern_obj;
lookup_user_data.node.module_inst = module_inst;
lookup_user_data.found = false;
os_mutex_lock(&externref_lock);
/* Lookup hashmap firstly */
bh_hash_map_traverse(externref_map, lookup_extobj_callback,
(void *)&lookup_user_data);
if (lookup_user_data.found) {
void *key = (void *)(uintptr_t)lookup_user_data.externref_idx;
ExternRefMapNode *node = bh_hash_map_find(externref_map, key);
node->cleanup = extern_obj_cleanup;
ok = true;
}
os_mutex_unlock(&externref_lock);
return ok;
}
bool bool
wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj, wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj,
uint32 *p_externref_idx) uint32 *p_externref_idx)
@ -4792,6 +4869,7 @@ wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj,
memset(node, 0, sizeof(ExternRefMapNode)); memset(node, 0, sizeof(ExternRefMapNode));
node->extern_obj = extern_obj; node->extern_obj = extern_obj;
node->module_inst = module_inst; node->module_inst = module_inst;
node->cleanup = NULL;
externref_idx = externref_global_id; externref_idx = externref_global_id;
@ -4842,8 +4920,7 @@ reclaim_extobj_callback(void *key, void *value, void *user_data)
if (node->module_inst == module_inst) { if (node->module_inst == module_inst) {
if (!node->marked && !node->retained) { if (!node->marked && !node->retained) {
bh_hash_map_remove(externref_map, key, NULL, NULL); delete_externref(key, node);
wasm_runtime_free(value);
} }
else { else {
node->marked = false; node->marked = false;
@ -4958,8 +5035,7 @@ cleanup_extobj_callback(void *key, void *value, void *user_data)
(WASMModuleInstanceCommon *)user_data; (WASMModuleInstanceCommon *)user_data;
if (node->module_inst == module_inst) { if (node->module_inst == module_inst) {
bh_hash_map_remove(externref_map, key, NULL, NULL); delete_externref(key, node);
wasm_runtime_free(value);
} }
} }

View File

@ -1292,6 +1292,32 @@ WASM_RUNTIME_API_EXTERN bool
wasm_externref_obj2ref(wasm_module_inst_t module_inst, wasm_externref_obj2ref(wasm_module_inst_t module_inst,
void *extern_obj, uint32_t *p_externref_idx); void *extern_obj, uint32_t *p_externref_idx);
/**
* Delete external object registered by `wasm_externref_obj2ref`.
*
* @param module_inst the WASM module instance that the extern object
* belongs to
* @param extern_obj the external object to be deleted
*
* @return true if success, false otherwise
*/
WASM_RUNTIME_API_EXTERN bool
wasm_externref_objdel(wasm_module_inst_t module_inst, void *extern_obj);
/**
* Set cleanup callback to release external object.
*
* @param module_inst the WASM module instance that the extern object
* belongs to
* @param extern_obj the external object to which to set the `extern_obj_cleanup` cleanup callback.
* @param extern_obj_cleanup a callback to release `extern_obj`
*
* @return true if success, false otherwise
*/
WASM_RUNTIME_API_EXTERN bool
wasm_externref_set_cleanup(wasm_module_inst_t module_inst, void *extern_obj,
void (*extern_obj_cleanup)(void *));
/** /**
* Retrieve the external object from an internal externref index * Retrieve the external object from an internal externref index
* *