mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-06 15:05:19 +00:00
ff25110840
When using the wasm-c-api and there's a trap, `wasm_func_call()` returns a `wasm_trap_t *` object. No matter which thread crashes, the trap contains the stack frames of the main thread. With this PR, when there's an exception, the stack frames of the thread where the exception occurs are stored into the thread cluster. `wasm_func_call()` can then return those stack frames.
5254 lines
149 KiB
C
5254 lines
149 KiB
C
/*
|
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
*/
|
|
|
|
#include "bh_log.h"
|
|
#include "wasm_c_api_internal.h"
|
|
|
|
#include "bh_assert.h"
|
|
#include "wasm_export.h"
|
|
#include "wasm_memory.h"
|
|
#if WASM_ENABLE_INTERP != 0
|
|
#include "wasm_runtime.h"
|
|
#endif
|
|
#if WASM_ENABLE_AOT != 0
|
|
#include "aot_runtime.h"
|
|
#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0
|
|
#include "aot.h"
|
|
#include "aot_llvm.h"
|
|
#endif /*WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0*/
|
|
#endif /*WASM_ENABLE_AOT != 0*/
|
|
|
|
#if WASM_ENABLE_WASM_CACHE != 0
|
|
#include <openssl/sha.h>
|
|
#endif
|
|
#if WASM_ENABLE_THREAD_MGR != 0
|
|
#include "thread_manager.h"
|
|
#endif
|
|
|
|
/*
|
|
* Thread Model:
|
|
* - Only one wasm_engine_t in one process
|
|
* - One wasm_store_t is only accessed by one thread. wasm_store_t can't be
|
|
* shared in threads
|
|
* - wasm_module_t can be shared in threads
|
|
* - wasm_instance_t can not be shared in threads
|
|
*/
|
|
|
|
#define ASSERT_NOT_IMPLEMENTED() bh_assert(!"not implemented")
|
|
#define UNREACHABLE() bh_assert(!"unreachable")
|
|
|
|
typedef struct wasm_module_ex_t {
|
|
struct WASMModuleCommon *module_comm_rt;
|
|
wasm_byte_vec_t *binary;
|
|
korp_mutex lock;
|
|
uint32 ref_count;
|
|
#if WASM_ENABLE_WASM_CACHE != 0
|
|
char hash[SHA256_DIGEST_LENGTH];
|
|
#endif
|
|
} wasm_module_ex_t;
|
|
|
|
#ifndef os_thread_local_attribute
|
|
typedef struct thread_local_stores {
|
|
korp_tid tid;
|
|
unsigned stores_num;
|
|
} thread_local_stores;
|
|
#endif
|
|
|
|
static void
|
|
wasm_module_delete_internal(wasm_module_t *);
|
|
|
|
static void
|
|
wasm_instance_delete_internal(wasm_instance_t *);
|
|
|
|
/* temporarily put stubs here */
|
|
static wasm_store_t *
|
|
wasm_store_copy(const wasm_store_t *src)
|
|
{
|
|
(void)src;
|
|
LOG_WARNING("in the stub of %s", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
wasm_module_t *
|
|
wasm_module_copy(const wasm_module_t *src)
|
|
{
|
|
(void)src;
|
|
LOG_WARNING("in the stub of %s", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
wasm_instance_t *
|
|
wasm_instance_copy(const wasm_instance_t *src)
|
|
{
|
|
(void)src;
|
|
LOG_WARNING("in the stub of %s", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
static inline void *
|
|
malloc_internal(uint64 size)
|
|
{
|
|
void *mem = NULL;
|
|
|
|
if (size < UINT32_MAX && (mem = wasm_runtime_malloc((uint32)size))) {
|
|
memset(mem, 0, size);
|
|
}
|
|
|
|
return mem;
|
|
}
|
|
|
|
/* clang-format off */
|
|
#define RETURN_OBJ(obj, obj_del_func) \
|
|
return obj; \
|
|
failed: \
|
|
obj_del_func(obj); \
|
|
return NULL;
|
|
|
|
#define RETURN_VOID(obj, obj_del_func) \
|
|
return; \
|
|
failed: \
|
|
obj_del_func(obj); \
|
|
return;
|
|
/* clang-format on */
|
|
|
|
/* Vectors */
|
|
#define INIT_VEC(vector_p, init_func, ...) \
|
|
do { \
|
|
if (!(vector_p = malloc_internal(sizeof(*(vector_p))))) { \
|
|
goto failed; \
|
|
} \
|
|
\
|
|
init_func(vector_p, ##__VA_ARGS__); \
|
|
if (vector_p->size && !vector_p->data) { \
|
|
LOG_DEBUG("%s failed", #init_func); \
|
|
goto failed; \
|
|
} \
|
|
} while (false)
|
|
|
|
#define DEINIT_VEC(vector_p, deinit_func) \
|
|
if ((vector_p)) { \
|
|
deinit_func(vector_p); \
|
|
wasm_runtime_free(vector_p); \
|
|
vector_p = NULL; \
|
|
}
|
|
|
|
#define WASM_DEFINE_VEC(name) \
|
|
void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t *out) \
|
|
{ \
|
|
wasm_##name##_vec_new_uninitialized(out, 0); \
|
|
} \
|
|
void wasm_##name##_vec_new_uninitialized(own wasm_##name##_vec_t *out, \
|
|
size_t size) \
|
|
{ \
|
|
wasm_##name##_vec_new(out, size, NULL); \
|
|
}
|
|
|
|
/* vectors with no ownership management of elements */
|
|
#define WASM_DEFINE_VEC_PLAIN(name) \
|
|
WASM_DEFINE_VEC(name) \
|
|
void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \
|
|
own wasm_##name##_t const data[]) \
|
|
{ \
|
|
if (!out) { \
|
|
return; \
|
|
} \
|
|
\
|
|
memset(out, 0, sizeof(wasm_##name##_vec_t)); \
|
|
\
|
|
if (!size) { \
|
|
return; \
|
|
} \
|
|
\
|
|
if (!bh_vector_init((Vector *)out, size, sizeof(wasm_##name##_t), \
|
|
true)) { \
|
|
LOG_DEBUG("bh_vector_init failed"); \
|
|
goto failed; \
|
|
} \
|
|
\
|
|
if (data) { \
|
|
uint32 size_in_bytes = 0; \
|
|
size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t)); \
|
|
bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \
|
|
out->num_elems = size; \
|
|
} \
|
|
\
|
|
RETURN_VOID(out, wasm_##name##_vec_delete) \
|
|
} \
|
|
void wasm_##name##_vec_copy(wasm_##name##_vec_t *out, \
|
|
const wasm_##name##_vec_t *src) \
|
|
{ \
|
|
if (!src) { \
|
|
return; \
|
|
} \
|
|
wasm_##name##_vec_new(out, src->size, src->data); \
|
|
} \
|
|
void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \
|
|
{ \
|
|
if (v) { \
|
|
bh_vector_destroy((Vector *)v); \
|
|
} \
|
|
}
|
|
|
|
/* vectors that own their elements */
|
|
#define WASM_DEFINE_VEC_OWN(name, elem_destroy_func) \
|
|
WASM_DEFINE_VEC(name) \
|
|
void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \
|
|
own wasm_##name##_t *const data[]) \
|
|
{ \
|
|
if (!out) { \
|
|
return; \
|
|
} \
|
|
\
|
|
memset(out, 0, sizeof(wasm_##name##_vec_t)); \
|
|
\
|
|
if (!size) { \
|
|
return; \
|
|
} \
|
|
\
|
|
if (!bh_vector_init((Vector *)out, size, sizeof(wasm_##name##_t *), \
|
|
true)) { \
|
|
LOG_DEBUG("bh_vector_init failed"); \
|
|
goto failed; \
|
|
} \
|
|
\
|
|
if (data) { \
|
|
uint32 size_in_bytes = 0; \
|
|
size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t *)); \
|
|
bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \
|
|
out->num_elems = size; \
|
|
} \
|
|
\
|
|
RETURN_VOID(out, wasm_##name##_vec_delete) \
|
|
} \
|
|
void wasm_##name##_vec_copy(own wasm_##name##_vec_t *out, \
|
|
const wasm_##name##_vec_t *src) \
|
|
{ \
|
|
size_t i = 0; \
|
|
\
|
|
if (!out) { \
|
|
return; \
|
|
} \
|
|
memset(out, 0, sizeof(Vector)); \
|
|
\
|
|
if (!src || !src->size) { \
|
|
return; \
|
|
} \
|
|
\
|
|
if (!bh_vector_init((Vector *)out, src->size, \
|
|
sizeof(wasm_##name##_t *), true)) { \
|
|
LOG_DEBUG("bh_vector_init failed"); \
|
|
goto failed; \
|
|
} \
|
|
\
|
|
for (i = 0; i != src->num_elems; ++i) { \
|
|
if (!(out->data[i] = wasm_##name##_copy(src->data[i]))) { \
|
|
LOG_DEBUG("wasm_%s_copy failed", #name); \
|
|
goto failed; \
|
|
} \
|
|
} \
|
|
out->num_elems = src->num_elems; \
|
|
\
|
|
RETURN_VOID(out, wasm_##name##_vec_delete) \
|
|
} \
|
|
void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \
|
|
{ \
|
|
size_t i = 0; \
|
|
if (!v) { \
|
|
return; \
|
|
} \
|
|
for (i = 0; i != v->num_elems && v->data; ++i) { \
|
|
elem_destroy_func(*(v->data + i)); \
|
|
} \
|
|
bh_vector_destroy((Vector *)v); \
|
|
}
|
|
|
|
WASM_DEFINE_VEC_PLAIN(byte)
|
|
WASM_DEFINE_VEC_PLAIN(val)
|
|
|
|
WASM_DEFINE_VEC_OWN(exporttype, wasm_exporttype_delete)
|
|
WASM_DEFINE_VEC_OWN(extern, wasm_extern_delete)
|
|
WASM_DEFINE_VEC_OWN(frame, wasm_frame_delete)
|
|
WASM_DEFINE_VEC_OWN(functype, wasm_functype_delete)
|
|
WASM_DEFINE_VEC_OWN(importtype, wasm_importtype_delete)
|
|
WASM_DEFINE_VEC_OWN(instance, wasm_instance_delete_internal)
|
|
WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal)
|
|
WASM_DEFINE_VEC_OWN(store, wasm_store_delete)
|
|
WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete)
|
|
|
|
#ifndef NDEBUG
|
|
#if WASM_ENABLE_MEMORY_PROFILING != 0
|
|
#define WASM_C_DUMP_PROC_MEM() LOG_PROC_MEM()
|
|
#else
|
|
#define WASM_C_DUMP_PROC_MEM() (void)0
|
|
#endif
|
|
#else
|
|
#define WASM_C_DUMP_PROC_MEM() (void)0
|
|
#endif
|
|
|
|
/* Runtime Environment */
|
|
own wasm_config_t *
|
|
wasm_config_new(void)
|
|
{
|
|
/* since wasm_runtime_malloc is not ready */
|
|
wasm_config_t *config = os_malloc(sizeof(wasm_config_t));
|
|
if (!config)
|
|
return NULL;
|
|
|
|
memset(config, 0, sizeof(wasm_config_t));
|
|
config->mem_alloc_type = Alloc_With_System_Allocator;
|
|
|
|
return config;
|
|
}
|
|
|
|
void
|
|
wasm_config_delete(own wasm_config_t *config)
|
|
{
|
|
if (config)
|
|
os_free(config);
|
|
}
|
|
|
|
wasm_config_t *
|
|
wasm_config_set_mem_alloc_opt(wasm_config_t *config,
|
|
mem_alloc_type_t mem_alloc_type,
|
|
MemAllocOption *mem_alloc_option)
|
|
{
|
|
if (!config)
|
|
return NULL;
|
|
|
|
config->mem_alloc_type = mem_alloc_type;
|
|
if (mem_alloc_option)
|
|
memcpy(&config->mem_alloc_option, mem_alloc_option,
|
|
sizeof(MemAllocOption));
|
|
return config;
|
|
}
|
|
|
|
wasm_config_t *
|
|
wasm_config_set_linux_perf_opt(wasm_config_t *config, bool enable)
|
|
{
|
|
if (!config)
|
|
return NULL;
|
|
|
|
config->enable_linux_perf = enable;
|
|
return config;
|
|
}
|
|
|
|
wasm_config_t *
|
|
wasm_config_set_segue_flags(wasm_config_t *config, uint32 segue_flags)
|
|
{
|
|
if (!config)
|
|
return NULL;
|
|
|
|
config->segue_flags = segue_flags;
|
|
return config;
|
|
}
|
|
|
|
static void
|
|
wasm_engine_delete_internal(wasm_engine_t *engine)
|
|
{
|
|
if (engine) {
|
|
/* clean all created wasm_module_t and their locks */
|
|
unsigned i;
|
|
|
|
for (i = 0; i < engine->modules.num_elems; i++) {
|
|
wasm_module_ex_t *module;
|
|
if (bh_vector_get(&engine->modules, i, &module)) {
|
|
os_mutex_destroy(&module->lock);
|
|
wasm_runtime_free(module);
|
|
}
|
|
}
|
|
|
|
bh_vector_destroy(&engine->modules);
|
|
|
|
#ifndef os_thread_local_attribute
|
|
bh_vector_destroy(&engine->stores_by_tid);
|
|
#endif
|
|
|
|
wasm_runtime_free(engine);
|
|
}
|
|
|
|
wasm_runtime_destroy();
|
|
}
|
|
|
|
static wasm_engine_t *
|
|
wasm_engine_new_internal(wasm_config_t *config)
|
|
{
|
|
wasm_engine_t *engine = NULL;
|
|
/* init runtime */
|
|
RuntimeInitArgs init_args = { 0 };
|
|
#if WASM_ENABLE_JIT != 0
|
|
LLVMJITOptions *jit_options = wasm_runtime_get_llvm_jit_options();
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
bh_log_set_verbose_level(BH_LOG_LEVEL_VERBOSE);
|
|
#else
|
|
bh_log_set_verbose_level(BH_LOG_LEVEL_WARNING);
|
|
#endif
|
|
|
|
WASM_C_DUMP_PROC_MEM();
|
|
|
|
/* wasm_config_t->MemAllocOption -> RuntimeInitArgs->MemAllocOption */
|
|
init_args.mem_alloc_type = config->mem_alloc_type;
|
|
memcpy(&init_args.mem_alloc_option, &config->mem_alloc_option,
|
|
sizeof(MemAllocOption));
|
|
init_args.enable_linux_perf = config->enable_linux_perf;
|
|
init_args.segue_flags = config->segue_flags;
|
|
|
|
#if WASM_ENABLE_JIT != 0
|
|
jit_options->quick_invoke_c_api_import = true;
|
|
#endif
|
|
|
|
if (!wasm_runtime_full_init(&init_args)) {
|
|
LOG_DEBUG("wasm_runtime_full_init failed");
|
|
goto failed;
|
|
}
|
|
|
|
/* create wasm_engine_t */
|
|
if (!(engine = malloc_internal(sizeof(wasm_engine_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!bh_vector_init(&engine->modules, DEFAULT_VECTOR_INIT_SIZE,
|
|
sizeof(wasm_module_ex_t *), true))
|
|
goto failed;
|
|
|
|
#ifndef os_thread_local_attribute
|
|
if (!bh_vector_init(&engine->stores_by_tid, DEFAULT_VECTOR_INIT_SIZE,
|
|
sizeof(thread_local_stores), true))
|
|
goto failed;
|
|
#endif
|
|
|
|
engine->ref_count = 1;
|
|
|
|
WASM_C_DUMP_PROC_MEM();
|
|
|
|
RETURN_OBJ(engine, wasm_engine_delete_internal)
|
|
}
|
|
|
|
/* global engine instance */
|
|
static wasm_engine_t *singleton_engine;
|
|
#ifdef os_thread_local_attribute
|
|
/* categorize wasm_store_t as threads*/
|
|
static os_thread_local_attribute unsigned thread_local_stores_num = 0;
|
|
#endif
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
/**
|
|
* lock for the singleton_engine
|
|
* Note: if the platform has mutex initializer, we use a global lock to
|
|
* lock the operations of the singleton_engine, otherwise when there are
|
|
* operations happening simultaneously in multiple threads, developer
|
|
* must create the lock by himself, and use it to lock the operations
|
|
*/
|
|
static korp_mutex engine_lock = OS_THREAD_MUTEX_INITIALIZER;
|
|
#endif
|
|
|
|
own wasm_engine_t *
|
|
wasm_engine_new()
|
|
{
|
|
wasm_config_t config = { 0 };
|
|
wasm_config_set_mem_alloc_opt(&config, Alloc_With_System_Allocator, NULL);
|
|
wasm_engine_t *engine = wasm_engine_new_with_config(&config);
|
|
return engine;
|
|
}
|
|
|
|
own wasm_engine_t *
|
|
wasm_engine_new_with_config(wasm_config_t *config)
|
|
{
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_lock(&engine_lock);
|
|
#endif
|
|
|
|
if (!singleton_engine)
|
|
singleton_engine = wasm_engine_new_internal(config);
|
|
else
|
|
singleton_engine->ref_count++;
|
|
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_unlock(&engine_lock);
|
|
#endif
|
|
|
|
return singleton_engine;
|
|
}
|
|
|
|
own wasm_engine_t *
|
|
wasm_engine_new_with_args(mem_alloc_type_t type, const MemAllocOption *opts)
|
|
{
|
|
wasm_config_t config = { 0 };
|
|
config.mem_alloc_type = type;
|
|
memcpy(&config.mem_alloc_option, opts, sizeof(MemAllocOption));
|
|
return wasm_engine_new_with_config(&config);
|
|
}
|
|
|
|
void
|
|
wasm_engine_delete(wasm_engine_t *engine)
|
|
{
|
|
if (!engine)
|
|
return;
|
|
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_lock(&engine_lock);
|
|
#endif
|
|
|
|
if (!singleton_engine) {
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_unlock(&engine_lock);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
bh_assert(engine == singleton_engine);
|
|
bh_assert(singleton_engine->ref_count > 0);
|
|
|
|
singleton_engine->ref_count--;
|
|
if (singleton_engine->ref_count == 0) {
|
|
wasm_engine_delete_internal(engine);
|
|
singleton_engine = NULL;
|
|
}
|
|
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_unlock(&engine_lock);
|
|
#endif
|
|
}
|
|
|
|
#ifndef os_thread_local_attribute
|
|
static bool
|
|
search_thread_local_store_num(Vector *stores_by_tid, korp_tid tid,
|
|
thread_local_stores *out_ts, unsigned *out_i)
|
|
{
|
|
unsigned i;
|
|
|
|
for (i = 0; i < stores_by_tid->num_elems; i++) {
|
|
bool ret = bh_vector_get(stores_by_tid, i, out_ts);
|
|
bh_assert(ret);
|
|
(void)ret;
|
|
|
|
if (out_ts->tid == tid) {
|
|
*out_i = i;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
static unsigned
|
|
retrive_thread_local_store_num(Vector *stores_by_tid, korp_tid tid)
|
|
{
|
|
#ifndef os_thread_local_attribute
|
|
unsigned i = 0;
|
|
thread_local_stores ts = { 0 };
|
|
unsigned ret = 0;
|
|
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_lock(&engine_lock);
|
|
#endif
|
|
|
|
if (search_thread_local_store_num(stores_by_tid, tid, &ts, &i))
|
|
ret = ts.stores_num;
|
|
else
|
|
ret = 0;
|
|
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_unlock(&engine_lock);
|
|
#endif
|
|
|
|
return ret;
|
|
#else
|
|
(void)stores_by_tid;
|
|
(void)tid;
|
|
|
|
return thread_local_stores_num;
|
|
#endif
|
|
}
|
|
|
|
static bool
|
|
increase_thread_local_store_num(Vector *stores_by_tid, korp_tid tid)
|
|
{
|
|
#ifndef os_thread_local_attribute
|
|
unsigned i = 0;
|
|
thread_local_stores ts = { 0 };
|
|
bool ret = false;
|
|
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_lock(&engine_lock);
|
|
#endif
|
|
|
|
if (search_thread_local_store_num(stores_by_tid, tid, &ts, &i)) {
|
|
/* just in case if integer overflow */
|
|
if (ts.stores_num + 1 < ts.stores_num) {
|
|
ret = false;
|
|
}
|
|
else {
|
|
ts.stores_num++;
|
|
ret = bh_vector_set(stores_by_tid, i, &ts);
|
|
bh_assert(ret);
|
|
}
|
|
}
|
|
else {
|
|
ts.tid = tid;
|
|
ts.stores_num = 1;
|
|
ret = bh_vector_append(stores_by_tid, &ts);
|
|
}
|
|
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_unlock(&engine_lock);
|
|
#endif
|
|
return ret;
|
|
#else
|
|
(void)stores_by_tid;
|
|
(void)tid;
|
|
|
|
/* just in case if integer overflow */
|
|
if (thread_local_stores_num + 1 < thread_local_stores_num)
|
|
return false;
|
|
|
|
thread_local_stores_num++;
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
static bool
|
|
decrease_thread_local_store_num(Vector *stores_by_tid, korp_tid tid)
|
|
{
|
|
#ifndef os_thread_local_attribute
|
|
unsigned i = 0;
|
|
thread_local_stores ts = { 0 };
|
|
bool ret = false;
|
|
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_lock(&engine_lock);
|
|
#endif
|
|
|
|
ret = search_thread_local_store_num(stores_by_tid, tid, &ts, &i);
|
|
bh_assert(ret);
|
|
|
|
/* just in case if integer overflow */
|
|
if (ts.stores_num - 1 > ts.stores_num) {
|
|
ret = false;
|
|
}
|
|
else {
|
|
ts.stores_num--;
|
|
ret = bh_vector_set(stores_by_tid, i, &ts);
|
|
bh_assert(ret);
|
|
}
|
|
|
|
#if defined(OS_THREAD_MUTEX_INITIALIZER)
|
|
os_mutex_unlock(&engine_lock);
|
|
#endif
|
|
|
|
return ret;
|
|
#else
|
|
(void)stores_by_tid;
|
|
(void)tid;
|
|
|
|
/* just in case if integer overflow */
|
|
if (thread_local_stores_num - 1 > thread_local_stores_num)
|
|
return false;
|
|
|
|
thread_local_stores_num--;
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
wasm_store_t *
|
|
wasm_store_new(wasm_engine_t *engine)
|
|
{
|
|
wasm_store_t *store = NULL;
|
|
|
|
WASM_C_DUMP_PROC_MEM();
|
|
|
|
if (!engine || singleton_engine != engine)
|
|
return NULL;
|
|
|
|
if (!retrive_thread_local_store_num(&engine->stores_by_tid,
|
|
os_self_thread())) {
|
|
if (!wasm_runtime_init_thread_env()) {
|
|
LOG_ERROR("init thread environment failed");
|
|
return NULL;
|
|
}
|
|
|
|
if (!increase_thread_local_store_num(&engine->stores_by_tid,
|
|
os_self_thread())) {
|
|
wasm_runtime_destroy_thread_env();
|
|
return NULL;
|
|
}
|
|
|
|
if (!(store = malloc_internal(sizeof(wasm_store_t)))) {
|
|
decrease_thread_local_store_num(&singleton_engine->stores_by_tid,
|
|
os_self_thread());
|
|
wasm_runtime_destroy_thread_env();
|
|
return NULL;
|
|
}
|
|
}
|
|
else {
|
|
if (!increase_thread_local_store_num(&engine->stores_by_tid,
|
|
os_self_thread()))
|
|
return NULL;
|
|
|
|
if (!(store = malloc_internal(sizeof(wasm_store_t)))) {
|
|
decrease_thread_local_store_num(&singleton_engine->stores_by_tid,
|
|
os_self_thread());
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* new a vector, and new its data */
|
|
INIT_VEC(store->modules, wasm_module_vec_new_uninitialized,
|
|
DEFAULT_VECTOR_INIT_LENGTH);
|
|
INIT_VEC(store->instances, wasm_instance_vec_new_uninitialized,
|
|
DEFAULT_VECTOR_INIT_LENGTH);
|
|
|
|
if (!(store->foreigns = malloc_internal(sizeof(Vector)))
|
|
|| !(bh_vector_init(store->foreigns, 24, sizeof(wasm_foreign_t *),
|
|
true))) {
|
|
goto failed;
|
|
}
|
|
|
|
WASM_C_DUMP_PROC_MEM();
|
|
|
|
return store;
|
|
failed:
|
|
wasm_store_delete(store);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
wasm_store_delete(wasm_store_t *store)
|
|
{
|
|
if (!store) {
|
|
return;
|
|
}
|
|
|
|
DEINIT_VEC(store->instances, wasm_instance_vec_delete);
|
|
DEINIT_VEC(store->modules, wasm_module_vec_delete);
|
|
if (store->foreigns) {
|
|
bh_vector_destroy(store->foreigns);
|
|
wasm_runtime_free(store->foreigns);
|
|
}
|
|
|
|
wasm_runtime_free(store);
|
|
|
|
if (decrease_thread_local_store_num(&singleton_engine->stores_by_tid,
|
|
os_self_thread())) {
|
|
if (!retrive_thread_local_store_num(&singleton_engine->stores_by_tid,
|
|
os_self_thread())) {
|
|
wasm_runtime_destroy_thread_env();
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Type Representations */
|
|
static inline wasm_valkind_t
|
|
val_type_rt_2_valkind(uint8 val_type_rt)
|
|
{
|
|
switch (val_type_rt) {
|
|
#define WAMR_VAL_TYPE_2_WASM_VAL_KIND(name) \
|
|
case VALUE_TYPE_##name: \
|
|
return WASM_##name;
|
|
|
|
WAMR_VAL_TYPE_2_WASM_VAL_KIND(I32)
|
|
WAMR_VAL_TYPE_2_WASM_VAL_KIND(I64)
|
|
WAMR_VAL_TYPE_2_WASM_VAL_KIND(F32)
|
|
WAMR_VAL_TYPE_2_WASM_VAL_KIND(F64)
|
|
WAMR_VAL_TYPE_2_WASM_VAL_KIND(FUNCREF)
|
|
#undef WAMR_VAL_TYPE_2_WASM_VAL_KIND
|
|
|
|
default:
|
|
return WASM_ANYREF;
|
|
}
|
|
}
|
|
|
|
static wasm_valtype_t *
|
|
wasm_valtype_new_internal(uint8 val_type_rt)
|
|
{
|
|
return wasm_valtype_new(val_type_rt_2_valkind(val_type_rt));
|
|
}
|
|
|
|
wasm_valtype_t *
|
|
wasm_valtype_new(wasm_valkind_t kind)
|
|
{
|
|
wasm_valtype_t *val_type;
|
|
|
|
if (kind > WASM_F64 && WASM_FUNCREF != kind
|
|
#if WASM_ENABLE_REF_TYPES != 0
|
|
&& WASM_ANYREF != kind
|
|
#endif
|
|
) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(val_type = malloc_internal(sizeof(wasm_valtype_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
val_type->kind = kind;
|
|
|
|
return val_type;
|
|
}
|
|
|
|
void
|
|
wasm_valtype_delete(wasm_valtype_t *val_type)
|
|
{
|
|
if (val_type) {
|
|
wasm_runtime_free(val_type);
|
|
}
|
|
}
|
|
|
|
wasm_valtype_t *
|
|
wasm_valtype_copy(const wasm_valtype_t *src)
|
|
{
|
|
return src ? wasm_valtype_new(src->kind) : NULL;
|
|
}
|
|
|
|
wasm_valkind_t
|
|
wasm_valtype_kind(const wasm_valtype_t *val_type)
|
|
{
|
|
return val_type ? val_type->kind : WASM_ANYREF;
|
|
}
|
|
|
|
static wasm_functype_t *
|
|
wasm_functype_new_internal(WASMType *type_rt)
|
|
{
|
|
wasm_functype_t *type = NULL;
|
|
wasm_valtype_t *param_type = NULL, *result_type = NULL;
|
|
uint32 i = 0;
|
|
|
|
if (!type_rt) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(type = malloc_internal(sizeof(wasm_functype_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
type->extern_kind = WASM_EXTERN_FUNC;
|
|
|
|
/* WASMType->types[0 : type_rt->param_count) -> type->params */
|
|
INIT_VEC(type->params, wasm_valtype_vec_new_uninitialized,
|
|
type_rt->param_count);
|
|
for (i = 0; i < type_rt->param_count; ++i) {
|
|
if (!(param_type = wasm_valtype_new_internal(*(type_rt->types + i)))) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!bh_vector_append((Vector *)type->params, ¶m_type)) {
|
|
LOG_DEBUG("bh_vector_append failed");
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
/* WASMType->types[type_rt->param_count : type_rt->result_count) ->
|
|
* type->results */
|
|
INIT_VEC(type->results, wasm_valtype_vec_new_uninitialized,
|
|
type_rt->result_count);
|
|
for (i = 0; i < type_rt->result_count; ++i) {
|
|
if (!(result_type = wasm_valtype_new_internal(
|
|
*(type_rt->types + type_rt->param_count + i)))) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!bh_vector_append((Vector *)type->results, &result_type)) {
|
|
LOG_DEBUG("bh_vector_append failed");
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
return type;
|
|
|
|
failed:
|
|
wasm_valtype_delete(param_type);
|
|
wasm_valtype_delete(result_type);
|
|
wasm_functype_delete(type);
|
|
return NULL;
|
|
}
|
|
|
|
wasm_functype_t *
|
|
wasm_functype_new(own wasm_valtype_vec_t *params,
|
|
own wasm_valtype_vec_t *results)
|
|
{
|
|
wasm_functype_t *type = NULL;
|
|
|
|
if (!(type = malloc_internal(sizeof(wasm_functype_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
type->extern_kind = WASM_EXTERN_FUNC;
|
|
|
|
/* take ownership */
|
|
if (!(type->params = malloc_internal(sizeof(wasm_valtype_vec_t)))) {
|
|
goto failed;
|
|
}
|
|
if (params) {
|
|
bh_memcpy_s(type->params, sizeof(wasm_valtype_vec_t), params,
|
|
sizeof(wasm_valtype_vec_t));
|
|
}
|
|
|
|
if (!(type->results = malloc_internal(sizeof(wasm_valtype_vec_t)))) {
|
|
goto failed;
|
|
}
|
|
if (results) {
|
|
bh_memcpy_s(type->results, sizeof(wasm_valtype_vec_t), results,
|
|
sizeof(wasm_valtype_vec_t));
|
|
}
|
|
|
|
return type;
|
|
|
|
failed:
|
|
wasm_functype_delete(type);
|
|
return NULL;
|
|
}
|
|
|
|
wasm_functype_t *
|
|
wasm_functype_copy(const wasm_functype_t *src)
|
|
{
|
|
wasm_functype_t *functype;
|
|
wasm_valtype_vec_t params = { 0 }, results = { 0 };
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
wasm_valtype_vec_copy(¶ms, src->params);
|
|
if (src->params->size && !params.data) {
|
|
goto failed;
|
|
}
|
|
|
|
wasm_valtype_vec_copy(&results, src->results);
|
|
if (src->results->size && !results.data) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(functype = wasm_functype_new(¶ms, &results))) {
|
|
goto failed;
|
|
}
|
|
|
|
return functype;
|
|
|
|
failed:
|
|
wasm_valtype_vec_delete(¶ms);
|
|
wasm_valtype_vec_delete(&results);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
wasm_functype_delete(wasm_functype_t *func_type)
|
|
{
|
|
if (!func_type) {
|
|
return;
|
|
}
|
|
|
|
DEINIT_VEC(func_type->params, wasm_valtype_vec_delete);
|
|
DEINIT_VEC(func_type->results, wasm_valtype_vec_delete);
|
|
|
|
wasm_runtime_free(func_type);
|
|
}
|
|
|
|
const wasm_valtype_vec_t *
|
|
wasm_functype_params(const wasm_functype_t *func_type)
|
|
{
|
|
if (!func_type) {
|
|
return NULL;
|
|
}
|
|
|
|
return func_type->params;
|
|
}
|
|
|
|
const wasm_valtype_vec_t *
|
|
wasm_functype_results(const wasm_functype_t *func_type)
|
|
{
|
|
if (!func_type) {
|
|
return NULL;
|
|
}
|
|
|
|
return func_type->results;
|
|
}
|
|
|
|
static bool
|
|
cmp_val_kind_with_val_type(wasm_valkind_t v_k, uint8 v_t)
|
|
{
|
|
return (v_k == WASM_I32 && v_t == VALUE_TYPE_I32)
|
|
|| (v_k == WASM_I64 && v_t == VALUE_TYPE_I64)
|
|
|| (v_k == WASM_F32 && v_t == VALUE_TYPE_F32)
|
|
|| (v_k == WASM_F64 && v_t == VALUE_TYPE_F64)
|
|
|| (v_k == WASM_ANYREF && v_t == VALUE_TYPE_EXTERNREF)
|
|
|| (v_k == WASM_FUNCREF && v_t == VALUE_TYPE_FUNCREF);
|
|
}
|
|
|
|
/*
|
|
*to compare a function type of wasm-c-api with a function type of wasm_runtime
|
|
*/
|
|
static bool
|
|
wasm_functype_same_internal(const wasm_functype_t *type,
|
|
const WASMType *type_intl)
|
|
{
|
|
uint32 i = 0;
|
|
|
|
if (!type || !type_intl || type->params->num_elems != type_intl->param_count
|
|
|| type->results->num_elems != type_intl->result_count)
|
|
return false;
|
|
|
|
for (i = 0; i < type->params->num_elems; i++) {
|
|
wasm_valtype_t *v_t = type->params->data[i];
|
|
if (!cmp_val_kind_with_val_type(wasm_valtype_kind(v_t),
|
|
type_intl->types[i]))
|
|
return false;
|
|
}
|
|
|
|
for (i = 0; i < type->results->num_elems; i++) {
|
|
wasm_valtype_t *v_t = type->results->data[i];
|
|
if (!cmp_val_kind_with_val_type(
|
|
wasm_valtype_kind(v_t),
|
|
type_intl->types[i + type->params->num_elems]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
wasm_globaltype_t *
|
|
wasm_globaltype_new(own wasm_valtype_t *val_type, wasm_mutability_t mut)
|
|
{
|
|
wasm_globaltype_t *global_type = NULL;
|
|
|
|
if (!val_type) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(global_type = malloc_internal(sizeof(wasm_globaltype_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
global_type->extern_kind = WASM_EXTERN_GLOBAL;
|
|
global_type->val_type = val_type;
|
|
global_type->mutability = mut;
|
|
|
|
return global_type;
|
|
}
|
|
|
|
wasm_globaltype_t *
|
|
wasm_globaltype_new_internal(uint8 val_type_rt, bool is_mutable)
|
|
{
|
|
wasm_globaltype_t *globaltype;
|
|
wasm_valtype_t *val_type;
|
|
|
|
if (!(val_type = wasm_valtype_new(val_type_rt_2_valkind(val_type_rt)))) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(globaltype = wasm_globaltype_new(
|
|
val_type, is_mutable ? WASM_VAR : WASM_CONST))) {
|
|
wasm_valtype_delete(val_type);
|
|
}
|
|
|
|
return globaltype;
|
|
}
|
|
|
|
void
|
|
wasm_globaltype_delete(wasm_globaltype_t *global_type)
|
|
{
|
|
if (!global_type) {
|
|
return;
|
|
}
|
|
|
|
if (global_type->val_type) {
|
|
wasm_valtype_delete(global_type->val_type);
|
|
global_type->val_type = NULL;
|
|
}
|
|
|
|
wasm_runtime_free(global_type);
|
|
}
|
|
|
|
wasm_globaltype_t *
|
|
wasm_globaltype_copy(const wasm_globaltype_t *src)
|
|
{
|
|
wasm_globaltype_t *global_type;
|
|
wasm_valtype_t *val_type;
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(val_type = wasm_valtype_copy(src->val_type))) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(global_type = wasm_globaltype_new(val_type, src->mutability))) {
|
|
wasm_valtype_delete(val_type);
|
|
}
|
|
|
|
return global_type;
|
|
}
|
|
|
|
const wasm_valtype_t *
|
|
wasm_globaltype_content(const wasm_globaltype_t *global_type)
|
|
{
|
|
if (!global_type) {
|
|
return NULL;
|
|
}
|
|
|
|
return global_type->val_type;
|
|
}
|
|
|
|
wasm_mutability_t
|
|
wasm_globaltype_mutability(const wasm_globaltype_t *global_type)
|
|
{
|
|
if (!global_type) {
|
|
return false;
|
|
}
|
|
|
|
return global_type->mutability;
|
|
}
|
|
|
|
static wasm_tabletype_t *
|
|
wasm_tabletype_new_internal(uint8 val_type_rt, uint32 init_size,
|
|
uint32 max_size)
|
|
{
|
|
wasm_tabletype_t *table_type;
|
|
wasm_limits_t limits = { init_size, max_size };
|
|
wasm_valtype_t *val_type;
|
|
|
|
if (!(val_type = wasm_valtype_new_internal(val_type_rt))) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(table_type = wasm_tabletype_new(val_type, &limits))) {
|
|
wasm_valtype_delete(val_type);
|
|
}
|
|
|
|
return table_type;
|
|
}
|
|
|
|
wasm_tabletype_t *
|
|
wasm_tabletype_new(own wasm_valtype_t *val_type, const wasm_limits_t *limits)
|
|
{
|
|
wasm_tabletype_t *table_type = NULL;
|
|
|
|
if (!val_type || !limits) {
|
|
return NULL;
|
|
}
|
|
|
|
if (wasm_valtype_kind(val_type) != WASM_FUNCREF
|
|
#if WASM_ENABLE_REF_TYPES != 0
|
|
&& wasm_valtype_kind(val_type) != WASM_ANYREF
|
|
#endif
|
|
) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(table_type = malloc_internal(sizeof(wasm_tabletype_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
table_type->extern_kind = WASM_EXTERN_TABLE;
|
|
table_type->val_type = val_type;
|
|
table_type->limits.min = limits->min;
|
|
table_type->limits.max = limits->max;
|
|
|
|
return table_type;
|
|
}
|
|
|
|
wasm_tabletype_t *
|
|
wasm_tabletype_copy(const wasm_tabletype_t *src)
|
|
{
|
|
wasm_tabletype_t *table_type;
|
|
wasm_valtype_t *val_type;
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(val_type = wasm_valtype_copy(src->val_type))) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(table_type = wasm_tabletype_new(val_type, &src->limits))) {
|
|
wasm_valtype_delete(val_type);
|
|
}
|
|
|
|
return table_type;
|
|
}
|
|
|
|
void
|
|
wasm_tabletype_delete(wasm_tabletype_t *table_type)
|
|
{
|
|
if (!table_type) {
|
|
return;
|
|
}
|
|
|
|
if (table_type->val_type) {
|
|
wasm_valtype_delete(table_type->val_type);
|
|
table_type->val_type = NULL;
|
|
}
|
|
|
|
wasm_runtime_free(table_type);
|
|
}
|
|
|
|
const wasm_valtype_t *
|
|
wasm_tabletype_element(const wasm_tabletype_t *table_type)
|
|
{
|
|
if (!table_type) {
|
|
return NULL;
|
|
}
|
|
|
|
return table_type->val_type;
|
|
}
|
|
|
|
const wasm_limits_t *
|
|
wasm_tabletype_limits(const wasm_tabletype_t *table_type)
|
|
{
|
|
if (!table_type) {
|
|
return NULL;
|
|
}
|
|
|
|
return &(table_type->limits);
|
|
}
|
|
|
|
static wasm_memorytype_t *
|
|
wasm_memorytype_new_internal(uint32 min_pages, uint32 max_pages)
|
|
{
|
|
wasm_limits_t limits = { min_pages, max_pages };
|
|
return wasm_memorytype_new(&limits);
|
|
}
|
|
|
|
wasm_memorytype_t *
|
|
wasm_memorytype_new(const wasm_limits_t *limits)
|
|
{
|
|
wasm_memorytype_t *memory_type = NULL;
|
|
|
|
if (!limits) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(memory_type = malloc_internal(sizeof(wasm_memorytype_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
memory_type->extern_kind = WASM_EXTERN_MEMORY;
|
|
memory_type->limits.min = limits->min;
|
|
memory_type->limits.max = limits->max;
|
|
|
|
return memory_type;
|
|
}
|
|
|
|
wasm_memorytype_t *
|
|
wasm_memorytype_copy(const wasm_memorytype_t *src)
|
|
{
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
return wasm_memorytype_new(&src->limits);
|
|
}
|
|
|
|
void
|
|
wasm_memorytype_delete(wasm_memorytype_t *memory_type)
|
|
{
|
|
if (memory_type) {
|
|
wasm_runtime_free(memory_type);
|
|
}
|
|
}
|
|
|
|
const wasm_limits_t *
|
|
wasm_memorytype_limits(const wasm_memorytype_t *memory_type)
|
|
{
|
|
if (!memory_type) {
|
|
return NULL;
|
|
}
|
|
|
|
return &(memory_type->limits);
|
|
}
|
|
|
|
wasm_externkind_t
|
|
wasm_externtype_kind(const wasm_externtype_t *extern_type)
|
|
{
|
|
if (!extern_type) {
|
|
return WASM_EXTERN_FUNC;
|
|
}
|
|
|
|
return extern_type->extern_kind;
|
|
}
|
|
|
|
#define BASIC_FOUR_TYPE_LIST(V) \
|
|
V(functype) \
|
|
V(globaltype) \
|
|
V(memorytype) \
|
|
V(tabletype)
|
|
|
|
#define WASM_EXTERNTYPE_AS_OTHERTYPE(name) \
|
|
wasm_##name##_t *wasm_externtype_as_##name(wasm_externtype_t *extern_type) \
|
|
{ \
|
|
return (wasm_##name##_t *)extern_type; \
|
|
}
|
|
|
|
BASIC_FOUR_TYPE_LIST(WASM_EXTERNTYPE_AS_OTHERTYPE)
|
|
#undef WASM_EXTERNTYPE_AS_OTHERTYPE
|
|
|
|
#define WASM_OTHERTYPE_AS_EXTERNTYPE(name) \
|
|
wasm_externtype_t *wasm_##name##_as_externtype(wasm_##name##_t *other) \
|
|
{ \
|
|
return (wasm_externtype_t *)other; \
|
|
}
|
|
|
|
BASIC_FOUR_TYPE_LIST(WASM_OTHERTYPE_AS_EXTERNTYPE)
|
|
#undef WASM_OTHERTYPE_AS_EXTERNTYPE
|
|
|
|
#define WASM_EXTERNTYPE_AS_OTHERTYPE_CONST(name) \
|
|
const wasm_##name##_t *wasm_externtype_as_##name##_const( \
|
|
const wasm_externtype_t *extern_type) \
|
|
{ \
|
|
return (const wasm_##name##_t *)extern_type; \
|
|
}
|
|
|
|
BASIC_FOUR_TYPE_LIST(WASM_EXTERNTYPE_AS_OTHERTYPE_CONST)
|
|
#undef WASM_EXTERNTYPE_AS_OTHERTYPE_CONST
|
|
|
|
#define WASM_OTHERTYPE_AS_EXTERNTYPE_CONST(name) \
|
|
const wasm_externtype_t *wasm_##name##_as_externtype_const( \
|
|
const wasm_##name##_t *other) \
|
|
{ \
|
|
return (const wasm_externtype_t *)other; \
|
|
}
|
|
|
|
BASIC_FOUR_TYPE_LIST(WASM_OTHERTYPE_AS_EXTERNTYPE_CONST)
|
|
#undef WASM_OTHERTYPE_AS_EXTERNTYPE_CONST
|
|
|
|
wasm_externtype_t *
|
|
wasm_externtype_copy(const wasm_externtype_t *src)
|
|
{
|
|
wasm_externtype_t *extern_type = NULL;
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
switch (src->extern_kind) {
|
|
#define COPY_EXTERNTYPE(NAME, name) \
|
|
case WASM_EXTERN_##NAME: \
|
|
{ \
|
|
extern_type = wasm_##name##_as_externtype( \
|
|
wasm_##name##_copy(wasm_externtype_as_##name##_const(src))); \
|
|
break; \
|
|
}
|
|
COPY_EXTERNTYPE(FUNC, functype)
|
|
COPY_EXTERNTYPE(GLOBAL, globaltype)
|
|
COPY_EXTERNTYPE(MEMORY, memorytype)
|
|
COPY_EXTERNTYPE(TABLE, tabletype)
|
|
#undef COPY_EXTERNTYPE
|
|
default:
|
|
LOG_WARNING("%s meets unsupported kind %u", __FUNCTION__,
|
|
src->extern_kind);
|
|
break;
|
|
}
|
|
return extern_type;
|
|
}
|
|
|
|
void
|
|
wasm_externtype_delete(wasm_externtype_t *extern_type)
|
|
{
|
|
if (!extern_type) {
|
|
return;
|
|
}
|
|
|
|
switch (wasm_externtype_kind(extern_type)) {
|
|
case WASM_EXTERN_FUNC:
|
|
wasm_functype_delete(wasm_externtype_as_functype(extern_type));
|
|
break;
|
|
case WASM_EXTERN_GLOBAL:
|
|
wasm_globaltype_delete(wasm_externtype_as_globaltype(extern_type));
|
|
break;
|
|
case WASM_EXTERN_MEMORY:
|
|
wasm_memorytype_delete(wasm_externtype_as_memorytype(extern_type));
|
|
break;
|
|
case WASM_EXTERN_TABLE:
|
|
wasm_tabletype_delete(wasm_externtype_as_tabletype(extern_type));
|
|
break;
|
|
default:
|
|
LOG_WARNING("%s meets unsupported type %u", __FUNCTION__,
|
|
wasm_externtype_kind(extern_type));
|
|
break;
|
|
}
|
|
}
|
|
|
|
own wasm_importtype_t *
|
|
wasm_importtype_new(own wasm_byte_vec_t *module_name,
|
|
own wasm_byte_vec_t *field_name,
|
|
own wasm_externtype_t *extern_type)
|
|
{
|
|
wasm_importtype_t *import_type = NULL;
|
|
|
|
if (!module_name || !field_name || !extern_type) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(import_type = malloc_internal(sizeof(wasm_importtype_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
/* take ownership */
|
|
if (!(import_type->module_name =
|
|
malloc_internal(sizeof(wasm_byte_vec_t)))) {
|
|
goto failed;
|
|
}
|
|
bh_memcpy_s(import_type->module_name, sizeof(wasm_byte_vec_t), module_name,
|
|
sizeof(wasm_byte_vec_t));
|
|
|
|
if (!(import_type->name = malloc_internal(sizeof(wasm_byte_vec_t)))) {
|
|
goto failed;
|
|
}
|
|
bh_memcpy_s(import_type->name, sizeof(wasm_byte_vec_t), field_name,
|
|
sizeof(wasm_byte_vec_t));
|
|
|
|
import_type->extern_type = extern_type;
|
|
|
|
return import_type;
|
|
failed:
|
|
wasm_importtype_delete(import_type);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
wasm_importtype_delete(own wasm_importtype_t *import_type)
|
|
{
|
|
if (!import_type) {
|
|
return;
|
|
}
|
|
|
|
DEINIT_VEC(import_type->module_name, wasm_byte_vec_delete);
|
|
DEINIT_VEC(import_type->name, wasm_byte_vec_delete);
|
|
wasm_externtype_delete(import_type->extern_type);
|
|
import_type->extern_type = NULL;
|
|
wasm_runtime_free(import_type);
|
|
}
|
|
|
|
own wasm_importtype_t *
|
|
wasm_importtype_copy(const wasm_importtype_t *src)
|
|
{
|
|
wasm_byte_vec_t module_name = { 0 }, name = { 0 };
|
|
wasm_externtype_t *extern_type = NULL;
|
|
wasm_importtype_t *import_type = NULL;
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
wasm_byte_vec_copy(&module_name, src->module_name);
|
|
if (src->module_name->size && !module_name.data) {
|
|
goto failed;
|
|
}
|
|
|
|
wasm_byte_vec_copy(&name, src->name);
|
|
if (src->name->size && !name.data) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(extern_type = wasm_externtype_copy(src->extern_type))) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(import_type =
|
|
wasm_importtype_new(&module_name, &name, extern_type))) {
|
|
goto failed;
|
|
}
|
|
|
|
return import_type;
|
|
|
|
failed:
|
|
wasm_byte_vec_delete(&module_name);
|
|
wasm_byte_vec_delete(&name);
|
|
wasm_externtype_delete(extern_type);
|
|
wasm_importtype_delete(import_type);
|
|
return NULL;
|
|
}
|
|
|
|
const wasm_byte_vec_t *
|
|
wasm_importtype_module(const wasm_importtype_t *import_type)
|
|
{
|
|
if (!import_type) {
|
|
return NULL;
|
|
}
|
|
|
|
return import_type->module_name;
|
|
}
|
|
|
|
const wasm_byte_vec_t *
|
|
wasm_importtype_name(const wasm_importtype_t *import_type)
|
|
{
|
|
if (!import_type) {
|
|
return NULL;
|
|
}
|
|
|
|
return import_type->name;
|
|
}
|
|
|
|
const wasm_externtype_t *
|
|
wasm_importtype_type(const wasm_importtype_t *import_type)
|
|
{
|
|
if (!import_type) {
|
|
return NULL;
|
|
}
|
|
|
|
return import_type->extern_type;
|
|
}
|
|
|
|
bool
|
|
wasm_importtype_is_linked(const wasm_importtype_t *import_type)
|
|
{
|
|
if (!import_type)
|
|
return false;
|
|
|
|
const wasm_name_t *module_name = wasm_importtype_module(import_type);
|
|
const wasm_name_t *field_name = wasm_importtype_name(import_type);
|
|
|
|
switch (wasm_externtype_kind(wasm_importtype_type(import_type))) {
|
|
case WASM_EXTERN_FUNC:
|
|
return wasm_runtime_is_import_func_linked(module_name->data,
|
|
field_name->data);
|
|
case WASM_EXTERN_GLOBAL:
|
|
return wasm_runtime_is_import_global_linked(module_name->data,
|
|
field_name->data);
|
|
case WASM_EXTERN_MEMORY:
|
|
case WASM_EXTERN_TABLE:
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
own wasm_exporttype_t *
|
|
wasm_exporttype_new(own wasm_byte_vec_t *name,
|
|
own wasm_externtype_t *extern_type)
|
|
{
|
|
wasm_exporttype_t *export_type = NULL;
|
|
|
|
if (!name || !extern_type) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(export_type = malloc_internal(sizeof(wasm_exporttype_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(export_type->name = malloc_internal(sizeof(wasm_byte_vec_t)))) {
|
|
wasm_exporttype_delete(export_type);
|
|
return NULL;
|
|
}
|
|
bh_memcpy_s(export_type->name, sizeof(wasm_byte_vec_t), name,
|
|
sizeof(wasm_byte_vec_t));
|
|
|
|
export_type->extern_type = extern_type;
|
|
|
|
return export_type;
|
|
}
|
|
|
|
wasm_exporttype_t *
|
|
wasm_exporttype_copy(const wasm_exporttype_t *src)
|
|
{
|
|
wasm_exporttype_t *export_type;
|
|
wasm_byte_vec_t name = { 0 };
|
|
wasm_externtype_t *extern_type = NULL;
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
wasm_byte_vec_copy(&name, src->name);
|
|
if (src->name->size && !name.data) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(extern_type = wasm_externtype_copy(src->extern_type))) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(export_type = wasm_exporttype_new(&name, extern_type))) {
|
|
goto failed;
|
|
}
|
|
|
|
return export_type;
|
|
failed:
|
|
wasm_byte_vec_delete(&name);
|
|
wasm_externtype_delete(extern_type);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
wasm_exporttype_delete(wasm_exporttype_t *export_type)
|
|
{
|
|
if (!export_type) {
|
|
return;
|
|
}
|
|
|
|
DEINIT_VEC(export_type->name, wasm_byte_vec_delete);
|
|
|
|
wasm_externtype_delete(export_type->extern_type);
|
|
|
|
wasm_runtime_free(export_type);
|
|
}
|
|
|
|
const wasm_byte_vec_t *
|
|
wasm_exporttype_name(const wasm_exporttype_t *export_type)
|
|
{
|
|
if (!export_type) {
|
|
return NULL;
|
|
}
|
|
return export_type->name;
|
|
}
|
|
|
|
const wasm_externtype_t *
|
|
wasm_exporttype_type(const wasm_exporttype_t *export_type)
|
|
{
|
|
if (!export_type) {
|
|
return NULL;
|
|
}
|
|
return export_type->extern_type;
|
|
}
|
|
|
|
/* Runtime Objects */
|
|
void
|
|
wasm_val_delete(wasm_val_t *v)
|
|
{
|
|
if (v)
|
|
wasm_runtime_free(v);
|
|
}
|
|
|
|
void
|
|
wasm_val_copy(wasm_val_t *out, const wasm_val_t *src)
|
|
{
|
|
if (!out || !src) {
|
|
return;
|
|
}
|
|
|
|
bh_memcpy_s(out, sizeof(wasm_val_t), src, sizeof(wasm_val_t));
|
|
}
|
|
|
|
bool
|
|
rt_val_to_wasm_val(const uint8 *data, uint8 val_type_rt, wasm_val_t *out)
|
|
{
|
|
bool ret = true;
|
|
switch (val_type_rt) {
|
|
case VALUE_TYPE_I32:
|
|
out->kind = WASM_I32;
|
|
out->of.i32 = *((int32 *)data);
|
|
break;
|
|
case VALUE_TYPE_F32:
|
|
out->kind = WASM_F32;
|
|
out->of.f32 = *((float32 *)data);
|
|
break;
|
|
case VALUE_TYPE_I64:
|
|
out->kind = WASM_I64;
|
|
out->of.i64 = *((int64 *)data);
|
|
break;
|
|
case VALUE_TYPE_F64:
|
|
out->kind = WASM_F64;
|
|
out->of.f64 = *((float64 *)data);
|
|
break;
|
|
#if WASM_ENABLE_REF_TYPES != 0
|
|
case VALUE_TYPE_EXTERNREF:
|
|
out->kind = WASM_ANYREF;
|
|
if (NULL_REF == *(uint32 *)data) {
|
|
out->of.ref = NULL;
|
|
}
|
|
else {
|
|
ret = wasm_externref_ref2obj(*(uint32 *)data,
|
|
(void **)&out->of.ref);
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
LOG_WARNING("unexpected value type %d", val_type_rt);
|
|
ret = false;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool
|
|
wasm_val_to_rt_val(WASMModuleInstanceCommon *inst_comm_rt, uint8 val_type_rt,
|
|
const wasm_val_t *v, uint8 *data)
|
|
{
|
|
bool ret = true;
|
|
switch (val_type_rt) {
|
|
case VALUE_TYPE_I32:
|
|
bh_assert(WASM_I32 == v->kind);
|
|
*((int32 *)data) = v->of.i32;
|
|
break;
|
|
case VALUE_TYPE_F32:
|
|
bh_assert(WASM_F32 == v->kind);
|
|
*((float32 *)data) = v->of.f32;
|
|
break;
|
|
case VALUE_TYPE_I64:
|
|
bh_assert(WASM_I64 == v->kind);
|
|
*((int64 *)data) = v->of.i64;
|
|
break;
|
|
case VALUE_TYPE_F64:
|
|
bh_assert(WASM_F64 == v->kind);
|
|
*((float64 *)data) = v->of.f64;
|
|
break;
|
|
#if WASM_ENABLE_REF_TYPES != 0
|
|
case VALUE_TYPE_EXTERNREF:
|
|
bh_assert(WASM_ANYREF == v->kind);
|
|
ret =
|
|
wasm_externref_obj2ref(inst_comm_rt, v->of.ref, (uint32 *)data);
|
|
break;
|
|
#endif
|
|
default:
|
|
LOG_WARNING("unexpected value type %d", val_type_rt);
|
|
ret = false;
|
|
break;
|
|
}
|
|
|
|
(void)inst_comm_rt;
|
|
return ret;
|
|
}
|
|
|
|
wasm_ref_t *
|
|
wasm_ref_new_internal(wasm_store_t *store, enum wasm_reference_kind kind,
|
|
uint32 ref_idx_rt, WASMModuleInstanceCommon *inst_comm_rt)
|
|
{
|
|
wasm_ref_t *ref;
|
|
|
|
if (!store) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(ref = malloc_internal(sizeof(wasm_ref_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
ref->store = store;
|
|
ref->kind = kind;
|
|
ref->ref_idx_rt = ref_idx_rt;
|
|
ref->inst_comm_rt = inst_comm_rt;
|
|
|
|
/* workaround */
|
|
if (WASM_REF_foreign == kind) {
|
|
wasm_foreign_t *foreign;
|
|
|
|
if (!(bh_vector_get(ref->store->foreigns, ref->ref_idx_rt, &foreign))
|
|
|| !foreign) {
|
|
wasm_runtime_free(ref);
|
|
return NULL;
|
|
}
|
|
|
|
foreign->ref_cnt++;
|
|
}
|
|
/* others doesn't include ref counters */
|
|
|
|
return ref;
|
|
}
|
|
|
|
own wasm_ref_t *
|
|
wasm_ref_copy(const wasm_ref_t *src)
|
|
{
|
|
if (!src)
|
|
return NULL;
|
|
|
|
/* host_info are different in wasm_ref_t(s) */
|
|
return wasm_ref_new_internal(src->store, src->kind, src->ref_idx_rt,
|
|
src->inst_comm_rt);
|
|
}
|
|
|
|
#define DELETE_HOST_INFO(obj) \
|
|
if (obj->host_info.info) { \
|
|
if (obj->host_info.finalizer) { \
|
|
obj->host_info.finalizer(obj->host_info.info); \
|
|
} \
|
|
}
|
|
|
|
void
|
|
wasm_ref_delete(own wasm_ref_t *ref)
|
|
{
|
|
if (!ref || !ref->store)
|
|
return;
|
|
|
|
DELETE_HOST_INFO(ref);
|
|
|
|
if (WASM_REF_foreign == ref->kind) {
|
|
wasm_foreign_t *foreign = NULL;
|
|
|
|
if (bh_vector_get(ref->store->foreigns, ref->ref_idx_rt, &foreign)
|
|
&& foreign) {
|
|
wasm_foreign_delete(foreign);
|
|
}
|
|
}
|
|
|
|
wasm_runtime_free(ref);
|
|
}
|
|
|
|
#define WASM_DEFINE_REF_BASE(name) \
|
|
bool wasm_##name##_same(const wasm_##name##_t *o1, \
|
|
const wasm_##name##_t *o2) \
|
|
{ \
|
|
return (!o1 && !o2) ? true \
|
|
: (!o1 || !o2) ? false \
|
|
: (o1->kind != o2->kind) \
|
|
? false \
|
|
: o1->name##_idx_rt == o2->name##_idx_rt; \
|
|
} \
|
|
\
|
|
void *wasm_##name##_get_host_info(const wasm_##name##_t *obj) \
|
|
{ \
|
|
return obj ? obj->host_info.info : NULL; \
|
|
} \
|
|
\
|
|
void wasm_##name##_set_host_info(wasm_##name##_t *obj, void *host_info) \
|
|
{ \
|
|
if (obj) { \
|
|
obj->host_info.info = host_info; \
|
|
obj->host_info.finalizer = NULL; \
|
|
} \
|
|
} \
|
|
\
|
|
void wasm_##name##_set_host_info_with_finalizer( \
|
|
wasm_##name##_t *obj, void *host_info, void (*finalizer)(void *)) \
|
|
{ \
|
|
if (obj) { \
|
|
obj->host_info.info = host_info; \
|
|
obj->host_info.finalizer = finalizer; \
|
|
} \
|
|
}
|
|
|
|
#define WASM_DEFINE_REF(name) \
|
|
WASM_DEFINE_REF_BASE(name) \
|
|
\
|
|
wasm_ref_t *wasm_##name##_as_ref(wasm_##name##_t *name) \
|
|
{ \
|
|
if (!name) { \
|
|
return NULL; \
|
|
} \
|
|
\
|
|
return wasm_ref_new_internal(name->store, WASM_REF_##name, \
|
|
name->name##_idx_rt, name->inst_comm_rt); \
|
|
} \
|
|
\
|
|
const wasm_ref_t *wasm_##name##_as_ref_const(const wasm_##name##_t *name) \
|
|
{ \
|
|
if (!name) { \
|
|
return NULL; \
|
|
} \
|
|
\
|
|
return wasm_ref_new_internal(name->store, WASM_REF_##name, \
|
|
name->name##_idx_rt, name->inst_comm_rt); \
|
|
} \
|
|
\
|
|
wasm_##name##_t *wasm_ref_as_##name(wasm_ref_t *ref) \
|
|
{ \
|
|
if (!ref || WASM_REF_##name != ref->kind) { \
|
|
return NULL; \
|
|
} \
|
|
\
|
|
return wasm_##name##_new_internal(ref->store, ref->ref_idx_rt, \
|
|
ref->inst_comm_rt); \
|
|
} \
|
|
\
|
|
const wasm_##name##_t *wasm_ref_as_##name##_const(const wasm_ref_t *ref) \
|
|
{ \
|
|
if (!ref || WASM_REF_##name != ref->kind) { \
|
|
return NULL; \
|
|
} \
|
|
\
|
|
return wasm_##name##_new_internal(ref->store, ref->ref_idx_rt, \
|
|
ref->inst_comm_rt); \
|
|
}
|
|
|
|
WASM_DEFINE_REF_BASE(ref)
|
|
WASM_DEFINE_REF(foreign)
|
|
WASM_DEFINE_REF(func)
|
|
WASM_DEFINE_REF(global)
|
|
WASM_DEFINE_REF(memory)
|
|
WASM_DEFINE_REF(table)
|
|
|
|
static wasm_frame_t *
|
|
wasm_frame_new(wasm_instance_t *instance, size_t module_offset,
|
|
uint32 func_index, size_t func_offset)
|
|
{
|
|
wasm_frame_t *frame;
|
|
|
|
if (!(frame = malloc_internal(sizeof(wasm_frame_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
frame->instance = instance;
|
|
frame->module_offset = (uint32)module_offset;
|
|
frame->func_index = func_index;
|
|
frame->func_offset = (uint32)func_offset;
|
|
return frame;
|
|
}
|
|
|
|
own wasm_frame_t *
|
|
wasm_frame_copy(const wasm_frame_t *src)
|
|
{
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
return wasm_frame_new(src->instance, src->module_offset, src->func_index,
|
|
src->func_offset);
|
|
}
|
|
|
|
void
|
|
wasm_frame_delete(own wasm_frame_t *frame)
|
|
{
|
|
if (frame) {
|
|
wasm_runtime_free(frame);
|
|
}
|
|
}
|
|
|
|
struct wasm_instance_t *
|
|
wasm_frame_instance(const wasm_frame_t *frame)
|
|
{
|
|
return frame ? frame->instance : NULL;
|
|
}
|
|
|
|
size_t
|
|
wasm_frame_module_offset(const wasm_frame_t *frame)
|
|
{
|
|
return frame ? frame->module_offset : 0;
|
|
}
|
|
|
|
uint32_t
|
|
wasm_frame_func_index(const wasm_frame_t *frame)
|
|
{
|
|
return frame ? frame->func_index : 0;
|
|
}
|
|
|
|
size_t
|
|
wasm_frame_func_offset(const wasm_frame_t *frame)
|
|
{
|
|
return frame ? frame->func_offset : 0;
|
|
}
|
|
|
|
void
|
|
wasm_frame_vec_clone_internal(Vector *src, Vector *out)
|
|
{
|
|
bh_assert(src->num_elems != 0 && src->data);
|
|
|
|
bh_vector_destroy(out);
|
|
if (!bh_vector_init(out, src->num_elems, sizeof(WASMCApiFrame), false)) {
|
|
bh_vector_destroy(out);
|
|
return;
|
|
}
|
|
|
|
bh_memcpy_s(out->data, src->num_elems * sizeof(WASMCApiFrame), src->data,
|
|
src->num_elems * sizeof(WASMCApiFrame));
|
|
out->num_elems = src->num_elems;
|
|
}
|
|
|
|
static wasm_trap_t *
|
|
wasm_trap_new_internal(wasm_store_t *store,
|
|
WASMModuleInstanceCommon *inst_comm_rt,
|
|
const char *error_info, Vector *cluster_frames)
|
|
{
|
|
wasm_trap_t *trap;
|
|
#if WASM_ENABLE_DUMP_CALL_STACK != 0
|
|
wasm_instance_vec_t *instances;
|
|
wasm_instance_t *frame_instance = NULL;
|
|
uint32 i;
|
|
#endif
|
|
|
|
if (!singleton_engine)
|
|
return NULL;
|
|
|
|
if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
/* fill in message */
|
|
if (error_info && strlen(error_info) > 0) {
|
|
if (!(trap->message = malloc_internal(sizeof(wasm_byte_vec_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
wasm_name_new_from_string_nt(trap->message, error_info);
|
|
if (!trap->message->data) {
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
/* fill in frames */
|
|
#if WASM_ENABLE_DUMP_CALL_STACK != 0
|
|
trap->frames = cluster_frames
|
|
? cluster_frames
|
|
: ((WASMModuleInstance *)inst_comm_rt)->frames;
|
|
|
|
if (trap->frames) {
|
|
/* fill in instances */
|
|
instances = store->instances;
|
|
bh_assert(instances != NULL);
|
|
|
|
for (i = 0; i < instances->num_elems; i++) {
|
|
if (instances->data[i]->inst_comm_rt == inst_comm_rt) {
|
|
frame_instance = instances->data[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < trap->frames->num_elems; i++) {
|
|
(((wasm_frame_t *)trap->frames->data) + i)->instance =
|
|
frame_instance;
|
|
}
|
|
}
|
|
#else
|
|
(void)store;
|
|
(void)inst_comm_rt;
|
|
#endif /* WASM_ENABLE_DUMP_CALL_STACK != 0 */
|
|
|
|
return trap;
|
|
failed:
|
|
wasm_trap_delete(trap);
|
|
return NULL;
|
|
}
|
|
|
|
wasm_trap_t *
|
|
wasm_trap_new(wasm_store_t *store, const wasm_message_t *message)
|
|
{
|
|
wasm_trap_t *trap;
|
|
|
|
if (!store) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) {
|
|
return NULL;
|
|
}
|
|
|
|
if (message) {
|
|
INIT_VEC(trap->message, wasm_byte_vec_new, message->size,
|
|
message->data);
|
|
}
|
|
|
|
return trap;
|
|
failed:
|
|
wasm_trap_delete(trap);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
wasm_trap_delete(wasm_trap_t *trap)
|
|
{
|
|
if (!trap) {
|
|
return;
|
|
}
|
|
|
|
DEINIT_VEC(trap->message, wasm_byte_vec_delete);
|
|
/* reuse frames of WASMModuleInstance, do not free it here */
|
|
|
|
wasm_runtime_free(trap);
|
|
}
|
|
|
|
void
|
|
wasm_trap_message(const wasm_trap_t *trap, own wasm_message_t *out)
|
|
{
|
|
if (!trap || !out) {
|
|
return;
|
|
}
|
|
|
|
wasm_byte_vec_copy(out, trap->message);
|
|
}
|
|
|
|
own wasm_frame_t *
|
|
wasm_trap_origin(const wasm_trap_t *trap)
|
|
{
|
|
wasm_frame_t *latest_frame;
|
|
|
|
if (!trap || !trap->frames || !trap->frames->num_elems) {
|
|
return NULL;
|
|
}
|
|
|
|
/* first frame is the latest frame */
|
|
latest_frame = (wasm_frame_t *)trap->frames->data;
|
|
return wasm_frame_copy(latest_frame);
|
|
}
|
|
|
|
void
|
|
wasm_trap_trace(const wasm_trap_t *trap, own wasm_frame_vec_t *out)
|
|
{
|
|
uint32 i;
|
|
|
|
if (!trap || !out) {
|
|
return;
|
|
}
|
|
|
|
if (!trap->frames || !trap->frames->num_elems) {
|
|
wasm_frame_vec_new_empty(out);
|
|
return;
|
|
}
|
|
|
|
wasm_frame_vec_new_uninitialized(out, trap->frames->num_elems);
|
|
if (out->size == 0 || !out->data) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < trap->frames->num_elems; i++) {
|
|
wasm_frame_t *frame = ((wasm_frame_t *)trap->frames->data) + i;
|
|
if (!(out->data[i] =
|
|
wasm_frame_new(frame->instance, frame->module_offset,
|
|
frame->func_index, frame->func_offset))) {
|
|
goto failed;
|
|
}
|
|
out->num_elems++;
|
|
}
|
|
|
|
return;
|
|
failed:
|
|
for (i = 0; i < out->num_elems; i++) {
|
|
if (out->data[i]) {
|
|
wasm_runtime_free(out->data[i]);
|
|
}
|
|
}
|
|
|
|
wasm_runtime_free(out->data);
|
|
}
|
|
|
|
wasm_foreign_t *
|
|
wasm_foreign_new_internal(wasm_store_t *store, uint32 foreign_idx_rt,
|
|
WASMModuleInstanceCommon *inst_comm_rt)
|
|
{
|
|
wasm_foreign_t *foreign = NULL;
|
|
|
|
if (!store || !store->foreigns)
|
|
return NULL;
|
|
|
|
if (!(bh_vector_get(store->foreigns, foreign_idx_rt, &foreign))
|
|
|| !foreign) {
|
|
return NULL;
|
|
}
|
|
|
|
foreign->ref_cnt++;
|
|
(void)inst_comm_rt;
|
|
return foreign;
|
|
}
|
|
|
|
own wasm_foreign_t *
|
|
wasm_foreign_new(wasm_store_t *store)
|
|
{
|
|
wasm_foreign_t *foreign;
|
|
|
|
if (!store)
|
|
return NULL;
|
|
|
|
if (!(foreign = malloc_internal(sizeof(wasm_foreign_t))))
|
|
return NULL;
|
|
|
|
foreign->store = store;
|
|
foreign->kind = WASM_REF_foreign;
|
|
foreign->foreign_idx_rt = (uint32)bh_vector_size(store->foreigns);
|
|
if (!(bh_vector_append(store->foreigns, &foreign))) {
|
|
wasm_runtime_free(foreign);
|
|
return NULL;
|
|
}
|
|
|
|
return foreign;
|
|
}
|
|
|
|
void
|
|
wasm_foreign_delete(wasm_foreign_t *foreign)
|
|
{
|
|
if (!foreign)
|
|
return;
|
|
|
|
if (foreign->ref_cnt < 1) {
|
|
return;
|
|
}
|
|
|
|
foreign->ref_cnt--;
|
|
if (!foreign->ref_cnt) {
|
|
wasm_runtime_free(foreign);
|
|
}
|
|
}
|
|
|
|
static inline wasm_module_t *
|
|
module_ext_to_module(wasm_module_ex_t *module_ex)
|
|
{
|
|
return (wasm_module_t *)module_ex;
|
|
}
|
|
|
|
static inline wasm_module_ex_t *
|
|
module_to_module_ext(wasm_module_t *module)
|
|
{
|
|
return (wasm_module_ex_t *)module;
|
|
}
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
#define MODULE_INTERP(module_comm) ((WASMModule *)(*module_comm))
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
#define MODULE_AOT(module_comm) ((AOTModule *)(*module_comm))
|
|
#endif
|
|
|
|
#if WASM_ENABLE_WASM_CACHE != 0
|
|
static wasm_module_ex_t *
|
|
check_loaded_module(Vector *modules, char *binary_hash)
|
|
{
|
|
unsigned i;
|
|
wasm_module_ex_t *module = NULL;
|
|
|
|
for (i = 0; i < modules->num_elems; i++) {
|
|
bh_vector_get(modules, i, &module);
|
|
if (!module) {
|
|
LOG_ERROR("Unexpected failure at %d\n", __LINE__);
|
|
return NULL;
|
|
}
|
|
|
|
if (!module->ref_count)
|
|
/* deleted */
|
|
continue;
|
|
|
|
if (memcmp(module->hash, binary_hash, SHA256_DIGEST_LENGTH) == 0)
|
|
return module;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static wasm_module_ex_t *
|
|
try_reuse_loaded_module(wasm_store_t *store, char *binary_hash)
|
|
{
|
|
wasm_module_ex_t *cached = NULL;
|
|
wasm_module_ex_t *ret = NULL;
|
|
|
|
cached = check_loaded_module(&singleton_engine->modules, binary_hash);
|
|
if (!cached)
|
|
goto quit;
|
|
|
|
os_mutex_lock(&cached->lock);
|
|
if (!cached->ref_count)
|
|
goto unlock;
|
|
|
|
if (!bh_vector_append((Vector *)store->modules, &cached))
|
|
goto unlock;
|
|
|
|
cached->ref_count += 1;
|
|
ret = cached;
|
|
|
|
unlock:
|
|
os_mutex_unlock(&cached->lock);
|
|
quit:
|
|
return ret;
|
|
}
|
|
#endif /* WASM_ENABLE_WASM_CACHE != 0 */
|
|
|
|
wasm_module_t *
|
|
wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary)
|
|
{
|
|
char error_buf[128] = { 0 };
|
|
wasm_module_ex_t *module_ex = NULL;
|
|
#if WASM_ENABLE_WASM_CACHE != 0
|
|
char binary_hash[SHA256_DIGEST_LENGTH] = { 0 };
|
|
#endif
|
|
|
|
bh_assert(singleton_engine);
|
|
|
|
if (!store || !binary || binary->size == 0 || binary->size > UINT32_MAX)
|
|
goto quit;
|
|
|
|
/* whether the combination of compilation flags are compatable with the
|
|
* package type */
|
|
{
|
|
PackageType pkg_type;
|
|
pkg_type =
|
|
get_package_type((uint8 *)binary->data, (uint32)binary->size);
|
|
bool result = false;
|
|
#if WASM_ENABLE_INTERP != 0
|
|
result = (pkg_type == Wasm_Module_Bytecode);
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
result = result || (pkg_type == Wasm_Module_AoT);
|
|
#endif
|
|
if (!result) {
|
|
LOG_VERBOSE("current building isn't compatiable with the module,"
|
|
"may need recompile");
|
|
goto quit;
|
|
}
|
|
}
|
|
|
|
#if WASM_ENABLE_WASM_CACHE != 0
|
|
/* if cached */
|
|
SHA256((void *)binary->data, binary->num_elems, (uint8_t *)binary_hash);
|
|
module_ex = try_reuse_loaded_module(store, binary_hash);
|
|
if (module_ex)
|
|
return module_ext_to_module(module_ex);
|
|
#endif
|
|
|
|
WASM_C_DUMP_PROC_MEM();
|
|
|
|
module_ex = malloc_internal(sizeof(wasm_module_ex_t));
|
|
if (!module_ex)
|
|
goto quit;
|
|
|
|
module_ex->binary = malloc_internal(sizeof(wasm_byte_vec_t));
|
|
if (!module_ex->binary)
|
|
goto free_module;
|
|
|
|
wasm_byte_vec_copy(module_ex->binary, binary);
|
|
if (!module_ex->binary->data)
|
|
goto free_binary;
|
|
|
|
module_ex->module_comm_rt = wasm_runtime_load(
|
|
(uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size,
|
|
error_buf, (uint32)sizeof(error_buf));
|
|
if (!(module_ex->module_comm_rt)) {
|
|
LOG_ERROR(error_buf);
|
|
goto free_vec;
|
|
}
|
|
|
|
/* append it to a watching list in store */
|
|
if (!bh_vector_append((Vector *)store->modules, &module_ex))
|
|
goto unload;
|
|
|
|
if (os_mutex_init(&module_ex->lock) != BHT_OK)
|
|
goto remove_last;
|
|
|
|
if (!bh_vector_append(&singleton_engine->modules, &module_ex))
|
|
goto destroy_lock;
|
|
|
|
#if WASM_ENABLE_WASM_CACHE != 0
|
|
bh_memcpy_s(module_ex->hash, sizeof(module_ex->hash), binary_hash,
|
|
sizeof(binary_hash));
|
|
#endif
|
|
|
|
module_ex->ref_count = 1;
|
|
|
|
WASM_C_DUMP_PROC_MEM();
|
|
|
|
return module_ext_to_module(module_ex);
|
|
|
|
destroy_lock:
|
|
os_mutex_destroy(&module_ex->lock);
|
|
remove_last:
|
|
bh_vector_remove((Vector *)store->modules,
|
|
(uint32)(store->modules->num_elems - 1), NULL);
|
|
unload:
|
|
wasm_runtime_unload(module_ex->module_comm_rt);
|
|
free_vec:
|
|
wasm_byte_vec_delete(module_ex->binary);
|
|
free_binary:
|
|
wasm_runtime_free(module_ex->binary);
|
|
free_module:
|
|
wasm_runtime_free(module_ex);
|
|
quit:
|
|
LOG_ERROR("%s failed", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
bool
|
|
wasm_module_validate(wasm_store_t *store, const wasm_byte_vec_t *binary)
|
|
{
|
|
wasm_byte_vec_t local_binary = { 0 };
|
|
struct WASMModuleCommon *module_rt;
|
|
char error_buf[128] = { 0 };
|
|
bool ret;
|
|
|
|
bh_assert(singleton_engine);
|
|
|
|
if (!store || !binary || binary->size > UINT32_MAX) {
|
|
LOG_ERROR("%s failed", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
/* make a copy of binary */
|
|
wasm_byte_vec_copy(&local_binary, binary);
|
|
|
|
if (binary->size && !local_binary.data)
|
|
return false;
|
|
|
|
module_rt = wasm_runtime_load((uint8 *)local_binary.data,
|
|
(uint32)local_binary.size, error_buf, 128);
|
|
wasm_byte_vec_delete(&local_binary);
|
|
if (module_rt) {
|
|
wasm_runtime_unload(module_rt);
|
|
ret = true;
|
|
}
|
|
else {
|
|
ret = false;
|
|
LOG_VERBOSE(error_buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
wasm_module_delete_internal(wasm_module_t *module)
|
|
{
|
|
wasm_module_ex_t *module_ex;
|
|
|
|
if (!module) {
|
|
return;
|
|
}
|
|
|
|
module_ex = module_to_module_ext(module);
|
|
|
|
os_mutex_lock(&module_ex->lock);
|
|
|
|
/* N -> N-1 -> 0 -> UINT32_MAX */
|
|
module_ex->ref_count--;
|
|
if (module_ex->ref_count > 0) {
|
|
os_mutex_unlock(&module_ex->lock);
|
|
return;
|
|
}
|
|
|
|
DEINIT_VEC(module_ex->binary, wasm_byte_vec_delete);
|
|
|
|
if (module_ex->module_comm_rt) {
|
|
wasm_runtime_unload(module_ex->module_comm_rt);
|
|
module_ex->module_comm_rt = NULL;
|
|
}
|
|
|
|
#if WASM_ENABLE_WASM_CACHE != 0
|
|
memset(module_ex->hash, 0, sizeof(module_ex->hash));
|
|
#endif
|
|
|
|
os_mutex_unlock(&module_ex->lock);
|
|
}
|
|
|
|
void
|
|
wasm_module_delete(wasm_module_t *module)
|
|
{
|
|
/* the module will be released when releasing the store */
|
|
(void)module;
|
|
}
|
|
|
|
void
|
|
wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out)
|
|
{
|
|
uint32 i, import_func_count = 0, import_memory_count = 0,
|
|
import_global_count = 0, import_table_count = 0, import_count = 0;
|
|
wasm_byte_vec_t module_name = { 0 }, name = { 0 };
|
|
wasm_externtype_t *extern_type = NULL;
|
|
wasm_importtype_t *import_type = NULL;
|
|
|
|
if (!module || !out) {
|
|
return;
|
|
}
|
|
|
|
if (((const wasm_module_ex_t *)(module))->ref_count == 0)
|
|
return;
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if ((*module)->module_type == Wasm_Module_Bytecode) {
|
|
import_func_count = MODULE_INTERP(module)->import_function_count;
|
|
import_global_count = MODULE_INTERP(module)->import_global_count;
|
|
import_memory_count = MODULE_INTERP(module)->import_memory_count;
|
|
import_table_count = MODULE_INTERP(module)->import_table_count;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if ((*module)->module_type == Wasm_Module_AoT) {
|
|
import_func_count = MODULE_AOT(module)->import_func_count;
|
|
import_global_count = MODULE_AOT(module)->import_global_count;
|
|
import_memory_count = MODULE_AOT(module)->import_memory_count;
|
|
import_table_count = MODULE_AOT(module)->import_table_count;
|
|
}
|
|
#endif
|
|
|
|
import_count = import_func_count + import_global_count + import_table_count
|
|
+ import_memory_count;
|
|
|
|
wasm_importtype_vec_new_uninitialized(out, import_count);
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* also leads to below branch
|
|
*/
|
|
if (!out->data) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i != import_count; ++i) {
|
|
char *module_name_rt = NULL, *field_name_rt = NULL;
|
|
|
|
memset(&module_name, 0, sizeof(wasm_val_vec_t));
|
|
memset(&name, 0, sizeof(wasm_val_vec_t));
|
|
extern_type = NULL;
|
|
import_type = NULL;
|
|
|
|
if (i < import_func_count) {
|
|
wasm_functype_t *type = NULL;
|
|
WASMType *type_rt = NULL;
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if ((*module)->module_type == Wasm_Module_Bytecode) {
|
|
WASMImport *import =
|
|
MODULE_INTERP(module)->import_functions + i;
|
|
module_name_rt = import->u.names.module_name;
|
|
field_name_rt = import->u.names.field_name;
|
|
type_rt = import->u.function.func_type;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if ((*module)->module_type == Wasm_Module_AoT) {
|
|
AOTImportFunc *import = MODULE_AOT(module)->import_funcs + i;
|
|
module_name_rt = import->module_name;
|
|
field_name_rt = import->func_name;
|
|
type_rt = import->func_type;
|
|
}
|
|
#endif
|
|
|
|
if (!module_name_rt || !field_name_rt || !type_rt) {
|
|
continue;
|
|
}
|
|
|
|
if (!(type = wasm_functype_new_internal(type_rt))) {
|
|
goto failed;
|
|
}
|
|
|
|
extern_type = wasm_functype_as_externtype(type);
|
|
}
|
|
else if (i < import_func_count + import_global_count) {
|
|
wasm_globaltype_t *type = NULL;
|
|
uint8 val_type_rt = 0;
|
|
bool mutability_rt = 0;
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if ((*module)->module_type == Wasm_Module_Bytecode) {
|
|
WASMImport *import = MODULE_INTERP(module)->import_globals
|
|
+ (i - import_func_count);
|
|
module_name_rt = import->u.names.module_name;
|
|
field_name_rt = import->u.names.field_name;
|
|
val_type_rt = import->u.global.type;
|
|
mutability_rt = import->u.global.is_mutable;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if ((*module)->module_type == Wasm_Module_AoT) {
|
|
AOTImportGlobal *import = MODULE_AOT(module)->import_globals
|
|
+ (i - import_func_count);
|
|
module_name_rt = import->module_name;
|
|
field_name_rt = import->global_name;
|
|
val_type_rt = import->type;
|
|
mutability_rt = import->is_mutable;
|
|
}
|
|
#endif
|
|
|
|
if (!module_name_rt || !field_name_rt) {
|
|
continue;
|
|
}
|
|
|
|
if (!(type = wasm_globaltype_new_internal(val_type_rt,
|
|
mutability_rt))) {
|
|
goto failed;
|
|
}
|
|
|
|
extern_type = wasm_globaltype_as_externtype(type);
|
|
}
|
|
else if (i < import_func_count + import_global_count
|
|
+ import_memory_count) {
|
|
wasm_memorytype_t *type = NULL;
|
|
uint32 min_page = 0, max_page = 0;
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if ((*module)->module_type == Wasm_Module_Bytecode) {
|
|
WASMImport *import =
|
|
MODULE_INTERP(module)->import_memories
|
|
+ (i - import_func_count - import_global_count);
|
|
module_name_rt = import->u.names.module_name;
|
|
field_name_rt = import->u.names.field_name;
|
|
min_page = import->u.memory.init_page_count;
|
|
max_page = import->u.memory.max_page_count;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if ((*module)->module_type == Wasm_Module_AoT) {
|
|
AOTImportMemory *import =
|
|
MODULE_AOT(module)->import_memories
|
|
+ (i - import_func_count - import_global_count);
|
|
module_name_rt = import->module_name;
|
|
field_name_rt = import->memory_name;
|
|
min_page = import->mem_init_page_count;
|
|
max_page = import->mem_max_page_count;
|
|
}
|
|
#endif
|
|
|
|
if (!module_name_rt || !field_name_rt) {
|
|
continue;
|
|
}
|
|
|
|
if (!(type = wasm_memorytype_new_internal(min_page, max_page))) {
|
|
goto failed;
|
|
}
|
|
|
|
extern_type = wasm_memorytype_as_externtype(type);
|
|
}
|
|
else {
|
|
wasm_tabletype_t *type = NULL;
|
|
uint8 elem_type_rt = 0;
|
|
uint32 min_size = 0, max_size = 0;
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if ((*module)->module_type == Wasm_Module_Bytecode) {
|
|
WASMImport *import =
|
|
MODULE_INTERP(module)->import_tables
|
|
+ (i - import_func_count - import_global_count
|
|
- import_memory_count);
|
|
module_name_rt = import->u.names.module_name;
|
|
field_name_rt = import->u.names.field_name;
|
|
elem_type_rt = import->u.table.elem_type;
|
|
min_size = import->u.table.init_size;
|
|
max_size = import->u.table.max_size;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if ((*module)->module_type == Wasm_Module_AoT) {
|
|
AOTImportTable *import =
|
|
MODULE_AOT(module)->import_tables
|
|
+ (i - import_func_count - import_global_count
|
|
- import_memory_count);
|
|
module_name_rt = import->module_name;
|
|
field_name_rt = import->table_name;
|
|
elem_type_rt = import->elem_type;
|
|
min_size = import->table_init_size;
|
|
max_size = import->table_max_size;
|
|
}
|
|
#endif
|
|
|
|
if (!module_name_rt || !field_name_rt) {
|
|
continue;
|
|
}
|
|
|
|
if (!(type = wasm_tabletype_new_internal(elem_type_rt, min_size,
|
|
max_size))) {
|
|
goto failed;
|
|
}
|
|
|
|
extern_type = wasm_tabletype_as_externtype(type);
|
|
}
|
|
|
|
bh_assert(extern_type);
|
|
|
|
wasm_name_new_from_string_nt(&module_name, module_name_rt);
|
|
if (strlen(module_name_rt) && !module_name.data) {
|
|
goto failed;
|
|
}
|
|
|
|
wasm_name_new_from_string_nt(&name, field_name_rt);
|
|
if (strlen(field_name_rt) && !name.data) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(import_type =
|
|
wasm_importtype_new(&module_name, &name, extern_type))) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!bh_vector_append((Vector *)out, &import_type)) {
|
|
goto failed_importtype_new;
|
|
}
|
|
|
|
continue;
|
|
|
|
failed:
|
|
wasm_byte_vec_delete(&module_name);
|
|
wasm_byte_vec_delete(&name);
|
|
wasm_externtype_delete(extern_type);
|
|
failed_importtype_new:
|
|
wasm_importtype_delete(import_type);
|
|
}
|
|
}
|
|
|
|
void
|
|
wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out)
|
|
{
|
|
uint32 i, export_count = 0;
|
|
wasm_byte_vec_t name = { 0 };
|
|
wasm_externtype_t *extern_type = NULL;
|
|
wasm_exporttype_t *export_type = NULL;
|
|
|
|
if (!module || !out) {
|
|
return;
|
|
}
|
|
|
|
if (((const wasm_module_ex_t *)(module))->ref_count == 0)
|
|
return;
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if ((*module)->module_type == Wasm_Module_Bytecode) {
|
|
export_count = MODULE_INTERP(module)->export_count;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if ((*module)->module_type == Wasm_Module_AoT) {
|
|
export_count = MODULE_AOT(module)->export_count;
|
|
}
|
|
#endif
|
|
|
|
wasm_exporttype_vec_new_uninitialized(out, export_count);
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* also leads to below branch
|
|
*/
|
|
if (!out->data) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i != export_count; i++) {
|
|
WASMExport *export = NULL;
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if ((*module)->module_type == Wasm_Module_Bytecode) {
|
|
export = MODULE_INTERP(module)->exports + i;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if ((*module)->module_type == Wasm_Module_AoT) {
|
|
export = MODULE_AOT(module)->exports + i;
|
|
}
|
|
#endif
|
|
|
|
if (!export) {
|
|
continue;
|
|
}
|
|
|
|
/* byte* -> wasm_byte_vec_t */
|
|
wasm_name_new_from_string_nt(&name, export->name);
|
|
if (strlen(export->name) && !name.data) {
|
|
goto failed;
|
|
}
|
|
|
|
/* WASMExport -> (WASMType, (uint8, bool)) -> (wasm_functype_t,
|
|
* wasm_globaltype_t) -> wasm_externtype_t*/
|
|
switch (export->kind) {
|
|
case EXPORT_KIND_FUNC:
|
|
{
|
|
wasm_functype_t *type = NULL;
|
|
WASMType *type_rt;
|
|
|
|
if (!wasm_runtime_get_export_func_type(*module, export,
|
|
&type_rt)) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(type = wasm_functype_new_internal(type_rt))) {
|
|
goto failed;
|
|
}
|
|
|
|
extern_type = wasm_functype_as_externtype(type);
|
|
break;
|
|
}
|
|
case EXPORT_KIND_GLOBAL:
|
|
{
|
|
wasm_globaltype_t *type = NULL;
|
|
uint8 val_type_rt = 0;
|
|
bool mutability_rt = 0;
|
|
|
|
if (!wasm_runtime_get_export_global_type(
|
|
*module, export, &val_type_rt, &mutability_rt)) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(type = wasm_globaltype_new_internal(val_type_rt,
|
|
mutability_rt))) {
|
|
goto failed;
|
|
}
|
|
|
|
extern_type = wasm_globaltype_as_externtype(type);
|
|
break;
|
|
}
|
|
case EXPORT_KIND_MEMORY:
|
|
{
|
|
wasm_memorytype_t *type = NULL;
|
|
uint32 min_page = 0, max_page = 0;
|
|
|
|
if (!wasm_runtime_get_export_memory_type(
|
|
*module, export, &min_page, &max_page)) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(type =
|
|
wasm_memorytype_new_internal(min_page, max_page))) {
|
|
goto failed;
|
|
}
|
|
|
|
extern_type = wasm_memorytype_as_externtype(type);
|
|
break;
|
|
}
|
|
case EXPORT_KIND_TABLE:
|
|
{
|
|
wasm_tabletype_t *type = NULL;
|
|
uint8 elem_type_rt = 0;
|
|
uint32 min_size = 0, max_size = 0;
|
|
|
|
if (!wasm_runtime_get_export_table_type(
|
|
*module, export, &elem_type_rt, &min_size, &max_size)) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(type = wasm_tabletype_new_internal(elem_type_rt, min_size,
|
|
max_size))) {
|
|
goto failed;
|
|
}
|
|
|
|
extern_type = wasm_tabletype_as_externtype(type);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
LOG_WARNING("%s meets unsupported type %u", __FUNCTION__,
|
|
export->kind);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!(export_type = wasm_exporttype_new(&name, extern_type))) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(bh_vector_append((Vector *)out, &export_type))) {
|
|
goto failed_exporttype_new;
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
failed:
|
|
wasm_byte_vec_delete(&name);
|
|
wasm_externtype_delete(extern_type);
|
|
failed_exporttype_new:
|
|
wasm_exporttype_delete(export_type);
|
|
wasm_exporttype_vec_delete(out);
|
|
}
|
|
|
|
#if WASM_ENABLE_JIT == 0 || WASM_ENABLE_LAZY_JIT != 0
|
|
void
|
|
wasm_module_serialize(wasm_module_t *module, own wasm_byte_vec_t *out)
|
|
{
|
|
(void)module;
|
|
(void)out;
|
|
LOG_ERROR("only supported serialization in JIT with eager compilation");
|
|
}
|
|
|
|
own wasm_module_t *
|
|
wasm_module_deserialize(wasm_store_t *module, const wasm_byte_vec_t *binary)
|
|
{
|
|
(void)module;
|
|
(void)binary;
|
|
LOG_ERROR("only supported deserialization in JIT with eager compilation");
|
|
return NULL;
|
|
}
|
|
#else
|
|
|
|
extern uint8 *
|
|
aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data,
|
|
uint32 *p_aot_file_size);
|
|
void
|
|
wasm_module_serialize(wasm_module_t *module, own wasm_byte_vec_t *out)
|
|
{
|
|
wasm_module_ex_t *module_ex;
|
|
AOTCompContext *comp_ctx;
|
|
AOTCompData *comp_data;
|
|
uint8 *aot_file_buf = NULL;
|
|
uint32 aot_file_size = 0;
|
|
|
|
if (!module || !out)
|
|
return;
|
|
|
|
if (((const wasm_module_ex_t *)(module))->ref_count == 0)
|
|
return;
|
|
|
|
module_ex = module_to_module_ext(module);
|
|
comp_ctx = ((WASMModule *)(module_ex->module_comm_rt))->comp_ctx;
|
|
comp_data = ((WASMModule *)(module_ex->module_comm_rt))->comp_data;
|
|
bh_assert(comp_ctx != NULL && comp_data != NULL);
|
|
|
|
aot_file_buf = aot_emit_aot_file_buf(comp_ctx, comp_data, &aot_file_size);
|
|
if (!aot_file_buf)
|
|
return;
|
|
|
|
wasm_byte_vec_new(out, aot_file_size, (wasm_byte_t *)aot_file_buf);
|
|
wasm_runtime_free(aot_file_buf);
|
|
return;
|
|
}
|
|
|
|
own wasm_module_t *
|
|
wasm_module_deserialize(wasm_store_t *store, const wasm_byte_vec_t *binary)
|
|
{
|
|
return wasm_module_new(store, binary);
|
|
}
|
|
#endif
|
|
|
|
wasm_module_t *
|
|
wasm_module_obtain(wasm_store_t *store, wasm_shared_module_t *shared_module)
|
|
{
|
|
wasm_module_ex_t *module_ex = NULL;
|
|
|
|
if (!store || !shared_module)
|
|
return NULL;
|
|
|
|
module_ex = (wasm_module_ex_t *)shared_module;
|
|
|
|
os_mutex_lock(&module_ex->lock);
|
|
|
|
/* deleting the module... */
|
|
if (module_ex->ref_count == 0) {
|
|
LOG_WARNING("wasm_module_obtain re-enter a module under deleting.");
|
|
os_mutex_unlock(&module_ex->lock);
|
|
return NULL;
|
|
}
|
|
|
|
/* add it to a watching list in store */
|
|
if (!bh_vector_append((Vector *)store->modules, &module_ex)) {
|
|
os_mutex_unlock(&module_ex->lock);
|
|
return NULL;
|
|
}
|
|
|
|
module_ex->ref_count++;
|
|
os_mutex_unlock(&module_ex->lock);
|
|
|
|
return (wasm_module_t *)shared_module;
|
|
}
|
|
|
|
wasm_shared_module_t *
|
|
wasm_module_share(wasm_module_t *module)
|
|
{
|
|
wasm_module_ex_t *module_ex = NULL;
|
|
|
|
if (!module)
|
|
return NULL;
|
|
|
|
module_ex = (wasm_module_ex_t *)module;
|
|
|
|
os_mutex_lock(&module_ex->lock);
|
|
|
|
/* deleting the module... */
|
|
if (module_ex->ref_count == 0) {
|
|
LOG_WARNING("wasm_module_share re-enter a module under deleting.");
|
|
os_mutex_unlock(&module_ex->lock);
|
|
return NULL;
|
|
}
|
|
|
|
module_ex->ref_count++;
|
|
|
|
os_mutex_unlock(&module_ex->lock);
|
|
|
|
return (wasm_shared_module_t *)module;
|
|
}
|
|
|
|
void
|
|
wasm_shared_module_delete(own wasm_shared_module_t *shared_module)
|
|
{
|
|
wasm_module_delete_internal((wasm_module_t *)shared_module);
|
|
}
|
|
|
|
static wasm_func_t *
|
|
wasm_func_new_basic(wasm_store_t *store, const wasm_functype_t *type,
|
|
wasm_func_callback_t func_callback)
|
|
{
|
|
wasm_func_t *func = NULL;
|
|
|
|
if (!type) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(func = malloc_internal(sizeof(wasm_func_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
func->store = store;
|
|
func->kind = WASM_EXTERN_FUNC;
|
|
func->func_idx_rt = (uint16)-1;
|
|
func->with_env = false;
|
|
func->u.cb = func_callback;
|
|
|
|
if (!(func->type = wasm_functype_copy(type))) {
|
|
goto failed;
|
|
}
|
|
func->param_count = func->type->params->num_elems;
|
|
func->result_count = func->type->results->num_elems;
|
|
|
|
RETURN_OBJ(func, wasm_func_delete)
|
|
}
|
|
|
|
static wasm_func_t *
|
|
wasm_func_new_with_env_basic(wasm_store_t *store, const wasm_functype_t *type,
|
|
wasm_func_callback_with_env_t callback, void *env,
|
|
void (*finalizer)(void *))
|
|
{
|
|
wasm_func_t *func = NULL;
|
|
|
|
if (!type) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(func = malloc_internal(sizeof(wasm_func_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
func->store = store;
|
|
func->kind = WASM_EXTERN_FUNC;
|
|
func->func_idx_rt = (uint16)-1;
|
|
func->with_env = true;
|
|
func->u.cb_env.cb = callback;
|
|
func->u.cb_env.env = env;
|
|
func->u.cb_env.finalizer = finalizer;
|
|
|
|
if (!(func->type = wasm_functype_copy(type))) {
|
|
goto failed;
|
|
}
|
|
func->param_count = func->type->params->num_elems;
|
|
func->result_count = func->type->results->num_elems;
|
|
|
|
RETURN_OBJ(func, wasm_func_delete)
|
|
}
|
|
|
|
wasm_func_t *
|
|
wasm_func_new(wasm_store_t *store, const wasm_functype_t *type,
|
|
wasm_func_callback_t callback)
|
|
{
|
|
bh_assert(singleton_engine);
|
|
if (!callback) {
|
|
return NULL;
|
|
}
|
|
return wasm_func_new_basic(store, type, callback);
|
|
}
|
|
|
|
wasm_func_t *
|
|
wasm_func_new_with_env(wasm_store_t *store, const wasm_functype_t *type,
|
|
wasm_func_callback_with_env_t callback, void *env,
|
|
void (*finalizer)(void *))
|
|
{
|
|
bh_assert(singleton_engine);
|
|
if (!callback) {
|
|
return NULL;
|
|
}
|
|
return wasm_func_new_with_env_basic(store, type, callback, env, finalizer);
|
|
}
|
|
|
|
wasm_func_t *
|
|
wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt,
|
|
WASMModuleInstanceCommon *inst_comm_rt)
|
|
{
|
|
wasm_func_t *func = NULL;
|
|
WASMType *type_rt = NULL;
|
|
|
|
bh_assert(singleton_engine);
|
|
|
|
if (!inst_comm_rt) {
|
|
return NULL;
|
|
}
|
|
|
|
func = malloc_internal(sizeof(wasm_func_t));
|
|
if (!func) {
|
|
goto failed;
|
|
}
|
|
|
|
func->kind = WASM_EXTERN_FUNC;
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
bh_assert(func_idx_rt
|
|
< ((WASMModuleInstance *)inst_comm_rt)->e->function_count);
|
|
WASMFunctionInstance *func_interp =
|
|
((WASMModuleInstance *)inst_comm_rt)->e->functions + func_idx_rt;
|
|
type_rt = func_interp->is_import_func
|
|
? func_interp->u.func_import->func_type
|
|
: func_interp->u.func->func_type;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
/* use same index to trace the function type in AOTFuncType **func_types
|
|
*/
|
|
AOTModule *module_aot =
|
|
(AOTModule *)((AOTModuleInstance *)inst_comm_rt)->module;
|
|
if (func_idx_rt < module_aot->import_func_count) {
|
|
type_rt = (module_aot->import_funcs + func_idx_rt)->func_type;
|
|
}
|
|
else {
|
|
type_rt =
|
|
module_aot->func_types[module_aot->func_type_indexes
|
|
[func_idx_rt
|
|
- module_aot->import_func_count]];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* also leads to below branch
|
|
*/
|
|
if (!type_rt) {
|
|
goto failed;
|
|
}
|
|
|
|
func->type = wasm_functype_new_internal(type_rt);
|
|
if (!func->type) {
|
|
goto failed;
|
|
}
|
|
func->param_count = func->type->params->num_elems;
|
|
func->result_count = func->type->results->num_elems;
|
|
|
|
/* will add name information when processing "exports" */
|
|
func->store = store;
|
|
func->module_name = NULL;
|
|
func->name = NULL;
|
|
func->func_idx_rt = func_idx_rt;
|
|
func->inst_comm_rt = inst_comm_rt;
|
|
return func;
|
|
|
|
failed:
|
|
LOG_DEBUG("%s failed", __FUNCTION__);
|
|
wasm_func_delete(func);
|
|
return NULL;
|
|
}
|
|
|
|
static wasm_func_t *
|
|
wasm_func_new_empty(wasm_store_t *store)
|
|
{
|
|
wasm_func_t *func = NULL;
|
|
|
|
if (!(func = malloc_internal(sizeof(wasm_func_t))))
|
|
goto failed;
|
|
|
|
func->store = store;
|
|
func->kind = WASM_EXTERN_FUNC;
|
|
|
|
RETURN_OBJ(func, wasm_func_delete)
|
|
}
|
|
|
|
void
|
|
wasm_func_delete(wasm_func_t *func)
|
|
{
|
|
if (!func) {
|
|
return;
|
|
}
|
|
|
|
if (func->type) {
|
|
wasm_functype_delete(func->type);
|
|
func->type = NULL;
|
|
}
|
|
|
|
if (func->with_env) {
|
|
if (func->u.cb_env.finalizer) {
|
|
func->u.cb_env.finalizer(func->u.cb_env.env);
|
|
func->u.cb_env.finalizer = NULL;
|
|
func->u.cb_env.env = NULL;
|
|
}
|
|
}
|
|
|
|
DELETE_HOST_INFO(func)
|
|
|
|
wasm_runtime_free(func);
|
|
}
|
|
|
|
own wasm_func_t *
|
|
wasm_func_copy(const wasm_func_t *func)
|
|
{
|
|
wasm_func_t *cloned = NULL;
|
|
|
|
if (!func) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(cloned = func->with_env ? wasm_func_new_with_env_basic(
|
|
func->store, func->type, func->u.cb_env.cb,
|
|
func->u.cb_env.env, func->u.cb_env.finalizer)
|
|
: wasm_func_new_basic(func->store, func->type,
|
|
func->u.cb))) {
|
|
goto failed;
|
|
}
|
|
|
|
cloned->func_idx_rt = func->func_idx_rt;
|
|
cloned->inst_comm_rt = func->inst_comm_rt;
|
|
|
|
RETURN_OBJ(cloned, wasm_func_delete)
|
|
}
|
|
|
|
own wasm_functype_t *
|
|
wasm_func_type(const wasm_func_t *func)
|
|
{
|
|
if (!func) {
|
|
return NULL;
|
|
}
|
|
return wasm_functype_copy(func->type);
|
|
}
|
|
|
|
static bool
|
|
params_to_argv(const wasm_val_vec_t *params,
|
|
const wasm_valtype_vec_t *param_defs, uint32 *argv,
|
|
uint32 *ptr_argc)
|
|
{
|
|
uint32 *argv_org = argv;
|
|
const wasm_val_t *param, *param_end;
|
|
|
|
bh_assert(params && params->num_elems && params->size && params->data);
|
|
|
|
param = params->data;
|
|
param_end = param + param_defs->num_elems;
|
|
|
|
for (; param < param_end; param++) {
|
|
switch (param->kind) {
|
|
case WASM_I32:
|
|
case WASM_F32:
|
|
*(int32 *)argv = param->of.i32;
|
|
argv += 1;
|
|
break;
|
|
case WASM_I64:
|
|
case WASM_F64:
|
|
*(int64 *)argv = param->of.i64;
|
|
argv += 2;
|
|
break;
|
|
break;
|
|
#if WASM_ENABLE_REF_TYPES != 0
|
|
case WASM_ANYREF:
|
|
*(uintptr_t *)argv = (uintptr_t)param->of.ref;
|
|
argv += sizeof(uintptr_t) / sizeof(uint32);
|
|
break;
|
|
#endif
|
|
default:
|
|
LOG_WARNING("unexpected parameter val type %d", param->kind);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
*ptr_argc = (uint32)(argv - argv_org);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
argv_to_results(const uint32 *argv, const wasm_valtype_vec_t *result_defs,
|
|
wasm_val_vec_t *results)
|
|
{
|
|
wasm_valtype_t **result_def, **result_def_end;
|
|
wasm_val_t *result;
|
|
|
|
bh_assert(results && results->size && results->data);
|
|
|
|
result_def = result_defs->data;
|
|
result_def_end = result_def + result_defs->num_elems;
|
|
result = results->data;
|
|
|
|
for (; result_def < result_def_end; result_def++, result++) {
|
|
result->kind = result_def[0]->kind;
|
|
switch (result->kind) {
|
|
case WASM_I32:
|
|
case WASM_F32:
|
|
result->of.i32 = *(int32 *)argv;
|
|
argv += 1;
|
|
break;
|
|
case WASM_I64:
|
|
case WASM_F64:
|
|
result->of.i64 = *(int64 *)argv;
|
|
argv += 2;
|
|
break;
|
|
#if WASM_ENABLE_REF_TYPES != 0
|
|
case WASM_ANYREF:
|
|
result->of.ref = (struct wasm_ref_t *)(*(uintptr_t *)argv);
|
|
argv += sizeof(uintptr_t) / sizeof(uint32);
|
|
break;
|
|
#endif
|
|
default:
|
|
LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__,
|
|
result->kind);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
wasm_trap_t *
|
|
wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
|
|
wasm_val_vec_t *results)
|
|
{
|
|
/* parameters count as if all are uint32 */
|
|
/* a int64 or float64 parameter means 2 */
|
|
uint32 argc = 0;
|
|
/* a parameter list and a return value list */
|
|
uint32 argv_buf[32] = { 0 }, *argv = argv_buf;
|
|
WASMFunctionInstanceCommon *func_comm_rt = NULL;
|
|
WASMExecEnv *exec_env = NULL;
|
|
size_t param_count, result_count, alloc_count;
|
|
Vector *cluster_frames = NULL;
|
|
|
|
bh_assert(func && func->type);
|
|
|
|
if (!func->inst_comm_rt) {
|
|
wasm_name_t message = { 0 };
|
|
wasm_trap_t *trap;
|
|
|
|
wasm_name_new_from_string_nt(&message,
|
|
"failed to call unlinked function");
|
|
trap = wasm_trap_new(func->store, &message);
|
|
wasm_byte_vec_delete(&message);
|
|
|
|
return trap;
|
|
}
|
|
|
|
if (func->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
#if WASM_ENABLE_INTERP != 0
|
|
func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->e->functions
|
|
+ func->func_idx_rt;
|
|
#endif
|
|
}
|
|
else if (func->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (!(func_comm_rt = func->func_comm_rt)) {
|
|
AOTModuleInstance *inst_aot =
|
|
(AOTModuleInstance *)func->inst_comm_rt;
|
|
AOTModule *module_aot = (AOTModule *)inst_aot->module;
|
|
uint32 export_i = 0, export_func_j = 0;
|
|
|
|
for (; export_i < module_aot->export_count; ++export_i) {
|
|
AOTExport *export = module_aot->exports + export_i;
|
|
if (export->kind == EXPORT_KIND_FUNC) {
|
|
if (export->index == func->func_idx_rt) {
|
|
func_comm_rt =
|
|
(AOTFunctionInstance *)inst_aot->export_functions
|
|
+ export_func_j;
|
|
((wasm_func_t *)func)->func_comm_rt = func_comm_rt;
|
|
break;
|
|
}
|
|
export_func_j++;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* also leads to below branch
|
|
*/
|
|
if (!func_comm_rt) {
|
|
goto failed;
|
|
}
|
|
|
|
param_count = wasm_func_param_arity(func);
|
|
result_count = wasm_func_result_arity(func);
|
|
|
|
alloc_count = (param_count > result_count) ? param_count : result_count;
|
|
if (alloc_count > (size_t)sizeof(argv_buf) / sizeof(uint64)) {
|
|
if (!(argv = malloc_internal(sizeof(uint64) * alloc_count))) {
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
/* copy parametes */
|
|
if (param_count
|
|
&& !params_to_argv(params, wasm_functype_params(func->type), argv,
|
|
&argc)) {
|
|
goto failed;
|
|
}
|
|
|
|
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
|
exec_env = wasm_runtime_get_exec_env_tls();
|
|
#endif
|
|
#if WASM_ENABLE_THREAD_MGR != 0
|
|
if (!exec_env) {
|
|
exec_env = wasm_clusters_search_exec_env(func->inst_comm_rt);
|
|
}
|
|
#endif
|
|
if (!exec_env) {
|
|
exec_env = wasm_runtime_get_exec_env_singleton(func->inst_comm_rt);
|
|
}
|
|
if (!exec_env) {
|
|
goto failed;
|
|
}
|
|
|
|
wasm_runtime_set_exception(func->inst_comm_rt, NULL);
|
|
if (!wasm_runtime_call_wasm(exec_env, func_comm_rt, argc, argv)) {
|
|
if (wasm_runtime_get_exception(func->inst_comm_rt)) {
|
|
LOG_DEBUG(wasm_runtime_get_exception(func->inst_comm_rt));
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
/* copy results */
|
|
if (result_count) {
|
|
if (!argv_to_results(argv, wasm_functype_results(func->type),
|
|
results)) {
|
|
goto failed;
|
|
}
|
|
results->num_elems = result_count;
|
|
results->size = result_count;
|
|
}
|
|
|
|
if (argv != argv_buf)
|
|
wasm_runtime_free(argv);
|
|
return NULL;
|
|
|
|
failed:
|
|
if (argv != argv_buf)
|
|
wasm_runtime_free(argv);
|
|
|
|
#if WASM_ENABLE_DUMP_CALL_STACK != 0 && WASM_ENABLE_THREAD_MGR != 0
|
|
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
|
cluster_frames = &cluster->exception_frames;
|
|
wasm_cluster_traverse_lock(exec_env);
|
|
#endif
|
|
|
|
wasm_trap_t *trap = wasm_trap_new_internal(
|
|
func->store, func->inst_comm_rt,
|
|
wasm_runtime_get_exception(func->inst_comm_rt), cluster_frames);
|
|
|
|
#if WASM_ENABLE_DUMP_CALL_STACK != 0 && WASM_ENABLE_THREAD_MGR != 0
|
|
wasm_cluster_traverse_unlock(exec_env);
|
|
#endif
|
|
return trap;
|
|
}
|
|
|
|
size_t
|
|
wasm_func_param_arity(const wasm_func_t *func)
|
|
{
|
|
return func->param_count;
|
|
}
|
|
|
|
size_t
|
|
wasm_func_result_arity(const wasm_func_t *func)
|
|
{
|
|
return func->result_count;
|
|
}
|
|
|
|
wasm_global_t *
|
|
wasm_global_new(wasm_store_t *store, const wasm_globaltype_t *global_type,
|
|
const wasm_val_t *init)
|
|
{
|
|
wasm_global_t *global = NULL;
|
|
|
|
bh_assert(singleton_engine);
|
|
|
|
if (!global_type || !init) {
|
|
goto failed;
|
|
}
|
|
|
|
global = malloc_internal(sizeof(wasm_global_t));
|
|
if (!global) {
|
|
goto failed;
|
|
}
|
|
|
|
global->store = store;
|
|
global->kind = WASM_EXTERN_GLOBAL;
|
|
global->type = wasm_globaltype_copy(global_type);
|
|
if (!global->type) {
|
|
goto failed;
|
|
}
|
|
|
|
global->init = malloc_internal(sizeof(wasm_val_t));
|
|
if (!global->init) {
|
|
goto failed;
|
|
}
|
|
|
|
wasm_val_copy(global->init, init);
|
|
/* TODO: how to check if above is failed */
|
|
|
|
return global;
|
|
|
|
failed:
|
|
LOG_DEBUG("%s failed", __FUNCTION__);
|
|
wasm_global_delete(global);
|
|
return NULL;
|
|
}
|
|
|
|
static wasm_global_t *
|
|
wasm_global_new_empty(wasm_store_t *store)
|
|
{
|
|
wasm_global_t *global = NULL;
|
|
|
|
global = malloc_internal(sizeof(wasm_global_t));
|
|
if (!global)
|
|
goto failed;
|
|
|
|
global->store = store;
|
|
global->kind = WASM_EXTERN_GLOBAL;
|
|
|
|
return global;
|
|
failed:
|
|
LOG_DEBUG("%s failed", __FUNCTION__);
|
|
wasm_global_delete(global);
|
|
return NULL;
|
|
}
|
|
|
|
/* almost same with wasm_global_new */
|
|
wasm_global_t *
|
|
wasm_global_copy(const wasm_global_t *src)
|
|
{
|
|
wasm_global_t *global = NULL;
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
global = malloc_internal(sizeof(wasm_global_t));
|
|
if (!global) {
|
|
goto failed;
|
|
}
|
|
|
|
global->kind = WASM_EXTERN_GLOBAL;
|
|
global->type = wasm_globaltype_copy(src->type);
|
|
if (!global->type) {
|
|
goto failed;
|
|
}
|
|
|
|
global->init = malloc_internal(sizeof(wasm_val_t));
|
|
if (!global->init) {
|
|
goto failed;
|
|
}
|
|
|
|
wasm_val_copy(global->init, src->init);
|
|
|
|
global->global_idx_rt = src->global_idx_rt;
|
|
global->inst_comm_rt = src->inst_comm_rt;
|
|
|
|
return global;
|
|
|
|
failed:
|
|
LOG_DEBUG("%s failed", __FUNCTION__);
|
|
wasm_global_delete(global);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
wasm_global_delete(wasm_global_t *global)
|
|
{
|
|
if (!global) {
|
|
return;
|
|
}
|
|
|
|
if (global->init) {
|
|
wasm_val_delete(global->init);
|
|
global->init = NULL;
|
|
}
|
|
|
|
if (global->type) {
|
|
wasm_globaltype_delete(global->type);
|
|
global->type = NULL;
|
|
}
|
|
|
|
DELETE_HOST_INFO(global)
|
|
|
|
wasm_runtime_free(global);
|
|
}
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
static bool
|
|
interp_global_set(const WASMModuleInstance *inst_interp, uint16 global_idx_rt,
|
|
const wasm_val_t *v)
|
|
{
|
|
const WASMGlobalInstance *global_interp =
|
|
inst_interp->e->globals + global_idx_rt;
|
|
uint8 val_type_rt = global_interp->type;
|
|
#if WASM_ENABLE_MULTI_MODULE != 0
|
|
uint8 *data = global_interp->import_global_inst
|
|
? global_interp->import_module_inst->global_data
|
|
+ global_interp->import_global_inst->data_offset
|
|
: inst_interp->global_data + global_interp->data_offset;
|
|
#else
|
|
uint8 *data = inst_interp->global_data + global_interp->data_offset;
|
|
#endif
|
|
|
|
return wasm_val_to_rt_val((WASMModuleInstanceCommon *)inst_interp,
|
|
val_type_rt, v, data);
|
|
}
|
|
|
|
static bool
|
|
interp_global_get(const WASMModuleInstance *inst_interp, uint16 global_idx_rt,
|
|
wasm_val_t *out)
|
|
{
|
|
WASMGlobalInstance *global_interp = inst_interp->e->globals + global_idx_rt;
|
|
uint8 val_type_rt = global_interp->type;
|
|
#if WASM_ENABLE_MULTI_MODULE != 0
|
|
uint8 *data = global_interp->import_global_inst
|
|
? global_interp->import_module_inst->global_data
|
|
+ global_interp->import_global_inst->data_offset
|
|
: inst_interp->global_data + global_interp->data_offset;
|
|
#else
|
|
uint8 *data = inst_interp->global_data + global_interp->data_offset;
|
|
#endif
|
|
|
|
return rt_val_to_wasm_val(data, val_type_rt, out);
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
static bool
|
|
aot_global_set(const AOTModuleInstance *inst_aot, uint16 global_idx_rt,
|
|
const wasm_val_t *v)
|
|
{
|
|
AOTModule *module_aot = (AOTModule *)inst_aot->module;
|
|
uint8 val_type_rt = 0;
|
|
uint32 data_offset = 0;
|
|
void *data = NULL;
|
|
|
|
if (global_idx_rt < module_aot->import_global_count) {
|
|
data_offset = module_aot->import_globals[global_idx_rt].data_offset;
|
|
val_type_rt = module_aot->import_globals[global_idx_rt].type;
|
|
}
|
|
else {
|
|
data_offset =
|
|
module_aot->globals[global_idx_rt - module_aot->import_global_count]
|
|
.data_offset;
|
|
val_type_rt =
|
|
module_aot->globals[global_idx_rt - module_aot->import_global_count]
|
|
.type;
|
|
}
|
|
|
|
data = (void *)(inst_aot->global_data + data_offset);
|
|
return wasm_val_to_rt_val((WASMModuleInstanceCommon *)inst_aot, val_type_rt,
|
|
v, data);
|
|
}
|
|
|
|
static bool
|
|
aot_global_get(const AOTModuleInstance *inst_aot, uint16 global_idx_rt,
|
|
wasm_val_t *out)
|
|
{
|
|
AOTModule *module_aot = (AOTModule *)inst_aot->module;
|
|
uint8 val_type_rt = 0;
|
|
uint32 data_offset = 0;
|
|
uint8 *data = NULL;
|
|
|
|
if (global_idx_rt < module_aot->import_global_count) {
|
|
data_offset = module_aot->import_globals[global_idx_rt].data_offset;
|
|
val_type_rt = module_aot->import_globals[global_idx_rt].type;
|
|
}
|
|
else {
|
|
data_offset =
|
|
module_aot->globals[global_idx_rt - module_aot->import_global_count]
|
|
.data_offset;
|
|
val_type_rt =
|
|
module_aot->globals[global_idx_rt - module_aot->import_global_count]
|
|
.type;
|
|
}
|
|
|
|
data = inst_aot->global_data + data_offset;
|
|
return rt_val_to_wasm_val(data, val_type_rt, out);
|
|
}
|
|
#endif
|
|
|
|
void
|
|
wasm_global_set(wasm_global_t *global, const wasm_val_t *v)
|
|
{
|
|
if (!global || !v || !global->inst_comm_rt) {
|
|
return;
|
|
}
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (global->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
(void)interp_global_set((WASMModuleInstance *)global->inst_comm_rt,
|
|
global->global_idx_rt, v);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (global->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
(void)aot_global_set((AOTModuleInstance *)global->inst_comm_rt,
|
|
global->global_idx_rt, v);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void
|
|
wasm_global_get(const wasm_global_t *global, wasm_val_t *out)
|
|
{
|
|
if (!global || !out) {
|
|
return;
|
|
}
|
|
|
|
if (!global->inst_comm_rt) {
|
|
return;
|
|
}
|
|
|
|
memset(out, 0, sizeof(wasm_val_t));
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (global->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
(void)interp_global_get((WASMModuleInstance *)global->inst_comm_rt,
|
|
global->global_idx_rt, out);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (global->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
(void)aot_global_get((AOTModuleInstance *)global->inst_comm_rt,
|
|
global->global_idx_rt, out);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
UNREACHABLE();
|
|
}
|
|
|
|
wasm_global_t *
|
|
wasm_global_new_internal(wasm_store_t *store, uint16 global_idx_rt,
|
|
WASMModuleInstanceCommon *inst_comm_rt)
|
|
{
|
|
wasm_global_t *global = NULL;
|
|
uint8 val_type_rt = 0;
|
|
bool is_mutable = 0;
|
|
bool init = false;
|
|
|
|
bh_assert(singleton_engine);
|
|
|
|
if (!inst_comm_rt) {
|
|
return NULL;
|
|
}
|
|
|
|
global = malloc_internal(sizeof(wasm_global_t));
|
|
if (!global) {
|
|
goto failed;
|
|
}
|
|
|
|
global->store = store;
|
|
global->kind = WASM_EXTERN_GLOBAL;
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
WASMGlobalInstance *global_interp =
|
|
((WASMModuleInstance *)inst_comm_rt)->e->globals + global_idx_rt;
|
|
val_type_rt = global_interp->type;
|
|
is_mutable = global_interp->is_mutable;
|
|
init = true;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt;
|
|
AOTModule *module_aot = (AOTModule *)inst_aot->module;
|
|
|
|
init = true;
|
|
|
|
if (global_idx_rt < module_aot->import_global_count) {
|
|
AOTImportGlobal *global_import_aot =
|
|
module_aot->import_globals + global_idx_rt;
|
|
val_type_rt = global_import_aot->type;
|
|
is_mutable = global_import_aot->is_mutable;
|
|
}
|
|
else {
|
|
AOTGlobal *global_aot =
|
|
module_aot->globals
|
|
+ (global_idx_rt - module_aot->import_global_count);
|
|
val_type_rt = global_aot->type;
|
|
is_mutable = global_aot->is_mutable;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
if (!init) {
|
|
goto failed;
|
|
}
|
|
|
|
global->type = wasm_globaltype_new_internal(val_type_rt, is_mutable);
|
|
if (!global->type) {
|
|
goto failed;
|
|
}
|
|
|
|
global->init = malloc_internal(sizeof(wasm_val_t));
|
|
if (!global->init) {
|
|
goto failed;
|
|
}
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
interp_global_get((WASMModuleInstance *)inst_comm_rt, global_idx_rt,
|
|
global->init);
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
aot_global_get((AOTModuleInstance *)inst_comm_rt, global_idx_rt,
|
|
global->init);
|
|
}
|
|
#endif
|
|
|
|
global->inst_comm_rt = inst_comm_rt;
|
|
global->global_idx_rt = global_idx_rt;
|
|
|
|
return global;
|
|
|
|
failed:
|
|
LOG_DEBUG("%s failed", __FUNCTION__);
|
|
wasm_global_delete(global);
|
|
return NULL;
|
|
}
|
|
|
|
wasm_globaltype_t *
|
|
wasm_global_type(const wasm_global_t *global)
|
|
{
|
|
if (!global) {
|
|
return NULL;
|
|
}
|
|
return wasm_globaltype_copy(global->type);
|
|
}
|
|
|
|
static wasm_table_t *
|
|
wasm_table_new_basic(wasm_store_t *store, const wasm_tabletype_t *type)
|
|
{
|
|
wasm_table_t *table = NULL;
|
|
|
|
if (!(table = malloc_internal(sizeof(wasm_table_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
table->store = store;
|
|
table->kind = WASM_EXTERN_TABLE;
|
|
|
|
if (!(table->type = wasm_tabletype_copy(type))) {
|
|
goto failed;
|
|
}
|
|
|
|
RETURN_OBJ(table, wasm_table_delete);
|
|
}
|
|
|
|
wasm_table_t *
|
|
wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt,
|
|
WASMModuleInstanceCommon *inst_comm_rt)
|
|
{
|
|
wasm_table_t *table = NULL;
|
|
uint8 val_type_rt = 0;
|
|
uint32 init_size = 0, max_size = 0;
|
|
|
|
bh_assert(singleton_engine);
|
|
|
|
if (!inst_comm_rt) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(table = malloc_internal(sizeof(wasm_table_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
table->store = store;
|
|
table->kind = WASM_EXTERN_TABLE;
|
|
|
|
if (!wasm_runtime_get_table_inst_elem_type(
|
|
inst_comm_rt, table_idx_rt, &val_type_rt, &init_size, &max_size)) {
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
goto failed;
|
|
}
|
|
|
|
if (!(table->type =
|
|
wasm_tabletype_new_internal(val_type_rt, init_size, max_size))) {
|
|
goto failed;
|
|
}
|
|
|
|
table->inst_comm_rt = inst_comm_rt;
|
|
table->table_idx_rt = table_idx_rt;
|
|
|
|
RETURN_OBJ(table, wasm_table_delete);
|
|
}
|
|
|
|
/* will not actually apply this new table into the runtime */
|
|
wasm_table_t *
|
|
wasm_table_new(wasm_store_t *store, const wasm_tabletype_t *table_type,
|
|
wasm_ref_t *init)
|
|
{
|
|
wasm_table_t *table;
|
|
(void)init;
|
|
|
|
bh_assert(singleton_engine);
|
|
|
|
if ((table = wasm_table_new_basic(store, table_type))) {
|
|
table->store = store;
|
|
}
|
|
|
|
return table;
|
|
}
|
|
|
|
wasm_table_t *
|
|
wasm_table_copy(const wasm_table_t *src)
|
|
{
|
|
wasm_table_t *table;
|
|
|
|
if (!(table = wasm_table_new_basic(src->store, src->type))) {
|
|
return NULL;
|
|
}
|
|
|
|
table->table_idx_rt = src->table_idx_rt;
|
|
table->inst_comm_rt = src->inst_comm_rt;
|
|
return table;
|
|
}
|
|
|
|
void
|
|
wasm_table_delete(wasm_table_t *table)
|
|
{
|
|
if (!table) {
|
|
return;
|
|
}
|
|
|
|
if (table->type) {
|
|
wasm_tabletype_delete(table->type);
|
|
table->type = NULL;
|
|
}
|
|
|
|
DELETE_HOST_INFO(table)
|
|
|
|
wasm_runtime_free(table);
|
|
}
|
|
|
|
wasm_tabletype_t *
|
|
wasm_table_type(const wasm_table_t *table)
|
|
{
|
|
if (!table) {
|
|
return NULL;
|
|
}
|
|
return wasm_tabletype_copy(table->type);
|
|
}
|
|
|
|
own wasm_ref_t *
|
|
wasm_table_get(const wasm_table_t *table, wasm_table_size_t index)
|
|
{
|
|
uint32 ref_idx = NULL_REF;
|
|
|
|
if (!table || !table->inst_comm_rt) {
|
|
return NULL;
|
|
}
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
WASMTableInstance *table_interp =
|
|
((WASMModuleInstance *)table->inst_comm_rt)
|
|
->tables[table->table_idx_rt];
|
|
if (index >= table_interp->cur_size) {
|
|
return NULL;
|
|
}
|
|
ref_idx = table_interp->elems[index];
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (table->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt;
|
|
AOTTableInstance *table_aot = inst_aot->tables[table->table_idx_rt];
|
|
if (index >= table_aot->cur_size) {
|
|
return NULL;
|
|
}
|
|
ref_idx = table_aot->elems[index];
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* also leads to below branch
|
|
*/
|
|
if (ref_idx == NULL_REF) {
|
|
return NULL;
|
|
}
|
|
|
|
#if WASM_ENABLE_REF_TYPES != 0
|
|
if (table->type->val_type->kind == WASM_ANYREF) {
|
|
void *externref_obj;
|
|
if (!wasm_externref_ref2obj(ref_idx, &externref_obj)) {
|
|
return NULL;
|
|
}
|
|
|
|
return externref_obj;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
return wasm_ref_new_internal(table->store, WASM_REF_func, ref_idx,
|
|
table->inst_comm_rt);
|
|
}
|
|
}
|
|
|
|
bool
|
|
wasm_table_set(wasm_table_t *table, wasm_table_size_t index,
|
|
own wasm_ref_t *ref)
|
|
{
|
|
uint32 *p_ref_idx = NULL;
|
|
uint32 function_count = 0;
|
|
|
|
if (!table || !table->inst_comm_rt) {
|
|
return false;
|
|
}
|
|
|
|
if (ref
|
|
#if WASM_ENABLE_REF_TYPES != 0
|
|
&& !(WASM_REF_foreign == ref->kind
|
|
&& WASM_ANYREF == table->type->val_type->kind)
|
|
#endif
|
|
&& !(WASM_REF_func == ref->kind
|
|
&& WASM_FUNCREF == table->type->val_type->kind)) {
|
|
return false;
|
|
}
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
WASMTableInstance *table_interp =
|
|
((WASMModuleInstance *)table->inst_comm_rt)
|
|
->tables[table->table_idx_rt];
|
|
|
|
if (index >= table_interp->cur_size) {
|
|
return false;
|
|
}
|
|
|
|
p_ref_idx = table_interp->elems + index;
|
|
function_count =
|
|
((WASMModuleInstance *)table->inst_comm_rt)->e->function_count;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (table->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt;
|
|
AOTModule *module_aot = (AOTModule *)inst_aot->module;
|
|
AOTTableInstance *table_aot = inst_aot->tables[table->table_idx_rt];
|
|
|
|
if (index >= table_aot->cur_size) {
|
|
return false;
|
|
}
|
|
|
|
p_ref_idx = table_aot->elems + index;
|
|
function_count = module_aot->func_count;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
if (!p_ref_idx) {
|
|
return false;
|
|
}
|
|
|
|
#if WASM_ENABLE_REF_TYPES != 0
|
|
if (table->type->val_type->kind == WASM_ANYREF) {
|
|
return wasm_externref_obj2ref(table->inst_comm_rt, ref, p_ref_idx);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (ref) {
|
|
if (NULL_REF != ref->ref_idx_rt) {
|
|
if (ref->ref_idx_rt >= function_count) {
|
|
return false;
|
|
}
|
|
}
|
|
*p_ref_idx = ref->ref_idx_rt;
|
|
wasm_ref_delete(ref);
|
|
}
|
|
else {
|
|
*p_ref_idx = NULL_REF;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
wasm_table_size_t
|
|
wasm_table_size(const wasm_table_t *table)
|
|
{
|
|
if (!table || !table->inst_comm_rt) {
|
|
return 0;
|
|
}
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
WASMTableInstance *table_interp =
|
|
((WASMModuleInstance *)table->inst_comm_rt)
|
|
->tables[table->table_idx_rt];
|
|
return table_interp->cur_size;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (table->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt;
|
|
AOTModule *module_aot = (AOTModule *)inst_aot->module;
|
|
|
|
if (table->table_idx_rt < module_aot->import_table_count) {
|
|
AOTImportTable *table_aot =
|
|
module_aot->import_tables + table->table_idx_rt;
|
|
return table_aot->table_init_size;
|
|
}
|
|
else {
|
|
AOTTable *table_aot =
|
|
module_aot->tables
|
|
+ (table->table_idx_rt - module_aot->import_table_count);
|
|
return table_aot->table_init_size;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
wasm_table_grow(wasm_table_t *table, wasm_table_size_t delta,
|
|
own wasm_ref_t *init)
|
|
{
|
|
(void)table;
|
|
(void)delta;
|
|
(void)init;
|
|
LOG_WARNING("Calling wasm_table_grow() by host is not supported."
|
|
"Only allow growing a table via the opcode table.grow");
|
|
return false;
|
|
}
|
|
|
|
static wasm_memory_t *
|
|
wasm_memory_new_basic(wasm_store_t *store, const wasm_memorytype_t *type)
|
|
{
|
|
wasm_memory_t *memory = NULL;
|
|
|
|
if (!type) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(memory = malloc_internal(sizeof(wasm_memory_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
memory->store = store;
|
|
memory->kind = WASM_EXTERN_MEMORY;
|
|
memory->type = wasm_memorytype_copy(type);
|
|
|
|
RETURN_OBJ(memory, wasm_memory_delete)
|
|
}
|
|
|
|
wasm_memory_t *
|
|
wasm_memory_new(wasm_store_t *store, const wasm_memorytype_t *type)
|
|
{
|
|
bh_assert(singleton_engine);
|
|
return wasm_memory_new_basic(store, type);
|
|
}
|
|
|
|
wasm_memory_t *
|
|
wasm_memory_copy(const wasm_memory_t *src)
|
|
{
|
|
wasm_memory_t *dst = NULL;
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(dst = wasm_memory_new_basic(src->store, src->type))) {
|
|
goto failed;
|
|
}
|
|
|
|
dst->memory_idx_rt = src->memory_idx_rt;
|
|
dst->inst_comm_rt = src->inst_comm_rt;
|
|
|
|
RETURN_OBJ(dst, wasm_memory_delete)
|
|
}
|
|
|
|
wasm_memory_t *
|
|
wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt,
|
|
WASMModuleInstanceCommon *inst_comm_rt)
|
|
{
|
|
wasm_memory_t *memory = NULL;
|
|
uint32 min_pages = 0, max_pages = 0;
|
|
bool init_flag = false;
|
|
|
|
bh_assert(singleton_engine);
|
|
|
|
if (!inst_comm_rt) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(memory = malloc_internal(sizeof(wasm_memory_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
memory->store = store;
|
|
memory->kind = WASM_EXTERN_MEMORY;
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
WASMMemoryInstance *memory_interp =
|
|
((WASMModuleInstance *)inst_comm_rt)->memories[memory_idx_rt];
|
|
min_pages = memory_interp->cur_page_count;
|
|
max_pages = memory_interp->max_page_count;
|
|
init_flag = true;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt;
|
|
AOTModule *module_aot = (AOTModule *)inst_aot->module;
|
|
|
|
if (memory_idx_rt < module_aot->import_memory_count) {
|
|
min_pages = module_aot->import_memories->mem_init_page_count;
|
|
max_pages = module_aot->import_memories->mem_max_page_count;
|
|
}
|
|
else {
|
|
min_pages = module_aot->memories->mem_init_page_count;
|
|
max_pages = module_aot->memories->mem_max_page_count;
|
|
}
|
|
init_flag = true;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
if (!init_flag) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!(memory->type = wasm_memorytype_new_internal(min_pages, max_pages))) {
|
|
goto failed;
|
|
}
|
|
|
|
memory->inst_comm_rt = inst_comm_rt;
|
|
memory->memory_idx_rt = memory_idx_rt;
|
|
|
|
RETURN_OBJ(memory, wasm_memory_delete);
|
|
}
|
|
|
|
void
|
|
wasm_memory_delete(wasm_memory_t *memory)
|
|
{
|
|
if (!memory) {
|
|
return;
|
|
}
|
|
|
|
if (memory->type) {
|
|
wasm_memorytype_delete(memory->type);
|
|
memory->type = NULL;
|
|
}
|
|
|
|
DELETE_HOST_INFO(memory)
|
|
|
|
wasm_runtime_free(memory);
|
|
}
|
|
|
|
wasm_memorytype_t *
|
|
wasm_memory_type(const wasm_memory_t *memory)
|
|
{
|
|
if (!memory) {
|
|
return NULL;
|
|
}
|
|
|
|
return wasm_memorytype_copy(memory->type);
|
|
}
|
|
|
|
byte_t *
|
|
wasm_memory_data(wasm_memory_t *memory)
|
|
{
|
|
WASMModuleInstanceCommon *module_inst_comm;
|
|
|
|
if (!memory || !memory->inst_comm_rt) {
|
|
return NULL;
|
|
}
|
|
|
|
module_inst_comm = memory->inst_comm_rt;
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (module_inst_comm->module_type == Wasm_Module_Bytecode) {
|
|
WASMModuleInstance *module_inst =
|
|
(WASMModuleInstance *)module_inst_comm;
|
|
WASMMemoryInstance *memory_inst =
|
|
module_inst->memories[memory->memory_idx_rt];
|
|
return (byte_t *)memory_inst->memory_data;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (module_inst_comm->module_type == Wasm_Module_AoT) {
|
|
AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm;
|
|
AOTMemoryInstance *memory_inst =
|
|
((AOTMemoryInstance **)
|
|
module_inst->memories)[memory->memory_idx_rt];
|
|
return (byte_t *)memory_inst->memory_data;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
size_t
|
|
wasm_memory_data_size(const wasm_memory_t *memory)
|
|
{
|
|
WASMModuleInstanceCommon *module_inst_comm;
|
|
|
|
if (!memory || !memory->inst_comm_rt) {
|
|
return 0;
|
|
}
|
|
|
|
module_inst_comm = memory->inst_comm_rt;
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (module_inst_comm->module_type == Wasm_Module_Bytecode) {
|
|
WASMModuleInstance *module_inst =
|
|
(WASMModuleInstance *)module_inst_comm;
|
|
WASMMemoryInstance *memory_inst =
|
|
module_inst->memories[memory->memory_idx_rt];
|
|
return (size_t)memory_inst->cur_page_count
|
|
* memory_inst->num_bytes_per_page;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (module_inst_comm->module_type == Wasm_Module_AoT) {
|
|
AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm;
|
|
AOTMemoryInstance *memory_inst =
|
|
((AOTMemoryInstance **)
|
|
module_inst->memories)[memory->memory_idx_rt];
|
|
return (size_t)memory_inst->cur_page_count
|
|
* memory_inst->num_bytes_per_page;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
wasm_memory_pages_t
|
|
wasm_memory_size(const wasm_memory_t *memory)
|
|
{
|
|
WASMModuleInstanceCommon *module_inst_comm;
|
|
|
|
if (!memory || !memory->inst_comm_rt) {
|
|
return 0;
|
|
}
|
|
|
|
module_inst_comm = memory->inst_comm_rt;
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (module_inst_comm->module_type == Wasm_Module_Bytecode) {
|
|
WASMModuleInstance *module_inst =
|
|
(WASMModuleInstance *)module_inst_comm;
|
|
WASMMemoryInstance *memory_inst =
|
|
module_inst->memories[memory->memory_idx_rt];
|
|
return memory_inst->cur_page_count;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (module_inst_comm->module_type == Wasm_Module_AoT) {
|
|
AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm;
|
|
AOTMemoryInstance *memory_inst =
|
|
((AOTMemoryInstance **)
|
|
module_inst->memories)[memory->memory_idx_rt];
|
|
return memory_inst->cur_page_count;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
wasm_memory_grow(wasm_memory_t *memory, wasm_memory_pages_t delta)
|
|
{
|
|
(void)memory;
|
|
(void)delta;
|
|
LOG_WARNING("Calling wasm_memory_grow() by host is not supported."
|
|
"Only allow growing a memory via the opcode memory.grow");
|
|
return false;
|
|
}
|
|
|
|
#if WASM_ENABLE_INTERP != 0
|
|
static bool
|
|
interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp,
|
|
uint16 func_idx_rt, wasm_func_t *import)
|
|
{
|
|
WASMImport *imported_func_interp = NULL;
|
|
|
|
bh_assert(inst && module_interp && import);
|
|
bh_assert(func_idx_rt < module_interp->import_function_count);
|
|
bh_assert(WASM_EXTERN_FUNC == import->kind);
|
|
|
|
imported_func_interp = module_interp->import_functions + func_idx_rt;
|
|
bh_assert(imported_func_interp);
|
|
bh_assert(imported_func_interp->kind == IMPORT_KIND_FUNC);
|
|
|
|
/* it is a placeholder and let's skip it*/
|
|
if (!import->type)
|
|
return true;
|
|
|
|
/* type comparison */
|
|
if (!wasm_functype_same_internal(
|
|
import->type, imported_func_interp->u.function.func_type))
|
|
return false;
|
|
|
|
imported_func_interp->u.function.call_conv_wasm_c_api = true;
|
|
/* only set func_ptr_linked to avoid unlink warning during instantiation,
|
|
func_ptr_linked, with_env and env will be stored in module instance's
|
|
c_api_func_imports later and used when calling import function */
|
|
if (import->with_env)
|
|
imported_func_interp->u.function.func_ptr_linked = import->u.cb_env.cb;
|
|
else
|
|
imported_func_interp->u.function.func_ptr_linked = import->u.cb;
|
|
bh_assert(imported_func_interp->u.function.func_ptr_linked);
|
|
|
|
import->func_idx_rt = func_idx_rt;
|
|
|
|
(void)inst;
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt,
|
|
wasm_global_t *import)
|
|
{
|
|
WASMImport *imported_global_interp = NULL;
|
|
|
|
bh_assert(module_interp && import);
|
|
bh_assert(global_idx_rt < module_interp->import_global_count);
|
|
bh_assert(WASM_EXTERN_GLOBAL == import->kind);
|
|
|
|
imported_global_interp = module_interp->import_globals + global_idx_rt;
|
|
bh_assert(imported_global_interp);
|
|
bh_assert(imported_global_interp->kind == IMPORT_KIND_GLOBAL);
|
|
|
|
/* it is a placeholder and let's skip it*/
|
|
if (!import->type)
|
|
return true;
|
|
|
|
/* type comparison */
|
|
if (!cmp_val_kind_with_val_type(wasm_valtype_kind(import->type->val_type),
|
|
imported_global_interp->u.global.type))
|
|
return false;
|
|
|
|
/* set init value */
|
|
bh_assert(import->init);
|
|
switch (wasm_valtype_kind(import->type->val_type)) {
|
|
case WASM_I32:
|
|
imported_global_interp->u.global.global_data_linked.i32 =
|
|
import->init->of.i32;
|
|
break;
|
|
case WASM_I64:
|
|
imported_global_interp->u.global.global_data_linked.i64 =
|
|
import->init->of.i64;
|
|
break;
|
|
case WASM_F32:
|
|
imported_global_interp->u.global.global_data_linked.f32 =
|
|
import->init->of.f32;
|
|
break;
|
|
case WASM_F64:
|
|
imported_global_interp->u.global.global_data_linked.f64 =
|
|
import->init->of.f64;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
import->global_idx_rt = global_idx_rt;
|
|
imported_global_interp->u.global.is_linked = true;
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
interp_process_export(wasm_store_t *store,
|
|
const WASMModuleInstance *inst_interp,
|
|
wasm_extern_vec_t *externals)
|
|
{
|
|
WASMExport *exports = NULL;
|
|
WASMExport *export = NULL;
|
|
wasm_extern_t *external = NULL;
|
|
uint32 export_cnt = 0;
|
|
uint32 i = 0;
|
|
|
|
bh_assert(store && inst_interp && inst_interp->module && externals);
|
|
|
|
exports = inst_interp->module->exports;
|
|
export_cnt = inst_interp->module->export_count;
|
|
|
|
for (i = 0; i < export_cnt; ++i) {
|
|
export = exports + i;
|
|
|
|
switch (export->kind) {
|
|
case EXPORT_KIND_FUNC:
|
|
{
|
|
wasm_func_t *func;
|
|
if (!(func = wasm_func_new_internal(
|
|
store, export->index,
|
|
(WASMModuleInstanceCommon *)inst_interp))) {
|
|
goto failed;
|
|
}
|
|
|
|
external = wasm_func_as_extern(func);
|
|
break;
|
|
}
|
|
case EXPORT_KIND_GLOBAL:
|
|
{
|
|
wasm_global_t *global;
|
|
if (!(global = wasm_global_new_internal(
|
|
store, export->index,
|
|
(WASMModuleInstanceCommon *)inst_interp))) {
|
|
goto failed;
|
|
}
|
|
|
|
external = wasm_global_as_extern(global);
|
|
break;
|
|
}
|
|
case EXPORT_KIND_TABLE:
|
|
{
|
|
wasm_table_t *table;
|
|
if (!(table = wasm_table_new_internal(
|
|
store, export->index,
|
|
(WASMModuleInstanceCommon *)inst_interp))) {
|
|
goto failed;
|
|
}
|
|
|
|
external = wasm_table_as_extern(table);
|
|
break;
|
|
}
|
|
case EXPORT_KIND_MEMORY:
|
|
{
|
|
wasm_memory_t *memory;
|
|
if (!(memory = wasm_memory_new_internal(
|
|
store, export->index,
|
|
(WASMModuleInstanceCommon *)inst_interp))) {
|
|
goto failed;
|
|
}
|
|
|
|
external = wasm_memory_as_extern(memory);
|
|
break;
|
|
}
|
|
default:
|
|
LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__,
|
|
export->kind);
|
|
goto failed;
|
|
}
|
|
|
|
if (!bh_vector_append((Vector *)externals, &external)) {
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
|
|
failed:
|
|
wasm_extern_delete(external);
|
|
return false;
|
|
}
|
|
#endif /* WASM_ENABLE_INTERP */
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
static bool
|
|
aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot,
|
|
uint32 import_func_idx_rt, wasm_func_t *import)
|
|
{
|
|
AOTImportFunc *import_aot_func = NULL;
|
|
|
|
bh_assert(inst && module_aot && import);
|
|
|
|
import_aot_func = module_aot->import_funcs + import_func_idx_rt;
|
|
bh_assert(import_aot_func);
|
|
|
|
/* it is a placeholder and let's skip it*/
|
|
if (!import->type)
|
|
return true;
|
|
|
|
/* type comparison */
|
|
if (!wasm_functype_same_internal(import->type, import_aot_func->func_type))
|
|
return false;
|
|
|
|
import_aot_func->call_conv_wasm_c_api = true;
|
|
/* only set func_ptr_linked to avoid unlink warning during instantiation,
|
|
func_ptr_linked, with_env and env will be stored in module instance's
|
|
c_api_func_imports later and used when calling import function */
|
|
if (import->with_env)
|
|
import_aot_func->func_ptr_linked = import->u.cb_env.cb;
|
|
else
|
|
import_aot_func->func_ptr_linked = import->u.cb;
|
|
bh_assert(import_aot_func->func_ptr_linked);
|
|
|
|
import->func_idx_rt = import_func_idx_rt;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt,
|
|
wasm_global_t *import)
|
|
{
|
|
AOTImportGlobal *import_aot_global = NULL;
|
|
const wasm_valtype_t *val_type = NULL;
|
|
|
|
bh_assert(module_aot && import);
|
|
|
|
import_aot_global = module_aot->import_globals + global_idx_rt;
|
|
bh_assert(import_aot_global);
|
|
|
|
/* it is a placeholder and let's skip it*/
|
|
if (!import->type)
|
|
return true;
|
|
|
|
val_type = wasm_globaltype_content(import->type);
|
|
bh_assert(val_type);
|
|
|
|
if (!cmp_val_kind_with_val_type(wasm_valtype_kind(val_type),
|
|
import_aot_global->type))
|
|
return false;
|
|
|
|
bh_assert(import->init);
|
|
switch (wasm_valtype_kind(val_type)) {
|
|
case WASM_I32:
|
|
import_aot_global->global_data_linked.i32 = import->init->of.i32;
|
|
break;
|
|
case WASM_I64:
|
|
import_aot_global->global_data_linked.i64 = import->init->of.i64;
|
|
break;
|
|
case WASM_F32:
|
|
import_aot_global->global_data_linked.f32 = import->init->of.f32;
|
|
break;
|
|
case WASM_F64:
|
|
import_aot_global->global_data_linked.f64 = import->init->of.f64;
|
|
break;
|
|
default:
|
|
goto failed;
|
|
}
|
|
|
|
import->global_idx_rt = global_idx_rt;
|
|
import_aot_global->is_linked = true;
|
|
return true;
|
|
failed:
|
|
LOG_DEBUG("%s failed", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
static bool
|
|
aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot,
|
|
wasm_extern_vec_t *externals)
|
|
{
|
|
uint32 i;
|
|
wasm_extern_t *external = NULL;
|
|
AOTModule *module_aot = NULL;
|
|
|
|
bh_assert(store && inst_aot && externals);
|
|
|
|
module_aot = (AOTModule *)inst_aot->module;
|
|
bh_assert(module_aot);
|
|
|
|
for (i = 0; i < module_aot->export_count; ++i) {
|
|
AOTExport *export = module_aot->exports + i;
|
|
|
|
switch (export->kind) {
|
|
case EXPORT_KIND_FUNC:
|
|
{
|
|
wasm_func_t *func = NULL;
|
|
if (!(func = wasm_func_new_internal(
|
|
store, export->index,
|
|
(WASMModuleInstanceCommon *)inst_aot))) {
|
|
goto failed;
|
|
}
|
|
|
|
external = wasm_func_as_extern(func);
|
|
break;
|
|
}
|
|
case EXPORT_KIND_GLOBAL:
|
|
{
|
|
wasm_global_t *global = NULL;
|
|
if (!(global = wasm_global_new_internal(
|
|
store, export->index,
|
|
(WASMModuleInstanceCommon *)inst_aot))) {
|
|
goto failed;
|
|
}
|
|
|
|
external = wasm_global_as_extern(global);
|
|
break;
|
|
}
|
|
case EXPORT_KIND_TABLE:
|
|
{
|
|
wasm_table_t *table;
|
|
if (!(table = wasm_table_new_internal(
|
|
store, export->index,
|
|
(WASMModuleInstanceCommon *)inst_aot))) {
|
|
goto failed;
|
|
}
|
|
|
|
external = wasm_table_as_extern(table);
|
|
break;
|
|
}
|
|
case EXPORT_KIND_MEMORY:
|
|
{
|
|
wasm_memory_t *memory;
|
|
if (!(memory = wasm_memory_new_internal(
|
|
store, export->index,
|
|
(WASMModuleInstanceCommon *)inst_aot))) {
|
|
goto failed;
|
|
}
|
|
|
|
external = wasm_memory_as_extern(memory);
|
|
break;
|
|
}
|
|
default:
|
|
LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__,
|
|
export->kind);
|
|
goto failed;
|
|
}
|
|
|
|
if (!(external->name = malloc_internal(sizeof(wasm_byte_vec_t)))) {
|
|
goto failed;
|
|
}
|
|
|
|
wasm_name_new_from_string_nt(external->name, export->name);
|
|
if (strlen(export->name) && !external->name->data) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!bh_vector_append((Vector *)externals, &external)) {
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
|
|
failed:
|
|
wasm_extern_delete(external);
|
|
return false;
|
|
}
|
|
#endif /* WASM_ENABLE_AOT */
|
|
|
|
static bool
|
|
do_link(const wasm_instance_t *inst, const wasm_module_t *module,
|
|
const wasm_extern_vec_t *imports)
|
|
{
|
|
uint32 i, import_func_i, import_global_i;
|
|
|
|
bh_assert(inst && module);
|
|
|
|
/* we have run a module_type check before. */
|
|
|
|
for (i = 0, import_func_i = 0, import_global_i = 0; i < imports->num_elems;
|
|
i++) {
|
|
wasm_extern_t *import = imports->data[i];
|
|
|
|
if (!import) {
|
|
LOG_ERROR("imports[%d] is NULL and it is fatal\n", i);
|
|
goto failed;
|
|
}
|
|
|
|
switch (wasm_extern_kind(import)) {
|
|
case WASM_EXTERN_FUNC:
|
|
{
|
|
bool ret = false;
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if ((*module)->module_type == Wasm_Module_Bytecode) {
|
|
ret = interp_link_func(inst, MODULE_INTERP(module),
|
|
import_func_i,
|
|
wasm_extern_as_func(import));
|
|
}
|
|
#endif
|
|
#if WASM_ENABLE_AOT != 0
|
|
if ((*module)->module_type == Wasm_Module_AoT) {
|
|
ret = aot_link_func(inst, MODULE_AOT(module), import_func_i,
|
|
wasm_extern_as_func(import));
|
|
}
|
|
#endif
|
|
if (!ret) {
|
|
LOG_WARNING("link function #%d failed", import_func_i);
|
|
goto failed;
|
|
}
|
|
|
|
import_func_i++;
|
|
break;
|
|
}
|
|
case WASM_EXTERN_GLOBAL:
|
|
{
|
|
bool ret = false;
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if ((*module)->module_type == Wasm_Module_Bytecode) {
|
|
ret = interp_link_global(MODULE_INTERP(module),
|
|
import_global_i,
|
|
wasm_extern_as_global(import));
|
|
}
|
|
#endif
|
|
#if WASM_ENABLE_AOT != 0
|
|
if ((*module)->module_type == Wasm_Module_AoT) {
|
|
ret = aot_link_global(MODULE_AOT(module), import_global_i,
|
|
wasm_extern_as_global(import));
|
|
}
|
|
#endif
|
|
if (!ret) {
|
|
LOG_WARNING("link global #%d failed", import_global_i);
|
|
goto failed;
|
|
}
|
|
|
|
import_global_i++;
|
|
break;
|
|
}
|
|
case WASM_EXTERN_MEMORY:
|
|
case WASM_EXTERN_TABLE:
|
|
{
|
|
LOG_WARNING("doesn't support import memories and tables for "
|
|
"now, ignore them");
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
failed:
|
|
LOG_DEBUG("%s failed", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
wasm_instance_t *
|
|
wasm_instance_new(wasm_store_t *store, const wasm_module_t *module,
|
|
const wasm_extern_vec_t *imports, own wasm_trap_t **trap)
|
|
{
|
|
return wasm_instance_new_with_args(store, module, imports, trap,
|
|
KILOBYTE(32), KILOBYTE(32));
|
|
}
|
|
|
|
wasm_instance_t *
|
|
wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module,
|
|
const wasm_extern_vec_t *imports,
|
|
own wasm_trap_t **trap, const uint32 stack_size,
|
|
const uint32 heap_size)
|
|
{
|
|
char sub_error_buf[128] = { 0 };
|
|
char error_buf[256] = { 0 };
|
|
wasm_instance_t *instance = NULL;
|
|
CApiFuncImport *func_import = NULL, **p_func_imports = NULL;
|
|
uint32 i = 0, import_func_count = 0;
|
|
uint64 total_size;
|
|
bool build_exported = false;
|
|
|
|
bh_assert(singleton_engine);
|
|
|
|
if (!module)
|
|
return NULL;
|
|
|
|
/*
|
|
* will do the check at the end of wasm_runtime_instantiate
|
|
*/
|
|
|
|
WASM_C_DUMP_PROC_MEM();
|
|
|
|
instance = malloc_internal(sizeof(wasm_instance_t));
|
|
if (!instance) {
|
|
snprintf(sub_error_buf, sizeof(sub_error_buf),
|
|
"Failed to malloc instance");
|
|
goto failed;
|
|
}
|
|
|
|
/* executes the instantiate-time linking if provided */
|
|
if (imports) {
|
|
if (!do_link(instance, module, imports)) {
|
|
snprintf(sub_error_buf, sizeof(sub_error_buf),
|
|
"Failed to validate imports");
|
|
goto failed;
|
|
}
|
|
}
|
|
/*
|
|
* will do the linking result check at the end of wasm_runtime_instantiate
|
|
*/
|
|
|
|
instance->inst_comm_rt = wasm_runtime_instantiate(
|
|
*module, stack_size, heap_size, sub_error_buf, sizeof(sub_error_buf));
|
|
if (!instance->inst_comm_rt) {
|
|
goto failed;
|
|
}
|
|
|
|
if (!wasm_runtime_create_exec_env_singleton(instance->inst_comm_rt)) {
|
|
snprintf(sub_error_buf, sizeof(sub_error_buf),
|
|
"Failed to create exec env singleton");
|
|
goto failed;
|
|
}
|
|
|
|
/* create the c-api func import list */
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
WASMModuleInstanceExtra *e =
|
|
((WASMModuleInstance *)instance->inst_comm_rt)->e;
|
|
p_func_imports = &(e->common.c_api_func_imports);
|
|
import_func_count = MODULE_INTERP(module)->import_function_count;
|
|
}
|
|
#endif
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
AOTModuleInstanceExtra *e =
|
|
(AOTModuleInstanceExtra *)((AOTModuleInstance *)
|
|
instance->inst_comm_rt)
|
|
->e;
|
|
p_func_imports = &(e->common.c_api_func_imports);
|
|
import_func_count = MODULE_AOT(module)->import_func_count;
|
|
}
|
|
#endif
|
|
bh_assert(p_func_imports);
|
|
|
|
total_size = (uint64)sizeof(CApiFuncImport) * import_func_count;
|
|
if (total_size > 0
|
|
&& !(*p_func_imports = func_import = malloc_internal(total_size))) {
|
|
snprintf(sub_error_buf, sizeof(sub_error_buf),
|
|
"Failed to create wasm-c-api func imports");
|
|
goto failed;
|
|
}
|
|
|
|
/* fill in module_inst->e->c_api_func_imports */
|
|
for (i = 0; imports && i < imports->num_elems; i++) {
|
|
wasm_func_t *func_host = NULL;
|
|
wasm_extern_t *in = imports->data[i];
|
|
bh_assert(in);
|
|
|
|
if (wasm_extern_kind(in) != WASM_EXTERN_FUNC)
|
|
continue;
|
|
|
|
func_host = wasm_extern_as_func(in);
|
|
/* it is a placeholder and let's skip it*/
|
|
if (!func_host->type) {
|
|
func_import++;
|
|
continue;
|
|
}
|
|
|
|
func_import->with_env_arg = func_host->with_env;
|
|
if (func_host->with_env) {
|
|
func_import->func_ptr_linked = func_host->u.cb_env.cb;
|
|
func_import->env_arg = func_host->u.cb_env.env;
|
|
}
|
|
else {
|
|
func_import->func_ptr_linked = func_host->u.cb;
|
|
func_import->env_arg = NULL;
|
|
}
|
|
bh_assert(func_import->func_ptr_linked);
|
|
|
|
func_import++;
|
|
}
|
|
|
|
/* fill with inst */
|
|
for (i = 0; imports && imports->data && i < imports->num_elems; ++i) {
|
|
wasm_extern_t *import = imports->data[i];
|
|
bh_assert(import);
|
|
|
|
switch (import->kind) {
|
|
case WASM_EXTERN_FUNC:
|
|
wasm_extern_as_func(import)->inst_comm_rt =
|
|
instance->inst_comm_rt;
|
|
break;
|
|
case WASM_EXTERN_GLOBAL:
|
|
wasm_extern_as_global(import)->inst_comm_rt =
|
|
instance->inst_comm_rt;
|
|
break;
|
|
case WASM_EXTERN_MEMORY:
|
|
wasm_extern_as_memory(import)->inst_comm_rt =
|
|
instance->inst_comm_rt;
|
|
break;
|
|
case WASM_EXTERN_TABLE:
|
|
wasm_extern_as_table(import)->inst_comm_rt =
|
|
instance->inst_comm_rt;
|
|
break;
|
|
default:
|
|
snprintf(sub_error_buf, sizeof(sub_error_buf),
|
|
"Unknown import kind");
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
/* build the exports list */
|
|
#if WASM_ENABLE_INTERP != 0
|
|
if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
|
|
uint32 export_cnt = ((WASMModuleInstance *)instance->inst_comm_rt)
|
|
->module->export_count;
|
|
|
|
INIT_VEC(instance->exports, wasm_extern_vec_new_uninitialized,
|
|
export_cnt);
|
|
|
|
if (!interp_process_export(store,
|
|
(WASMModuleInstance *)instance->inst_comm_rt,
|
|
instance->exports)) {
|
|
snprintf(sub_error_buf, sizeof(sub_error_buf),
|
|
"Interpreter failed to process exports");
|
|
goto failed;
|
|
}
|
|
|
|
build_exported = true;
|
|
}
|
|
#endif
|
|
|
|
#if WASM_ENABLE_AOT != 0
|
|
if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) {
|
|
uint32 export_cnt =
|
|
((AOTModuleInstance *)instance->inst_comm_rt)->export_func_count
|
|
+ ((AOTModuleInstance *)instance->inst_comm_rt)->export_global_count
|
|
+ ((AOTModuleInstance *)instance->inst_comm_rt)->export_table_count
|
|
+ ((AOTModuleInstance *)instance->inst_comm_rt)
|
|
->export_memory_count;
|
|
|
|
INIT_VEC(instance->exports, wasm_extern_vec_new_uninitialized,
|
|
export_cnt);
|
|
|
|
if (!aot_process_export(store,
|
|
(AOTModuleInstance *)instance->inst_comm_rt,
|
|
instance->exports)) {
|
|
snprintf(sub_error_buf, sizeof(sub_error_buf),
|
|
"AOT failed to process exports");
|
|
goto failed;
|
|
}
|
|
|
|
build_exported = true;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* a wrong combination of module filetype and compilation flags
|
|
* leads to below branch
|
|
*/
|
|
if (!build_exported) {
|
|
snprintf(sub_error_buf, sizeof(sub_error_buf),
|
|
"Incorrect filetype and compilation flags");
|
|
goto failed;
|
|
}
|
|
|
|
/* add it to a watching list in store */
|
|
if (!bh_vector_append((Vector *)store->instances, &instance)) {
|
|
snprintf(sub_error_buf, sizeof(sub_error_buf),
|
|
"Failed to add to store instances");
|
|
goto failed;
|
|
}
|
|
|
|
WASM_C_DUMP_PROC_MEM();
|
|
|
|
return instance;
|
|
|
|
failed:
|
|
snprintf(error_buf, sizeof(error_buf), "%s failed: %s", __FUNCTION__,
|
|
sub_error_buf);
|
|
if (trap != NULL) {
|
|
wasm_message_t message = { 0 };
|
|
wasm_name_new_from_string_nt(&message, error_buf);
|
|
*trap = wasm_trap_new(store, &message);
|
|
wasm_byte_vec_delete(&message);
|
|
}
|
|
LOG_DEBUG(error_buf);
|
|
wasm_instance_delete_internal(instance);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
wasm_instance_delete_internal(wasm_instance_t *instance)
|
|
{
|
|
if (!instance) {
|
|
return;
|
|
}
|
|
|
|
DEINIT_VEC(instance->exports, wasm_extern_vec_delete);
|
|
|
|
if (instance->inst_comm_rt) {
|
|
wasm_runtime_deinstantiate(instance->inst_comm_rt);
|
|
instance->inst_comm_rt = NULL;
|
|
}
|
|
wasm_runtime_free(instance);
|
|
}
|
|
|
|
void
|
|
wasm_instance_delete(wasm_instance_t *inst)
|
|
{
|
|
DELETE_HOST_INFO(inst)
|
|
/* will release instance when releasing the store */
|
|
}
|
|
|
|
void
|
|
wasm_instance_exports(const wasm_instance_t *instance,
|
|
own wasm_extern_vec_t *out)
|
|
{
|
|
if (!instance || !out) {
|
|
return;
|
|
}
|
|
wasm_extern_vec_copy(out, instance->exports);
|
|
}
|
|
|
|
wasm_extern_t *
|
|
wasm_extern_copy(const wasm_extern_t *src)
|
|
{
|
|
wasm_extern_t *dst = NULL;
|
|
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
|
|
switch (wasm_extern_kind(src)) {
|
|
case WASM_EXTERN_FUNC:
|
|
dst = wasm_func_as_extern(
|
|
wasm_func_copy(wasm_extern_as_func_const(src)));
|
|
break;
|
|
case WASM_EXTERN_GLOBAL:
|
|
dst = wasm_global_as_extern(
|
|
wasm_global_copy(wasm_extern_as_global_const(src)));
|
|
break;
|
|
case WASM_EXTERN_MEMORY:
|
|
dst = wasm_memory_as_extern(
|
|
wasm_memory_copy(wasm_extern_as_memory_const(src)));
|
|
break;
|
|
case WASM_EXTERN_TABLE:
|
|
dst = wasm_table_as_extern(
|
|
wasm_table_copy(wasm_extern_as_table_const(src)));
|
|
break;
|
|
default:
|
|
LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__,
|
|
src->kind);
|
|
break;
|
|
}
|
|
|
|
if (!dst) {
|
|
goto failed;
|
|
}
|
|
|
|
return dst;
|
|
|
|
failed:
|
|
LOG_DEBUG("%s failed", __FUNCTION__);
|
|
wasm_extern_delete(dst);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
wasm_extern_delete(wasm_extern_t *external)
|
|
{
|
|
if (!external) {
|
|
return;
|
|
}
|
|
|
|
if (external->name) {
|
|
wasm_byte_vec_delete(external->name);
|
|
wasm_runtime_free(external->name);
|
|
external->name = NULL;
|
|
}
|
|
|
|
switch (wasm_extern_kind(external)) {
|
|
case WASM_EXTERN_FUNC:
|
|
wasm_func_delete(wasm_extern_as_func(external));
|
|
break;
|
|
case WASM_EXTERN_GLOBAL:
|
|
wasm_global_delete(wasm_extern_as_global(external));
|
|
break;
|
|
case WASM_EXTERN_MEMORY:
|
|
wasm_memory_delete(wasm_extern_as_memory(external));
|
|
break;
|
|
case WASM_EXTERN_TABLE:
|
|
wasm_table_delete(wasm_extern_as_table(external));
|
|
break;
|
|
default:
|
|
LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__,
|
|
external->kind);
|
|
break;
|
|
}
|
|
}
|
|
|
|
wasm_externkind_t
|
|
wasm_extern_kind(const wasm_extern_t *external)
|
|
{
|
|
if (!external) {
|
|
return WASM_ANYREF;
|
|
}
|
|
|
|
return external->kind;
|
|
}
|
|
|
|
own wasm_externtype_t *
|
|
wasm_extern_type(const wasm_extern_t *external)
|
|
{
|
|
if (!external) {
|
|
return NULL;
|
|
}
|
|
|
|
switch (wasm_extern_kind(external)) {
|
|
case WASM_EXTERN_FUNC:
|
|
return wasm_functype_as_externtype(
|
|
wasm_func_type(wasm_extern_as_func_const(external)));
|
|
case WASM_EXTERN_GLOBAL:
|
|
return wasm_globaltype_as_externtype(
|
|
wasm_global_type(wasm_extern_as_global_const(external)));
|
|
case WASM_EXTERN_MEMORY:
|
|
return wasm_memorytype_as_externtype(
|
|
wasm_memory_type(wasm_extern_as_memory_const(external)));
|
|
case WASM_EXTERN_TABLE:
|
|
return wasm_tabletype_as_externtype(
|
|
wasm_table_type(wasm_extern_as_table_const(external)));
|
|
default:
|
|
LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__,
|
|
external->kind);
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#define BASIC_FOUR_LIST(V) \
|
|
V(func) \
|
|
V(global) \
|
|
V(memory) \
|
|
V(table)
|
|
|
|
#define WASM_EXTERN_AS_OTHER(name) \
|
|
wasm_##name##_t *wasm_extern_as_##name(wasm_extern_t *external) \
|
|
{ \
|
|
return (wasm_##name##_t *)external; \
|
|
}
|
|
|
|
BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER)
|
|
#undef WASM_EXTERN_AS_OTHER
|
|
|
|
#define WASM_OTHER_AS_EXTERN(name) \
|
|
wasm_extern_t *wasm_##name##_as_extern(wasm_##name##_t *other) \
|
|
{ \
|
|
return (wasm_extern_t *)other; \
|
|
}
|
|
|
|
BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN)
|
|
#undef WASM_OTHER_AS_EXTERN
|
|
|
|
#define WASM_EXTERN_AS_OTHER_CONST(name) \
|
|
const wasm_##name##_t *wasm_extern_as_##name##_const( \
|
|
const wasm_extern_t *external) \
|
|
{ \
|
|
return (const wasm_##name##_t *)external; \
|
|
}
|
|
|
|
BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER_CONST)
|
|
#undef WASM_EXTERN_AS_OTHER_CONST
|
|
|
|
#define WASM_OTHER_AS_EXTERN_CONST(name) \
|
|
const wasm_extern_t *wasm_##name##_as_extern_const( \
|
|
const wasm_##name##_t *other) \
|
|
{ \
|
|
return (const wasm_extern_t *)other; \
|
|
}
|
|
|
|
BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN_CONST)
|
|
#undef WASM_OTHER_AS_EXTERN_CONST
|
|
|
|
wasm_extern_t *
|
|
wasm_extern_new_empty(wasm_store_t *store, wasm_externkind_t extern_kind)
|
|
{
|
|
if (extern_kind == WASM_EXTERN_FUNC)
|
|
return wasm_func_as_extern(wasm_func_new_empty(store));
|
|
|
|
if (extern_kind == WASM_EXTERN_GLOBAL)
|
|
return wasm_global_as_extern(wasm_global_new_empty(store));
|
|
|
|
LOG_ERROR("Don't support linking table and memory for now");
|
|
return NULL;
|
|
}
|