diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index a39613a3..b1866215 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -4681,6 +4681,8 @@ typedef struct ExternRefMapNode { bool retained; /* Whether it is marked by runtime */ bool marked; + /* cleanup function called when the externref is freed */ + void (*cleanup)(void *); } ExternRefMapNode; 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 wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj, uint32 *p_externref_idx) @@ -4792,6 +4869,7 @@ wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj, memset(node, 0, sizeof(ExternRefMapNode)); node->extern_obj = extern_obj; node->module_inst = module_inst; + node->cleanup = NULL; 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->marked && !node->retained) { - bh_hash_map_remove(externref_map, key, NULL, NULL); - wasm_runtime_free(value); + delete_externref(key, node); } else { node->marked = false; @@ -4958,8 +5035,7 @@ cleanup_extobj_callback(void *key, void *value, void *user_data) (WASMModuleInstanceCommon *)user_data; if (node->module_inst == module_inst) { - bh_hash_map_remove(externref_map, key, NULL, NULL); - wasm_runtime_free(value); + delete_externref(key, node); } } diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 46bd3782..18e15782 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -1292,6 +1292,32 @@ WASM_RUNTIME_API_EXTERN bool wasm_externref_obj2ref(wasm_module_inst_t module_inst, 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 *