Import reference-types feature (#612)

Implement spec reference-types proposal for interpreter, AOT and JIT, update documents and add sample. And upgrade AOT_CURRENT_VERSION to 3 as AOT file format and AOT module instance layout are changed.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang
2021-04-15 11:29:20 +08:00
committed by GitHub
parent 7706e4b151
commit 03d45f1d62
48 changed files with 5557 additions and 856 deletions

View File

@ -49,6 +49,16 @@ static void
wasm_runtime_destroy_registered_module_list();
#endif /* WASM_ENABLE_MULTI_MODULE */
#if WASM_ENABLE_REF_TYPES != 0
/* Initialize externref hashmap */
static bool
wasm_externref_map_init();
/* Destroy externref hashmap */
static void
wasm_externref_map_destroy();
#endif /* WASM_ENABLE_REF_TYPES */
static void
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
{
@ -119,10 +129,20 @@ wasm_runtime_env_init()
#endif
#endif
#if WASM_ENABLE_REF_TYPES != 0
if (!wasm_externref_map_init()) {
goto fail7;
}
#endif
return true;
#if WASM_ENABLE_REF_TYPES != 0
fail7:
#endif
#if WASM_ENABLE_AOT != 0
#ifdef OS_ENABLE_HW_BOUND_CHECK
aot_signal_destroy();
fail6:
#endif
#endif
@ -175,6 +195,10 @@ wasm_runtime_init()
void
wasm_runtime_destroy()
{
#if WASM_ENABLE_REF_TYPES != 0
wasm_externref_map_destroy();
#endif
#if WASM_ENABLE_AOT != 0
#ifdef OS_ENABLE_HW_BOUND_CHECK
aot_signal_destroy();
@ -997,10 +1021,35 @@ wasm_runtime_get_user_data(WASMExecEnv *exec_env)
return exec_env->user_data;
}
WASMType *
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
uint32 module_type)
{
WASMType *type = NULL;
#if WASM_ENABLE_INTERP != 0
if (module_type == Wasm_Module_Bytecode) {
WASMFunctionInstance *wasm_func = (WASMFunctionInstance *)function;
type = wasm_func->is_import_func
? wasm_func->u.func_import->func_type
: wasm_func->u.func->func_type;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_type == Wasm_Module_AoT) {
AOTFunctionInstance *aot_func = (AOTFunctionInstance *)function;
type = aot_func->is_import_func
? aot_func->u.func_import->func_type
: aot_func->u.func.func_type;
}
#endif
return type;
}
WASMFunctionInstanceCommon *
wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst,
const char *name,
const char *signature)
const char *name, const char *signature)
{
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode)
@ -1017,11 +1066,57 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst,
return NULL;
}
#if WASM_ENABLE_REF_TYPES != 0
static void
wasm_runtime_reclaim_externref(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
uint32 *argv)
{
uint32 i = 0, cell_num = 0;
WASMType *func_type = wasm_runtime_get_function_type(
function, exec_env->module_inst->module_type);
bh_assert(func_type);
while (i < func_type->result_count) {
uint8 result_type = func_type->types[func_type->param_count + i];
if (result_type == VALUE_TYPE_EXTERNREF && argv[i] != NULL_REF) {
/* Retain the externref returned to runtime embedder */
(void)wasm_externref_retain(argv[i]);
}
cell_num += wasm_value_type_cell_num(result_type);
i++;
}
wasm_externref_reclaim(exec_env->module_inst);
}
void
wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function)
{
exec_env->nested_calling_depth++;
}
void
wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
bool ret, uint32 *argv)
{
exec_env->nested_calling_depth--;
if (!exec_env->nested_calling_depth && ret) {
wasm_runtime_reclaim_externref(exec_env, function, argv);
}
}
#endif
bool
wasm_runtime_call_wasm(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
uint32 argc, uint32 argv[])
{
bool ret = false;
if (!wasm_runtime_exec_env_check(exec_env)) {
LOG_ERROR("Invalid exec env stack info.");
return false;
@ -1030,19 +1125,28 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
/* set thread handle and stack boundary */
wasm_exec_env_set_thread_info(exec_env);
#if WASM_ENABLE_REF_TYPES != 0
wasm_runtime_prepare_call_function(exec_env, function);
#endif
#if WASM_ENABLE_INTERP != 0
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode)
return wasm_call_function(exec_env,
ret = wasm_call_function(exec_env,
(WASMFunctionInstance*)function,
argc, argv);
#endif
#if WASM_ENABLE_AOT != 0
if (exec_env->module_inst->module_type == Wasm_Module_AoT)
return aot_call_function(exec_env,
ret = aot_call_function(exec_env,
(AOTFunctionInstance*)function,
argc, argv);
#endif
return false;
#if WASM_ENABLE_REF_TYPES != 0
wasm_runtime_finalize_call_function(exec_env, function, ret, argv);
#endif
return ret;
}
static uint32
@ -1142,32 +1246,21 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env,
uint32 num_results, wasm_val_t results[],
uint32 num_args, wasm_val_t args[])
{
uint32 argc, *argv, ret_num, cell_num, total_size;
uint32 argc, *argv, ret_num, cell_num, total_size, module_type;
WASMType *type;
bool ret = false;
WASMType *type = NULL;
#if WASM_ENABLE_INTERP != 0
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) {
WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function;
type = wasm_func->u.func->func_type;
argc = wasm_func->param_cell_num;
cell_num = argc > wasm_func->ret_cell_num ?
argc : wasm_func->ret_cell_num;
}
#endif
#if WASM_ENABLE_AOT != 0
if (exec_env->module_inst->module_type == Wasm_Module_AoT) {
type = ((AOTFunctionInstance*)function)->u.func.func_type;
argc = type->param_cell_num;
cell_num = argc > type->ret_cell_num ?
argc : type->ret_cell_num;
}
#endif
module_type = exec_env->module_inst->module_type;
type = wasm_runtime_get_function_type(function, module_type);
if (!type) {
LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one.");
goto fail1;
}
argc = type->param_cell_num;
cell_num = (argc > type->ret_cell_num) ? argc : type->ret_cell_num;
if (num_results != type->result_count) {
LOG_ERROR("The result value number does not match the function declaration.");
goto fail1;
@ -1207,27 +1300,21 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env,
wasm_val_t *args = NULL;
WASMType *type = NULL;
bool ret = false;
uint32 i = 0;
uint32 i = 0, module_type;
va_list vargs;
#if WASM_ENABLE_INTERP != 0
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) {
WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function;
type = wasm_func->u.func->func_type;
}
#endif
#if WASM_ENABLE_AOT != 0
if (exec_env->module_inst->module_type == Wasm_Module_AoT) {
type = ((AOTFunctionInstance*)function)->u.func.func_type;
}
#endif
module_type = exec_env->module_inst->module_type;
type = wasm_runtime_get_function_type(function, module_type);
if (!type) {
LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one.");
LOG_ERROR("Function type get failed, WAMR Interpreter and AOT "
"must be enabled at least one.");
goto fail1;
}
if (num_args != type->param_count) {
LOG_ERROR("The argument value number does not match the function declaration.");
LOG_ERROR("The argument value number does not match the "
"function declaration.");
goto fail1;
}
if (!(args = runtime_malloc(sizeof(wasm_val_t) * num_args, NULL, NULL, 0))) {
@ -1260,7 +1347,8 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env,
}
}
va_end(vargs);
ret = wasm_runtime_call_wasm_a(exec_env, function, num_results, results, num_args, args);
ret = wasm_runtime_call_wasm_a(exec_env, function, num_results, results,
num_args, args);
wasm_runtime_free(args);
fail1:
@ -1272,21 +1360,21 @@ wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst
WASMFunctionInstanceCommon *function,
uint32 argc, uint32 argv[])
{
bool ret = false;
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode)
return wasm_create_exec_env_and_call_function(
(WASMModuleInstance*)module_inst,
(WASMFunctionInstance*)function,
argc, argv);
ret = wasm_create_exec_env_and_call_function(
(WASMModuleInstance *)module_inst, (WASMFunctionInstance *)function,
argc, argv);
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT)
return aot_create_exec_env_and_call_function(
(AOTModuleInstance*)module_inst,
(AOTFunctionInstance*)function,
argc, argv);
ret = aot_create_exec_env_and_call_function(
(AOTModuleInstance *)module_inst, (AOTFunctionInstance *)function,
argc, argv);
#endif
return false;
return ret;
}
void
@ -2192,8 +2280,8 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
uint32 argv_buf_offset = 0;
int32 i;
char *argv_buf, *p, *p_end;
uint32 *argv_offsets;
bool ret;
uint32 *argv_offsets, module_type;
bool ret, is_import_func = true;
#if WASM_ENABLE_LIBC_WASI != 0
if (wasm_runtime_is_wasi_mode(module_inst)) {
@ -2219,19 +2307,24 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
if (((WASMFunctionInstance*)func)->is_import_func) {
wasm_runtime_set_exception(module_inst,
"lookup main function failed");
return false;
}
func_type = ((WASMFunctionInstance*)func)->u.func->func_type;
is_import_func = ((WASMFunctionInstance*)func)->is_import_func;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT)
func_type = ((AOTFunctionInstance*)func)->u.func.func_type;
if (module_inst->module_type == Wasm_Module_AoT) {
is_import_func = ((AOTFunctionInstance*)func)->is_import_func;
}
#endif
if (is_import_func) {
wasm_runtime_set_exception(module_inst,
"lookup main function failed");
return false;
}
module_type = module_inst->module_type;
func_type = wasm_runtime_get_function_type(func, module_type);
if (!func_type) {
LOG_ERROR("invalid module instance type");
return false;
@ -2462,7 +2555,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
WASMFunctionInstanceCommon *func;
WASMType *type = NULL;
uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0;
int32 i, p;
int32 i, p, module_type;
uint64 total_size;
const char *exception;
char buf[128];
@ -2489,22 +2582,12 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
wasm_runtime_set_exception(module_inst, buf);
goto fail;
}
type = wasm_func->is_import_func ? wasm_func->u.func_import->func_type
: wasm_func->u.func->func_type;
argc1 = wasm_func->param_cell_num;
cell_num = argc1 > wasm_func->ret_cell_num ?
argc1 : wasm_func->ret_cell_num;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
type = ((AOTFunctionInstance*)func)->u.func.func_type;
argc1 = type->param_cell_num;
cell_num = argc1 > type->ret_cell_num ?
argc1 : type->ret_cell_num;
}
#endif
module_type = module_inst->module_type;
type = wasm_runtime_get_function_type(func, module_type);
if (!type) {
LOG_ERROR("invalid module instance type");
return false;
@ -2516,6 +2599,9 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
goto fail;
}
argc1 = type->param_cell_num;
cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num;
total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2);
if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst,
NULL, 0)))) {
@ -2619,6 +2705,38 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
break;
}
#endif /* WASM_ENABLE_SIMD != 0 */
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
{
if (strncasecmp(argv[i], "null", 4) == 0) {
argv1[p++] = NULL_REF;
}
else {
argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0);
}
break;
}
case VALUE_TYPE_EXTERNREF:
{
if (strncasecmp(argv[i], "null", 4) == 0) {
argv1[p++] = NULL_REF;
}
else {
uint64 val = strtoull(argv[i], &endptr, 0);
void *extern_obj = (void *)(uintptr_t)val;
uint32 externref_idx;
if (!wasm_externref_obj2ref(module_inst, extern_obj,
&externref_idx)) {
wasm_runtime_set_exception(
module_inst, "map extern object to ref failed");
goto fail;
}
argv1[p++] = externref_idx;
}
break;
}
#endif /* WASM_ENABLE_REF_TYPES */
default:
bh_assert(0);
break;
@ -2666,9 +2784,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
break;
}
case VALUE_TYPE_F32:
{
os_printf("%.7g:f32", *(float32*)(argv1 + k));
k++;
break;
}
case VALUE_TYPE_F64:
{
union { float64 val; uint32 parts[2]; } u;
@ -2678,6 +2798,31 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
os_printf("%.7g:f64", u.val);
break;
}
#if WASM_ENABLE_REF_TYPES
case VALUE_TYPE_FUNCREF:
{
if (argv1[k] != NULL_REF)
os_printf("%u:ref.func", argv1[k]);
else
os_printf("func:ref.null");
k++;
break;
}
case VALUE_TYPE_EXTERNREF:
{
if (argv1[k] != NULL_REF) {
void *extern_obj = NULL;
bool ret = wasm_externref_ref2obj(argv1[k], &extern_obj);
bh_assert(ret);
(void)ret;
os_printf("%p:ref.extern", extern_obj);
}
else
os_printf("extern:ref.null");
k++;
break;
}
#endif
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
{
@ -2802,6 +2947,12 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
case VALUE_TYPE_F32:
*(float32*)argv_dst = *(float32*)argv_src++;
break;
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
*(uint32*)argv_dst = *argv_src++;
break;
#endif
default:
bh_assert(0);
break;
@ -2815,6 +2966,10 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
if (func_type->result_count > 0) {
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret[0] = *(uint32*)argv1;
break;
case VALUE_TYPE_F32:
@ -2899,6 +3054,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
for (i = 0; i < func_type->param_count; i++) {
switch (func_type->types[i]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
if (n_ints < MAX_REG_INTS)
n_ints++;
else
@ -3067,6 +3226,17 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
stacks[n_stacks++] = arg_i32;
break;
}
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
{
if (n_ints < MAX_REG_INTS)
ints[n_ints++] = *argv_src++;
else
stacks[n_stacks++] = *argv_src++;
break;
}
#endif
case VALUE_TYPE_I64:
{
if (n_ints < MAX_REG_INTS - 1) {
@ -3204,6 +3374,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
else {
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks);
break;
case VALUE_TYPE_I64:
@ -3341,6 +3515,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
argv1[j++] = *argv++;
break;
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv1[j++] = *argv++;
break;
default:
@ -3360,6 +3538,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
else {
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, argc1);
break;
case VALUE_TYPE_I64:
@ -3582,6 +3764,15 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
}
argv_src += 2;
break;
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
if (n_ints < MAX_REG_INTS)
ints[n_ints++] = *argv_src++;
else
stacks[n_stacks++] = *argv_src++;
break;
#endif
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
if (n_fps < MAX_REG_FLOATS) {
@ -3617,6 +3808,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
/* Invoke the native function and get the first result value */
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks);
break;
case VALUE_TYPE_I64:
@ -3670,11 +3865,11 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env,
#if WASM_ENABLE_INTERP != 0
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode)
return wasm_call_indirect(exec_env, element_indices, argc, argv);
return wasm_call_indirect(exec_env, 0, element_indices, argc, argv);
#endif
#if WASM_ENABLE_AOT != 0
if (exec_env->module_inst->module_type == Wasm_Module_AoT)
return aot_call_indirect(exec_env, element_indices, argc, argv);
return aot_call_indirect(exec_env, 0, element_indices, argc, argv);
#endif
return false;
}
@ -3795,8 +3990,318 @@ wasm_runtime_join_thread(wasm_thread_t tid, void **retval)
return os_thread_join((korp_tid)tid, retval);
}
#endif /* end of WASM_ENABLE_THREAD_MGR */
#if WASM_ENABLE_REF_TYPES != 0
static korp_mutex externref_lock;
static uint32 externref_global_id = 1;
static HashMap *externref_map;
typedef struct ExternRefMapNode {
/* The extern object from runtime embedder */
void *extern_obj;
/* The module instance it belongs to */
WASMModuleInstanceCommon *module_inst;
/* Whether it is retained */
bool retained;
/* Whether it is marked by runtime */
bool marked;
} ExternRefMapNode;
static uint32
wasm_externref_hash(const void *key)
{
uint32 externref_idx = (uint32)(uintptr_t)key;
return externref_idx;
}
static bool
wasm_externref_equal(void *key1, void *key2)
{
uint32 externref_idx1 = (uint32)(uintptr_t)key1;
uint32 externref_idx2 = (uint32)(uintptr_t)key2;
return externref_idx1 == externref_idx2 ? true : false;
}
static bool
wasm_externref_map_init()
{
if (os_mutex_init(&externref_lock) != 0)
return false;
if (!(externref_map = bh_hash_map_create(32, false,
wasm_externref_hash,
wasm_externref_equal,
NULL,
wasm_runtime_free))) {
os_mutex_destroy(&externref_lock);
return false;
}
externref_global_id = 1;
return true;
}
static void
wasm_externref_map_destroy()
{
bh_hash_map_destroy(externref_map);
os_mutex_destroy(&externref_lock);
}
typedef struct LookupExtObj_UserData {
ExternRefMapNode node;
bool found;
uint32 externref_idx;
} LookupExtObj_UserData;
static void
lookup_extobj_callback(void *key, void *value, void *user_data)
{
uint32 externref_idx = (uint32)(uintptr_t)key;
ExternRefMapNode *node = (ExternRefMapNode *)value;
LookupExtObj_UserData *user_data_lookup = (LookupExtObj_UserData *)
user_data;
if (node->extern_obj == user_data_lookup->node.extern_obj
&& node->module_inst == user_data_lookup->node.module_inst) {
user_data_lookup->found = true;
user_data_lookup->externref_idx = externref_idx;
}
}
bool
wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst,
void *extern_obj, uint32 *p_externref_idx)
{
LookupExtObj_UserData lookup_user_data;
ExternRefMapNode *node;
uint32 externref_idx;
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) {
*p_externref_idx = lookup_user_data.externref_idx;
os_mutex_unlock(&externref_lock);
return true;
}
/* Not found in hashmap */
if (externref_global_id == NULL_REF
|| externref_global_id == 0) {
goto fail1;
}
if (!(node = wasm_runtime_malloc(sizeof(ExternRefMapNode)))) {
goto fail1;
}
memset(node, 0, sizeof(ExternRefMapNode));
node->extern_obj = extern_obj;
node->module_inst = module_inst;
externref_idx = externref_global_id;
if (!bh_hash_map_insert(externref_map,
(void*)(uintptr_t)externref_idx,
(void*)node)) {
goto fail2;
}
externref_global_id++;
*p_externref_idx = externref_idx;
os_mutex_unlock(&externref_lock);
return true;
fail2:
wasm_runtime_free(node);
fail1:
os_mutex_unlock(&externref_lock);
return false;
}
bool
wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj)
{
ExternRefMapNode *node;
if (externref_idx == NULL_REF) {
return false;
}
os_mutex_lock(&externref_lock);
node = bh_hash_map_find(externref_map,
(void*)(uintptr_t)externref_idx);
os_mutex_unlock(&externref_lock);
if (!node)
return false;
*p_extern_obj = node->extern_obj;
return true;
}
static void
reclaim_extobj_callback(void *key, void *value, void *user_data)
{
ExternRefMapNode *node = (ExternRefMapNode *)value;
WASMModuleInstanceCommon *module_inst = (WASMModuleInstanceCommon *)
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);
}
else {
node->marked = false;
}
}
}
static void
mark_externref(uint32 externref_idx)
{
ExternRefMapNode *node;
if (externref_idx != NULL_REF) {
node = bh_hash_map_find(externref_map,
(void*)(uintptr_t)externref_idx);
if (node) {
node->marked = true;
}
}
}
#if WASM_ENABLE_INTERP != 0
static void
interp_mark_all_externrefs(WASMModuleInstance *module_inst)
{
uint32 i, j, externref_idx, *table_data;
uint8 *global_data = module_inst->global_data;
WASMGlobalInstance *global;
WASMTableInstance *table;
global = module_inst->globals;
for (i = 0; i < module_inst->global_count; i++, global++) {
if (global->type == VALUE_TYPE_EXTERNREF) {
externref_idx = *(uint32*)(global_data + global->data_offset);
mark_externref(externref_idx);
}
}
for (i = 0; i < module_inst->table_count; i++) {
table = wasm_get_table_inst(module_inst, i);
if (table->elem_type == VALUE_TYPE_EXTERNREF) {
table_data = (uint32 *)table->base_addr;
for (j = 0; j < table->cur_size; j++) {
externref_idx = table_data[j];
mark_externref(externref_idx);
}
}
}
}
#endif
#if WASM_ENABLE_AOT != 0
static void
aot_mark_all_externrefs(AOTModuleInstance *module_inst)
{
uint32 i = 0, j = 0;
const AOTModule *module = (AOTModule *)(module_inst->aot_module.ptr);
const AOTTable *table = module->tables;
const AOTGlobal *global = module->globals;
const AOTTableInstance *table_inst =
(AOTTableInstance *)module_inst->tables.ptr;
for (i = 0; i < module->global_count; i++, global++) {
if (global->type == VALUE_TYPE_EXTERNREF) {
mark_externref(*(uint32 *)((uint8 *)module_inst->global_data.ptr
+ global->data_offset));
}
}
for (i = 0; i < module->table_count;
i++, table_inst = aot_next_tbl_inst(table_inst)) {
if ((table + i)->elem_type == VALUE_TYPE_EXTERNREF) {
while (j < table_inst->cur_size) {
mark_externref(table_inst->data[j++]);
}
}
}
}
#endif
void
wasm_externref_reclaim(WASMModuleInstanceCommon *module_inst)
{
os_mutex_lock(&externref_lock);
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode)
interp_mark_all_externrefs((WASMModuleInstance*)module_inst);
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT)
aot_mark_all_externrefs((AOTModuleInstance*)module_inst);
#endif
bh_hash_map_traverse(externref_map, reclaim_extobj_callback,
(void*)module_inst);
os_mutex_unlock(&externref_lock);
}
static void
cleanup_extobj_callback(void *key, void *value, void *user_data)
{
ExternRefMapNode *node = (ExternRefMapNode *)value;
WASMModuleInstanceCommon *module_inst = (WASMModuleInstanceCommon *)
user_data;
if (node->module_inst == module_inst) {
bh_hash_map_remove(externref_map, key, NULL, NULL);
wasm_runtime_free(value);
}
}
void
wasm_externref_cleanup(WASMModuleInstanceCommon *module_inst)
{
os_mutex_lock(&externref_lock);
bh_hash_map_traverse(externref_map, cleanup_extobj_callback,
(void*)module_inst);
os_mutex_unlock(&externref_lock);
}
bool
wasm_externref_retain(uint32 externref_idx)
{
ExternRefMapNode *node;
os_mutex_lock(&externref_lock);
if (externref_idx != NULL_REF) {
node = bh_hash_map_find(externref_map,
(void*)(uintptr_t)externref_idx);
if (node) {
node->retained = true;
os_mutex_unlock(&externref_lock);
return true;
}
}
os_mutex_unlock(&externref_lock);
return false;
}
#endif /* end of WASM_ENABLE_REF_TYPES */
#if WASM_ENABLE_DUMP_CALL_STACK != 0
void
wasm_runtime_dump_call_stack(WASMExecEnv *exec_env)
@ -3815,3 +4320,4 @@ wasm_runtime_dump_call_stack(WASMExecEnv *exec_env)
#endif
}
#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */