diff --git a/README.md b/README.md index 28045e26..a5a667a7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ WebAssembly Micro Runtime ========================= -[Build WAMR VM core](./doc/build_wamr.md) | [Embed WAMR](./doc/embed_wamr.md) | [Export native function](./doc/export_native_api.md) | [Build WASM applications](./doc/build_wasm_app.md) | [Samples](https://github.com/bytecodealliance/wasm-micro-runtime#samples-and-demos) +[Build WAMR VM core](./doc/build_wamr.md) | [Embed WAMR](./doc/embed_wamr.md) | [Export native function](./doc/export_native_api.md) | [Build WASM applications](./doc/build_wasm_app.md) | [Samples](https://github.com/bytecodealliance/wasm-micro-runtime#samples) **A [Bytecode Alliance][BA] project** @@ -36,6 +36,7 @@ iwasm VM core - [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) - [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) - [Multi-value](https://github.com/WebAssembly/multi-value) +- [wasm-c-api](https://github.com/WebAssembly/wasm-c-api) ### Performance and memory usage The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page. @@ -112,8 +113,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a - **[Simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default. - **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LittlevGL](https://github.com/littlevgl/) 2D user graphic library and the UI application is built into WASM application. It uses **WASI libc** and executes apps in **AoT mode** by default. - **[gui](./samples/gui/README.md)**: Moved the [LittlevGL](https://github.com/littlevgl/) library into the runtime and defined a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default. - - +- **[wasm-c-api](./samples/wasm-c-api/README.md)**: they are samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and show supported APIs. Releases and acknowledgments diff --git a/core/config.h b/core/config.h index 9dd042a5..c14eac4e 100644 --- a/core/config.h +++ b/core/config.h @@ -127,6 +127,11 @@ enum { /* WASM Interpreter labels-as-values feature */ #define WASM_ENABLE_LABELS_AS_VALUES 1 +/* Enable fast interpreter or not */ +#ifndef WASM_ENABLE_FAST_INTERP +#define WASM_ENABLE_FAST_INTERP 0 +#endif + #if WASM_ENABLE_FAST_INTERP != 0 #define WASM_ENABLE_ABS_LABEL_ADDR 1 #define WASM_DEBUG_PREPROCESSOR 0 diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c new file mode 100644 index 00000000..dc6e38a2 --- /dev/null +++ b/core/iwasm/common/wasm_c_api.c @@ -0,0 +1,2745 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_c_api_internal.h" +#include "wasm_memory.h" +#if WASM_ENABLE_INTERP != 0 +#include "wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + +#define NOT_REACHED() bh_assert(!"should not be reached") + +typedef struct wasm_module_ex_t wasm_module_ex_t; + +void +wasm_module_delete_internal(wasm_module_t *); + +void +wasm_instance_delete_internal(wasm_instance_t *); + +static void * +malloc_internal(size_t size) +{ + void *mem = NULL; + + if (size >= UINT32_MAX) { + return NULL; + } + + mem = wasm_runtime_malloc((uint32)size); + if (mem) { + memset(mem, 0, size); + } + + return mem; +} + +#define FREEIF(p) \ + if (p) { \ + wasm_runtime_free(p); \ + } + +/* Vectors */ +#define INIT_VEC(vector_p, func_prefix, size) \ + do { \ + vector_p = malloc_internal(sizeof(*(vector_p))); \ + if (!vector_p) { \ + goto failed; \ + } \ + func_prefix##_new_uninitialized(vector_p, size); \ + if (!(vector_p)->data) { \ + goto failed; \ + } \ + } while (false) + +#define DEINIT_VEC(vector_p, delete_func) \ + if ((vector_p)) { \ + if ((vector_p)->data) { \ + delete_func(vector_p); \ + } \ + wasm_runtime_free(vector_p); \ + vector_p = NULL; \ + } + +#define FREE_VEC_ELEMS(vec, del_func) \ + for (i = 0; i < (vec)->num_elems; ++i) { \ + del_func(*((vec)->data + i)); \ + *((vec)->data + i) = NULL; \ + } + +static inline void +generic_vec_init_data(Vector *out, size_t num_of_elems, size_t size_of_elem) +{ + if (!bh_vector_init(out, num_of_elems, size_of_elem)) { + memset(out, 0, sizeof(Vector)); + } + else { + memset(out->data, 0, num_of_elems * size_of_elem); + } +} + +void +wasm_byte_vec_new_uninitialized(wasm_byte_vec_t *out, size_t size) +{ + bh_assert(out); + generic_vec_init_data((Vector *)out, size, sizeof(wasm_byte_t)); +} + +void +wasm_byte_vec_copy(wasm_byte_vec_t *out, const wasm_byte_vec_t *src) +{ + uint32 len = 0; + + bh_assert(out && src); + + generic_vec_init_data((Vector *)out, src->size, src->size_of_elem); + if (!out->data) { + goto failed; + } + + len = src->size * src->size_of_elem; + bh_memcpy_s(out->data, len, src->data, len); + out->num_elems = src->num_elems; + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_byte_vec_delete(out); +} + +void +wasm_byte_vec_new(wasm_byte_vec_t *out, size_t size, const wasm_byte_t *data) +{ + size_t size_in_bytes = 0; + + bh_assert(out && data); + + generic_vec_init_data((Vector *)out, size, sizeof(wasm_byte_t)); + if (!out->data) { + goto failed; + } + + size_in_bytes = size * sizeof(wasm_byte_t); + bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); + out->num_elems = size; + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_byte_vec_delete(out); +} + +void +wasm_byte_vec_delete(wasm_byte_vec_t *byte_vec) +{ + if (byte_vec && byte_vec->data) { + bh_vector_destroy((Vector *)byte_vec); + } +} + +/* Runtime Environment */ +static void +wasm_engine_delete_internal(wasm_engine_t *engine) +{ + if (engine) { + DEINIT_VEC(engine->stores, wasm_store_vec_delete); + wasm_runtime_free(engine); + } + + wasm_runtime_destroy(); +} + +static wasm_engine_t * +wasm_engine_new_internal(mem_alloc_type_t type, + const MemAllocOption *opts, + runtime_mode_e mode) +{ + wasm_engine_t *engine = NULL; + /* init runtime */ + RuntimeInitArgs init_args = { 0 }; + init_args.mem_alloc_type = type; + + if (type == Alloc_With_Pool) { + init_args.mem_alloc_option.pool.heap_buf = opts->pool.heap_buf; + init_args.mem_alloc_option.pool.heap_size = opts->pool.heap_size; + } + else if (type == Alloc_With_Allocator) { + init_args.mem_alloc_option.allocator.malloc_func = + opts->allocator.malloc_func; + init_args.mem_alloc_option.allocator.free_func = + opts->allocator.free_func; + init_args.mem_alloc_option.allocator.realloc_func = + opts->allocator.realloc_func; + } + else { + init_args.mem_alloc_option.pool.heap_buf = NULL; + init_args.mem_alloc_option.pool.heap_size = 0; + } + + if (!wasm_runtime_full_init(&init_args)) { + goto failed; + } + +#if BH_DEBUG == 1 + bh_log_set_verbose_level(5); +#else + bh_log_set_verbose_level(3); +#endif + + /* create wasm_engine_t */ + engine = malloc_internal(sizeof(wasm_engine_t)); + if (!engine) { + goto failed; + } + + /* set running mode */ + LOG_WARNING("running under mode %d", mode); + engine->mode = mode; + + /* create wasm_store_vec_t */ + INIT_VEC(engine->stores, wasm_store_vec, 1); + + return engine; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_engine_delete_internal(engine); + return NULL; +} + +/* global engine instance */ +static wasm_engine_t *singleton_engine = NULL; + +static inline runtime_mode_e +current_runtime_mode() +{ + bh_assert(singleton_engine); + return singleton_engine->mode; +} + +wasm_engine_t * +wasm_engine_new() +{ + runtime_mode_e mode = INTERP_MODE; +#if WASM_ENABLE_INTERP == 0 && WASM_ENABLE_AOT != 0 + mode = AOT_MODE; +#endif + + if (INTERP_MODE == mode) { +#if WASM_ENABLE_INTERP == 0 + bh_assert(!"does not support INTERP_MODE. Please recompile"); +#endif + } + else { +#if WASM_ENABLE_AOT == 0 + bh_assert(!"does not support AOT_MODE. Please recompile"); +#endif + } + + if (!singleton_engine) { + singleton_engine = + wasm_engine_new_internal(Alloc_With_System_Allocator, NULL, mode); + } + return singleton_engine; +} + +wasm_engine_t * +wasm_engine_new_with_args(mem_alloc_type_t type, + const MemAllocOption *opts, + runtime_mode_e mode) +{ + if (!singleton_engine) { + singleton_engine = wasm_engine_new_internal(type, opts, mode); + } + return singleton_engine; +} + +void +wasm_engine_delete(wasm_engine_t *engine) +{ + if (engine) { + wasm_engine_delete_internal(engine); + singleton_engine = NULL; + } +} + +wasm_store_t * +wasm_store_new(wasm_engine_t *engine) +{ + wasm_store_t *store = NULL; + + bh_assert(engine && singleton_engine == engine); + + /* always return the first store */ + if (bh_vector_size((Vector *)singleton_engine->stores) > 0) { + /* + * although it is a copy of the first store, but still point to + * the wasm_store_t + */ + if (!bh_vector_get((Vector *)singleton_engine->stores, 0, &store)) { + goto failed; + } + return store; + } + + store = malloc_internal(sizeof(wasm_store_t)); + if (!store) { + goto failed; + } + + /* new a vector, and new its data */ + INIT_VEC(store->modules, wasm_module_vec, DEFAULT_VECTOR_INIT_LENGTH); + INIT_VEC(store->instances, wasm_instance_vec, DEFAULT_VECTOR_INIT_LENGTH); + + /* append to a store list of engine */ + if (!bh_vector_append((Vector *)singleton_engine->stores, &store)) { + goto failed; + } + + return store; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_store_delete(store); + return NULL; +} + +void +wasm_store_delete(wasm_store_t *store) +{ + if (!store || singleton_engine->stores->num_elems == 0) { + return; + } + + DEINIT_VEC(store->modules, wasm_module_vec_delete); + DEINIT_VEC(store->instances, wasm_instance_vec_delete); + + wasm_runtime_free(store); + bh_vector_remove((Vector *)singleton_engine->stores, 0, NULL); +} + +void +wasm_store_vec_new_uninitialized(wasm_store_vec_t *out, size_t size) +{ + bh_assert(out); + generic_vec_init_data((Vector *)out, size, sizeof(wasm_store_t *)); +} + +void +wasm_store_vec_delete(wasm_store_vec_t *store_vec) +{ + size_t i = 0; + if (!store_vec || !store_vec->data) { + return; + } + + FREE_VEC_ELEMS(store_vec, wasm_store_delete); + bh_vector_destroy((Vector *)store_vec); +} + +static inline void +check_engine_and_store(wasm_engine_t *engine, wasm_store_t *store) +{ + /* remove it if we are supporting more than one store */ + bh_assert(engine && store && engine->stores->data[0] == store); +} + +/* Type Representations */ +static wasm_valtype_t * +wasm_valtype_new_internal(uint8 val_type_rt) +{ + switch (val_type_rt) { + case VALUE_TYPE_I32: + return wasm_valtype_new_i32(); + case VALUE_TYPE_I64: + return wasm_valtype_new_i64(); + case VALUE_TYPE_F32: + return wasm_valtype_new_f32(); + case VALUE_TYPE_F64: + return wasm_valtype_new_f64(); + case VALUE_TYPE_ANY: + return wasm_valtype_new_anyref(); + default: + return NULL; + } +} + +wasm_valtype_t * +wasm_valtype_new(wasm_valkind_t kind) +{ + wasm_valtype_t *val_type = malloc_internal(sizeof(wasm_valtype_t)); + if (val_type) { + val_type->kind = kind; + } + return val_type; +} + +void +wasm_valtype_delete(wasm_valtype_t *val_type) +{ + bh_assert(val_type); + wasm_runtime_free(val_type); +} + +wasm_valtype_t * +wasm_valtype_copy(wasm_valtype_t *src) +{ + bh_assert(src); + return wasm_valtype_new(src->kind); +} + +wasm_valkind_t +wasm_valtype_kind(const wasm_valtype_t *val_type) +{ + bh_assert(val_type); + return val_type->kind; +} + +bool +wasm_valtype_same(const wasm_valtype_t *vt1, const wasm_valtype_t *vt2) +{ + if (!vt1 && !vt2) { + return true; + } + + if (!vt1 || !vt2) { + return false; + } + + return vt1->kind == vt2->kind; +} + +void +wasm_valtype_vec_new_uninitialized(wasm_valtype_vec_t *out, size_t size) +{ + bh_assert(out); + generic_vec_init_data((Vector *)out, size, sizeof(wasm_valtype_t *)); +} + +void +wasm_valtype_vec_new_empty(wasm_valtype_vec_t *out) +{ + bh_assert(out); + memset(out, 0, sizeof(wasm_valtype_vec_t)); +} + +void +wasm_valtype_vec_new(wasm_valtype_vec_t *out, + size_t size, + wasm_valtype_t *const data[]) +{ + size_t size_in_bytes = 0; + bh_assert(out && data); + generic_vec_init_data((Vector *)out, size, sizeof(wasm_valtype_t *)); + if (!out->data) { + goto failed; + } + + size_in_bytes = size * sizeof(wasm_valtype_t *); + bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); + out->num_elems = size; + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_valtype_vec_delete(out); +} + +void +wasm_valtype_vec_copy(wasm_valtype_vec_t *out, const wasm_valtype_vec_t *src) +{ + size_t i = 0; + + bh_assert(out && src); + + generic_vec_init_data((Vector *)out, src->size, src->size_of_elem); + if (!out->data) { + goto failed; + } + + /* clone every wasm_valtype_t */ + for (i = 0; i < src->num_elems; i++) { + wasm_valtype_t *cloned = wasm_valtype_copy(*(src->data + i)); + if (!cloned) { + goto failed; + } + if (!bh_vector_append((Vector *)out, &cloned)) { + goto failed; + } + } + + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_valtype_vec_delete(out); +} + +void +wasm_valtype_vec_delete(wasm_valtype_vec_t *val_type_vec) +{ + size_t i = 0; + if (!val_type_vec || !val_type_vec->data) { + return; + } + + FREE_VEC_ELEMS(val_type_vec, wasm_valtype_delete); + bh_vector_destroy((Vector *)val_type_vec); +} + +static wasm_functype_t * +wasm_functype_new_internal(WASMType *type_rt) +{ + wasm_functype_t *func_type = NULL; + uint32 i = 0; + + bh_assert(type_rt); + + func_type = malloc_internal(sizeof(wasm_functype_t)); + if (!func_type) { + goto failed; + } + + /* WASMType->types[0 : type_rt->param_count) -> func_type->params */ + INIT_VEC(func_type->params, wasm_valtype_vec, type_rt->param_count); + for (i = 0; i < type_rt->param_count; ++i) { + wasm_valtype_t *param_type = + wasm_valtype_new_internal(*(type_rt->types + i)); + if (!param_type) { + goto failed; + } + + if (!bh_vector_append((Vector *)func_type->params, ¶m_type)) { + goto failed; + } + } + + /* WASMType->types[type_rt->param_count : type_rt->result_count) -> func_type->results */ + INIT_VEC(func_type->results, wasm_valtype_vec, type_rt->result_count); + for (i = type_rt->param_count; i < type_rt->result_count; ++i) { + wasm_valtype_t *result_type = + wasm_valtype_new_internal(*(type_rt->types + i)); + if (!result_type) { + goto failed; + } + + if (!bh_vector_append((Vector *)func_type->results, &result_type)) { + goto failed; + } + } + + return func_type; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_functype_delete(func_type); + return NULL; +} + +wasm_functype_t * +wasm_functype_new(wasm_valtype_vec_t *params, wasm_valtype_vec_t *results) +{ + wasm_functype_t *func_type = NULL; + + bh_assert(params); + bh_assert(results); + + func_type = malloc_internal(sizeof(wasm_functype_t)); + if (!func_type) { + goto failed; + } + + func_type->extern_kind = WASM_EXTERN_FUNC; + + func_type->params = malloc_internal(sizeof(wasm_valtype_vec_t)); + if (!func_type->params) { + goto failed; + } + + /* transfer ownership of contents of params and results */ + bh_memcpy_s(func_type->params, sizeof(wasm_valtype_vec_t), params, + sizeof(wasm_valtype_vec_t)); + + func_type->results = malloc_internal(sizeof(wasm_valtype_vec_t)); + if (!func_type->results) { + goto failed; + } + + bh_memcpy_s(func_type->results, sizeof(wasm_valtype_vec_t), results, + sizeof(wasm_valtype_vec_t)); + + return func_type; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + FREEIF(func_type->params); + FREEIF(func_type->results); + FREEIF(func_type); + return NULL; +} + +wasm_functype_t * +wasm_functype_copy(wasm_functype_t *src) +{ + wasm_functype_t *dst = NULL; + + bh_assert(src); + + dst = malloc_internal(sizeof(wasm_functype_t)); + if (!dst) { + goto failed; + } + + dst->extern_kind = src->extern_kind; + + dst->params = malloc_internal(sizeof(wasm_valtype_vec_t)); + if (!dst->params) { + goto failed; + } + + wasm_valtype_vec_copy(dst->params, src->params); + if (!dst->params) { + goto failed; + } + + dst->results = malloc_internal(sizeof(wasm_valtype_vec_t)); + if (!dst->results) { + goto failed; + } + + wasm_valtype_vec_copy(dst->results, src->results); + if (!dst->results) { + goto failed; + } + + return dst; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_functype_delete(dst); + return NULL; +} + +void +wasm_functype_delete(wasm_functype_t *func_type) +{ + if (!func_type) { + return; + } + + if (func_type->params) { + wasm_valtype_vec_delete(func_type->params); + wasm_runtime_free(func_type->params); + func_type->params = NULL; + } + + if (func_type->results) { + wasm_valtype_vec_delete(func_type->results); + wasm_runtime_free(func_type->results); + func_type->results = NULL; + } + + wasm_runtime_free(func_type); +} + +const wasm_valtype_vec_t * +wasm_functype_params(const wasm_functype_t *func_type) +{ + bh_assert(func_type); + return func_type->params; +} + +const wasm_valtype_vec_t * +wasm_functype_results(const wasm_functype_t *func_type) +{ + bh_assert(func_type); + return func_type->results; +} + +wasm_globaltype_t * +wasm_globaltype_new(wasm_valtype_t *val_type, wasm_mutability_t mut) +{ + wasm_globaltype_t *global_type = NULL; + + bh_assert(val_type); + + global_type = malloc_internal(sizeof(wasm_globaltype_t)); + if (!global_type) { + goto failed; + } + + global_type->val_type = val_type; + global_type->mutability = mut; + + return global_type; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_globaltype_delete(global_type); + return NULL; +} + +wasm_globaltype_t * +wasm_globaltype_new_internal(uint8 val_type_rt, bool is_mutable) +{ + wasm_globaltype_t *global_type = NULL; + + global_type = malloc_internal(sizeof(wasm_globaltype_t)); + if (!global_type) { + goto failed; + } + + global_type->val_type = wasm_valtype_new_internal(val_type_rt); + if (!global_type->val_type) { + goto failed; + } + + global_type->mutability = is_mutable ? WASM_VAR : WASM_CONST; + + return global_type; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_globaltype_delete(global_type); + return NULL; +} + +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(wasm_globaltype_t *src) +{ + wasm_globaltype_t *dst = NULL; + + bh_assert(src); + + dst = malloc_internal(sizeof(wasm_globaltype_t)); + if (!dst) { + goto failed; + } + + dst->val_type = wasm_valtype_copy(src->val_type); + if (!dst->val_type) { + goto failed; + } + + dst->mutability = src->mutability; + + return dst; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_globaltype_delete(dst); + return NULL; +} + +const wasm_valtype_t * +wasm_globaltype_content(const wasm_globaltype_t *global_type) +{ + bh_assert(global_type); + return global_type->val_type; +} + +wasm_mutability_t +wasm_globaltype_mutability(const wasm_globaltype_t *global_type) +{ + bh_assert(global_type); + return global_type->mutability; +} + +bool +wasm_globaltype_same(const wasm_globaltype_t *gt1, + const wasm_globaltype_t *gt2) +{ + if (!gt1 && !gt2) { + return true; + } + + if (!gt1 || !gt2) { + return false; + } + + return wasm_valtype_same(gt1->val_type, gt2->val_type) + || gt1->mutability == gt2->mutability; +} + +wasm_tabletype_t * +wasm_tabletype_new(wasm_valtype_t *val_type, const wasm_limits_t *limits) +{ + return NULL; +} + +void +wasm_tabletype_delete(wasm_tabletype_t *table_type) +{} + +wasm_memorytype_t * +wasm_memorytype_new(const wasm_limits_t *limits) +{ + return NULL; +} + +void +wasm_memorytype_delete(wasm_memorytype_t *memory_type) +{} + +/* Runtime Objects */ + +void +wasm_val_delete(wasm_val_t *v) +{ + /* do nothing */ +} + +void +wasm_val_copy(wasm_val_t *out, const wasm_val_t *src) +{ + bh_assert(out && src); + bh_memcpy_s(out, sizeof(wasm_val_t), src, sizeof(wasm_val_t)); +} + +bool +wasm_val_same(const wasm_val_t *v1, const wasm_val_t *v2) +{ + if (!v1 && !v2) { + return true; + } + + if (!v1 || !v2) { + return false; + } + + if (v1->kind != v2->kind) { + return false; + } + + switch (v1->kind) { + case WASM_I32: + return v1->of.i32 == v2->of.i32; + case WASM_I64: + return v1->of.i64 == v2->of.i64; + case WASM_F32: + return v1->of.f32 == v2->of.f32; + case WASM_F64: + return v1->of.f64 == v2->of.f64; + case WASM_FUNCREF: + return v1->of.ref == v2->of.ref; + default: + break; + } + return false; +} + +wasm_trap_t * +wasm_trap_new(wasm_store_t *store, const wasm_message_t *message) +{ + wasm_trap_t *trap; + + bh_assert(store && message); + + trap = malloc_internal(sizeof(wasm_trap_t)); + if (!trap) { + goto failed; + } + + wasm_byte_vec_new(trap->message, message->num_elems, message->data); + if (!trap->message->data) { + goto failed; + } + + return trap; + +failed: + wasm_trap_delete(trap); + return NULL; +} + +void +wasm_trap_delete(wasm_trap_t *trap) +{ + if (!trap) { + return; + } + + if (trap->message) { + wasm_byte_vec_delete(trap->message); + } + + wasm_runtime_free(trap); +} + +void +wasm_trap_message(const wasm_trap_t *trap, wasm_message_t *out) +{ + bh_assert(trap && out); + wasm_byte_vec_copy(out, trap->message); +} + +struct wasm_module_ex_t { + struct WASMModuleCommon *module_comm_rt; + wasm_byte_vec_t *binary; +}; + +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; +} + +wasm_module_t * +wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) +{ + char error[128] = { 0 }; + wasm_module_ex_t *module_ex = NULL; + PackageType pkg_type = Package_Type_Unknown; + + check_engine_and_store(singleton_engine, store); + bh_assert(binary && binary->data && binary->size); + + pkg_type = get_package_type((uint8 *)binary->data, binary->size); + if (Package_Type_Unknown == pkg_type + || (Wasm_Module_Bytecode == pkg_type + && INTERP_MODE != current_runtime_mode()) + || (Wasm_Module_AoT == pkg_type + && INTERP_MODE == current_runtime_mode())) { + LOG_WARNING( + "current runtime mode %d doesn\'t support the package type " + "%d", + current_runtime_mode(), pkg_type); + goto failed; + } + + module_ex = malloc_internal(sizeof(wasm_module_ex_t)); + if (!module_ex) { + goto failed; + } + + module_ex->binary = malloc_internal(sizeof(wasm_byte_vec_t)); + if (!module_ex->binary) { + goto failed; + } + + wasm_byte_vec_copy(module_ex->binary, binary); + if (!module_ex->binary->data) { + goto failed; + } + + module_ex->module_comm_rt = + wasm_runtime_load((uint8 *)module_ex->binary->data, + module_ex->binary->size, error, (uint32)sizeof(error)); + if (!(module_ex->module_comm_rt)) { + LOG_ERROR(error); + goto failed; + } + + /* add it to a watching list in store */ + if (!bh_vector_append((Vector *)store->modules, &module_ex)) { + goto failed; + } + + return module_ext_to_module(module_ex); + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_module_delete_internal(module_ext_to_module(module_ex)); + return NULL; +} + +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); + if (module_ex->binary) { + wasm_byte_vec_delete(module_ex->binary); + wasm_runtime_free(module_ex->binary); + module_ex->binary = NULL; + } + + if (module_ex->module_comm_rt) { + wasm_runtime_unload(module_ex->module_comm_rt); + module_ex->module_comm_rt = NULL; + } + + wasm_runtime_free(module_ex); +} + +/* will release module when releasing the store */ +void +wasm_module_delete(wasm_module_t *module) +{ + /* pass */ +} + +void +wasm_module_vec_new_uninitialized(wasm_module_vec_t *out, size_t size) +{ + generic_vec_init_data((Vector *)out, size, sizeof(wasm_module_t *)); +} + +void +wasm_module_vec_delete(wasm_module_vec_t *module_vec) +{ + size_t i = 0; + if (!module_vec || !module_vec->data) { + return; + } + + FREE_VEC_ELEMS(module_vec, wasm_module_delete_internal); + bh_vector_destroy((Vector *)module_vec); +} + +static uint32 +argv_to_params(const uint64 *argv, + const wasm_valtype_vec_t *param_defs, + wasm_val_t *out) +{ + size_t i = 0; + uint32 argc = 0; + void *argv_p = (void *)argv; + + for (i = 0; i < param_defs->num_elems; i++) { + wasm_valtype_t *param_def = param_defs->data[i]; + wasm_val_t *param = out + i; + switch (param_def->kind) { + case WASM_I32: + param->kind = WASM_I32; + param->of.i32 = *(uint32 *)argv_p; + argv_p = (uint32 *)argv_p + 1; + argc++; + break; + case WASM_I64: + param->kind = WASM_I64; + param->of.i64 = *(uint64 *)argv_p; + argv_p = (uint64 *)argv_p + 1; + argc++; + break; + case WASM_F32: + param->kind = WASM_F32; + param->of.f32 = *(float32 *)argv_p; + argv_p = (float32 *)argv_p + 1; + argc++; + break; + case WASM_F64: + param->kind = WASM_F64; + param->of.f64 = *(float64 *)argv_p; + argv_p = (float64 *)argv_p + 1; + argc++; + break; + default: + NOT_REACHED(); + goto failed; + } + } + + return argc; +failed: + return 0; +} + +static uint32 +results_to_argv(const wasm_val_t *results, + const wasm_valtype_vec_t *result_defs, + uint64 *out) +{ + size_t i = 0; + uint32 argc = 0; + void *argv_p = out; + + for (i = 0; i < result_defs->num_elems; ++i) { + wasm_valtype_t *result_def = result_defs->data[i]; + const wasm_val_t *result = results + i; + switch (result_def->kind) { + case WASM_I32: + *(uint32 *)argv_p = result->of.i32; + argv_p = (uint32 *)argv_p + 1; + argc++; + break; + case WASM_I64: + *(uint64 *)argv_p = result->of.i64; + argv_p = (uint64 *)argv_p + 1; + argc++; + break; + case WASM_F32: + *(float32 *)argv_p = result->of.f32; + argv_p = (float32 *)argv_p + 1; + argc++; + break; + case WASM_F64: + *(float64 *)argv_p = result->of.f64; + argv_p = (float64 *)argv_p + 1; + argc++; + break; + default: + NOT_REACHED(); + goto failed; + } + } + + return argc; +failed: + return 0; +} + +static void +native_func_trampoline(wasm_exec_env_t exec_env, uint64 *argv) +{ + wasm_val_t *params = NULL; + wasm_val_t *results = NULL; + uint32 argc = 0; + const wasm_func_t *func = NULL; + wasm_trap_t *trap = NULL; + + bh_assert(argv); + + func = wasm_runtime_get_function_attachment(exec_env); + bh_assert(func); + + params = malloc_internal(wasm_func_param_arity(func) * sizeof(wasm_val_t)); + if (!params) { + goto failed; + } + + results = + malloc_internal(wasm_func_result_arity(func) * sizeof(wasm_val_t)); + if (!results) { + goto failed; + } + + /* argv -> const wasm_val_t params[] */ + argc = + argv_to_params(argv, wasm_functype_params(wasm_func_type(func)), params); + if (wasm_func_param_arity(func) && !argc) { + goto failed; + } + + if (func->with_env) { + trap = func->u.cb_env.cb(func->u.cb_env.env, params, results); + } + else { + trap = func->u.cb(params, results); + } + + if (trap) { + wasm_name_t *message = NULL; + wasm_trap_message(trap, message); + LOG_WARNING("got a trap %s", message->data); + wasm_name_delete(message); + } + + /* there is no result or there is an exception */ + if (trap || !wasm_func_result_arity(func)) { + memset(argv, 0, wasm_func_param_arity(func) * sizeof(uint64)); + } + + /* wasm_val_t results[] -> argv */ + argc = results_to_argv(results, + wasm_functype_results(wasm_func_type(func)), argv); + if (wasm_func_result_arity(func) && !argc) { + goto failed; + } + +failed: + FREEIF(params); + FREEIF(results); + return; +} + +wasm_func_t * +wasm_func_new(wasm_store_t *store, + const wasm_functype_t *func_type, + wasm_func_callback_t callback) +{ + wasm_func_t *func = NULL; + + check_engine_and_store(singleton_engine, store); + bh_assert(func_type); + + func = malloc_internal(sizeof(wasm_func_t)); + if (!func) { + goto failed; + } + + func->kind = WASM_EXTERN_FUNC; + func->with_env = false; + func->u.cb = callback; + + func->func_type = wasm_functype_copy((wasm_functype_t *)func_type); + if (!func->func_type) { + goto failed; + } + + return func; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_func_delete(func); + return NULL; +} + +wasm_func_t * +wasm_func_new_with_env(wasm_store_t *store, + const wasm_functype_t *func_type, + wasm_func_callback_with_env_t callback, + void *env, + void (*finalizer)(void *)) +{ + wasm_func_t *func = NULL; + + check_engine_and_store(singleton_engine, store); + bh_assert(func_type); + + func = malloc_internal(sizeof(wasm_func_t)); + if (!func) { + goto failed; + } + + func->kind = WASM_EXTERN_FUNC; + func->with_env = true; + func->u.cb_env.cb = callback; + func->u.cb_env.env = env; + func->u.cb_env.finalizer = finalizer; + + func->func_type = wasm_functype_copy((wasm_functype_t *)func_type); + if (!func->func_type) { + goto failed; + } + + return func; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_func_delete(func); + return NULL; +} + +static 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; + + check_engine_and_store(singleton_engine, store); + bh_assert(inst_comm_rt); + + func = malloc_internal(sizeof(wasm_func_t)); + if (!func) { + goto failed; + } + + func->kind = WASM_EXTERN_FUNC; + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + bh_assert(func_idx_rt + < ((WASMModuleInstance *)inst_comm_rt)->function_count); + WASMFunctionInstance *func_interp = + ((WASMModuleInstance *)inst_comm_rt)->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 + } + else { +#if WASM_ENABLE_AOT != 0 + /* use same index to trace the function type in AOTFuncType **func_types */ + AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; + AOTFunctionInstance *func_aot = + (AOTFunctionInstance *)inst_aot->export_funcs.ptr + func_idx_rt; + type_rt = func_aot->is_import_func ? func_aot->u.func_import->func_type + : func_aot->u.func.func_type; +#endif + } + + if (!type_rt) { + goto failed; + } + + func->func_type = wasm_functype_new_internal(type_rt); + if (!func->func_type) { + goto failed; + } + + /* will add name information when processing "exports" */ + 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; +} + +void +wasm_func_delete(wasm_func_t *func) +{ + if (!func) { + return; + } + + if (func->func_type) { + wasm_functype_delete(func->func_type); + func->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; + } + } + + wasm_runtime_free(func); +} + +wasm_func_t * +wasm_func_copy(const wasm_func_t *func) +{ + wasm_func_t *cloned = NULL; + + bh_assert(func); + + cloned = malloc_internal(sizeof(wasm_func_t)); + if (!cloned) { + goto failed; + } + + cloned->kind = func->kind; + cloned->with_env = func->with_env; + if (cloned->with_env) { + cloned->u.cb_env.cb = func->u.cb_env.cb; + cloned->u.cb_env.env = func->u.cb_env.env; + cloned->u.cb_env.finalizer = func->u.cb_env.finalizer; + } + else { + cloned->u.cb = func->u.cb; + } + + cloned->func_idx_rt = func->func_idx_rt; + cloned->inst_comm_rt = func->inst_comm_rt; + cloned->func_type = wasm_functype_copy(func->func_type); + if (!cloned->func_type) { + goto failed; + } + + return cloned; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_func_delete(cloned); + return NULL; +} + +wasm_functype_t * +wasm_func_type(const wasm_func_t *func) +{ + bh_assert(func); + return func->func_type; +} + +static uint32 +params_to_argv(const wasm_val_t *params, + const wasm_valtype_vec_t *param_defs, + size_t param_arity, + uint32 *out) +{ + size_t i = 0; + uint32 argc = 0; + const wasm_val_t *param = NULL; + + if (!param_arity) { + return 0; + } + + bh_assert(params && param_defs && out); + bh_assert(param_defs->num_elems == param_arity); + + for (i = 0; out && i < param_arity; ++i) { + param = params + i; + bh_assert((*(param_defs->data + i))->kind == param->kind); + + switch (param->kind) { + case WASM_I32: + *(int32 *)out = param->of.i32; + out += 1; + argc += 1; + break; + case WASM_I64: + *(int64 *)out = param->of.i64; + out += 2; + argc += 2; + break; + case WASM_F32: + *(float32 *)out = param->of.f32; + out += 1; + argc += 1; + break; + case WASM_F64: + *(float64 *)out = param->of.f64; + out += 2; + argc += 2; + break; + default: + LOG_DEBUG("unexpected parameter val type %d", param->kind); + goto failed; + } + } + + return argc; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return 0; +} + +static uint32 +argv_to_results(const uint32 *results, + const wasm_valtype_vec_t *result_defs, + size_t result_arity, + wasm_val_t *out) +{ + size_t i = 0; + uint32 argc = 0; + const uint32 *result = results; + const wasm_valtype_t *def = NULL; + + if (!result_arity) { + return 0; + } + + bh_assert(results && result_defs && out); + bh_assert(result_arity == result_defs->num_elems); + + for (i = 0; out && i < result_arity; i++) { + def = *(result_defs->data + i); + + switch (def->kind) { + case WASM_I32: + out->kind = WASM_I32; + out->of.i32 = *(int32 *)result; + result += 1; + break; + case WASM_I64: + out->kind = WASM_I64; + out->of.i64 = *(int64 *)result; + result += 2; + break; + case WASM_F32: + out->kind = WASM_F32; + out->of.f32 = *(float32 *)result; + result += 1; + break; + case WASM_F64: + out->kind = WASM_F64; + out->of.f64 = *(float64 *)result; + result += 2; + break; + default: + LOG_DEBUG("unexpected parameter val type %d", def->kind); + goto failed; + } + out++; + argc++; + } + + return argc; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return 0; +} + +wasm_trap_t * +wasm_func_call(const wasm_func_t *func, + const wasm_val_t params[], + wasm_val_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 = NULL; + WASMFunctionInstanceCommon *func_comm_rt = NULL; + size_t param_count = 0; + size_t result_count = 0; + + bh_assert(func && func->func_type && func->inst_comm_rt); + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->functions + + func->func_idx_rt; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTModuleInstance *inst_aot = (AOTModuleInstance *)func->inst_comm_rt; + func_comm_rt = (AOTFunctionInstance *)inst_aot->export_funcs.ptr + + func->func_idx_rt; +#endif + } + if (!func_comm_rt) { + goto failed; + } + + param_count = wasm_func_param_arity(func); + result_count = wasm_func_result_arity(func); + argv = malloc_internal( + sizeof(uint64) + * (param_count > result_count ? param_count : result_count)); + if (!argv) { + goto failed; + } + + /* copy parametes */ + argc = params_to_argv(params, wasm_functype_params(wasm_func_type(func)), + wasm_func_param_arity(func), argv); + if (wasm_func_param_arity(func) && !argc) { + goto failed; + } + + if (!wasm_runtime_create_exec_env_and_call_wasm( + func->inst_comm_rt, func_comm_rt, argc, argv)) { + LOG_DEBUG("wasm_runtime_create_exec_env_and_call_wasm failed"); + goto failed; + } + + /* copy results */ + argc = argv_to_results(argv, wasm_functype_results(wasm_func_type(func)), + wasm_func_result_arity(func), results); + if (wasm_func_result_arity(func) && !argc) { + goto failed; + } + + FREEIF(argv); + /* should return trap */ + return NULL; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + FREEIF(argv); + return NULL; +} + +size_t +wasm_func_param_arity(const wasm_func_t *func) +{ + bh_assert(func && func->func_type && func->func_type->params); + return func->func_type->params->num_elems; +} + +size_t +wasm_func_result_arity(const wasm_func_t *func) +{ + bh_assert(func && func->func_type && func->func_type->results); + return func->func_type->results->num_elems; +} + +wasm_extern_t * +wasm_func_as_extern(wasm_func_t *func) +{ + return (wasm_extern_t *)func; +} + +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; + + check_engine_and_store(singleton_engine, store); + bh_assert(store && global_type && init); + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) { + goto failed; + } + + global->kind = WASM_EXTERN_GLOBAL; + global->type = wasm_globaltype_copy((wasm_globaltype_t *)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; +} + +/* almost same with wasm_global_new */ +wasm_global_t * +wasm_global_copy(const wasm_global_t *src) +{ + wasm_global_t *global = NULL; + + bh_assert(src); + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) { + goto failed; + } + + global->kind = WASM_EXTERN_GLOBAL; + global->type = wasm_globaltype_copy((wasm_globaltype_t *)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); + wasm_runtime_free(global->init); + global->init = NULL; + } + + if (global->type) { + wasm_globaltype_delete(global->type); + global->type = NULL; + } + + wasm_runtime_free(global); +} + +bool +wasm_global_same(const wasm_global_t *g1, const wasm_global_t *g2) +{ + if (!g1 && !g2) { + return true; + } + + if (!g1 || !g2) { + return false; + } + + return g1->kind == g2->kind && wasm_globaltype_same(g1->type, g2->type) + && wasm_val_same(g1->init, g2->init); +} + +#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->globals + global_idx_rt; + uint8 val_type_rt = global_interp->type; + uint8 *data = inst_interp->global_data + global_interp->data_offset; + 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; + default: + LOG_DEBUG("unexpected value type %d", val_type_rt); + ret = false; + break; + } + + return ret; +} + +static bool +interp_global_get(const WASMModuleInstance *inst_interp, + uint16 global_idx_rt, + wasm_val_t *out) +{ + WASMGlobalInstance *global_interp = inst_interp->globals + global_idx_rt; + uint8 val_type_rt = global_interp->type; + uint8 *data = inst_interp->global_data + global_interp->data_offset; + 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; + default: + LOG_DEBUG("unexpected value type %d", val_type_rt); + ret = false; + } + return ret; +} +#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 = inst_aot->aot_module.ptr; + uint8 val_type_rt = 0; + uint32 data_offset = 0; + void *data = NULL; + bool ret = true; + + 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.ptr + data_offset; + 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; + default: + LOG_DEBUG("unexpected value type %d", val_type_rt); + ret = false; + } + return ret; +} + +static bool +aot_global_get(const AOTModuleInstance *inst_aot, + uint16 global_idx_rt, + wasm_val_t *out) +{ + AOTModule *module_aot = inst_aot->aot_module.ptr; + uint8 val_type_rt = 0; + uint32 data_offset = 0; + void *data = NULL; + bool ret = true; + + 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.ptr + data_offset; + 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; + default: + LOG_DEBUG("unexpected value type %d", val_type_rt); + ret = false; + } + return ret; +} +#endif + +void +wasm_global_set(wasm_global_t *global, const wasm_val_t *v) +{ + bh_assert(global && v); + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + (void)interp_global_set((WASMModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, v); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + (void)aot_global_set((AOTModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, v); +#endif + } +} + +void +wasm_global_get(const wasm_global_t *global, wasm_val_t *out) +{ + bh_assert(global && out); + + memset(out, 0, sizeof(wasm_val_t)); + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + (void)interp_global_get((WASMModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, out); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + (void)aot_global_get((AOTModuleInstance *)global->inst_comm_rt, + global->global_idx_rt, out); +#endif + } + + bh_assert(global->init->kind == out->kind); +} + +static 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; + + check_engine_and_store(singleton_engine, store); + bh_assert(inst_comm_rt); + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) { + goto failed; + } + + /* + * global->module_name = NULL; + * global->name = NULL; + */ + global->kind = WASM_EXTERN_GLOBAL; + + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + WASMGlobalInstance *global_interp = + ((WASMModuleInstance *)inst_comm_rt)->globals + global_idx_rt; + val_type_rt = global_interp->type; + is_mutable = global_interp->is_mutable; +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; + AOTModule *module_aot = inst_aot->aot_module.ptr; + 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 + } + + 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 (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + interp_global_get((WASMModuleInstance *)inst_comm_rt, global_idx_rt, + global->init); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + 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) +{ + bh_assert(global); + return global->type; +} + +wasm_extern_t * +wasm_global_as_extern(wasm_global_t *global) +{ + return (wasm_extern_t *)global; +} + +void +wasm_table_delete(wasm_table_t *table) +{} + +void +wasm_memory_delete(wasm_memory_t *memory) +{} + +#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; + wasm_func_t *cloned = 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); + + cloned = wasm_func_copy(import); + if (!cloned || !bh_vector_append((Vector *)inst->imports, &cloned)) { + return false; + } + + /* add native_func_trampoline as a NativeSymbol */ + imported_func_interp->u.function.call_conv_raw = true; + imported_func_interp->u.function.attachment = cloned; + imported_func_interp->u.function.func_ptr_linked = native_func_trampoline; + import->func_idx_rt = func_idx_rt; + + 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); + + /* set init value */ + switch (wasm_valtype_kind(import->type->val_type)) { + case WASM_I32: + bh_assert(VALUE_TYPE_I32 == imported_global_interp->u.global.type); + imported_global_interp->u.global.global_data_linked.i32 = + import->init->of.i32; + break; + case WASM_I64: + bh_assert(VALUE_TYPE_I64 == imported_global_interp->u.global.type); + imported_global_interp->u.global.global_data_linked.i64 = + import->init->of.i64; + break; + case WASM_F32: + bh_assert(VALUE_TYPE_F32 == imported_global_interp->u.global.type); + imported_global_interp->u.global.global_data_linked.f32 = + import->init->of.f32; + break; + case WASM_F64: + bh_assert(VALUE_TYPE_F64 == imported_global_interp->u.global.type); + imported_global_interp->u.global.global_data_linked.f64 = + import->init->of.f64; + break; + default: + return false; + } + + import->global_idx_rt = global_idx_rt; + return true; +} + +static bool +interp_link_memory(const WASMModule *module_interp, + uint16 memory_inst_index, + wasm_memory_t *import) +{ + return false; +} + +static bool +interp_link_table(const WASMModule *module_interp, + uint16 table_inst_index, + wasm_table_t *import) +{ + return false; +} + +static int32 +interp_link(const wasm_instance_t *inst, + const WASMModule *module_interp, + wasm_extern_t *imports[]) +{ + uint32 i = 0; + uint32 import_func_i = 0; + uint32 import_global_i = 0; + uint32 import_table_i = 0; + uint32 import_memory_i = 0; + wasm_func_t *func = NULL; + wasm_global_t *global = NULL; + + bh_assert(inst && module_interp && imports); + + for (i = 0; i < module_interp->import_count; ++i) { + wasm_extern_t *import = imports[i]; + WASMImport *import_rt = module_interp->imports + i; + + switch (import_rt->kind) { + case IMPORT_KIND_FUNC: + func = wasm_extern_as_func(import); + if (!interp_link_func(inst, module_interp, import_func_i++, + func)) { + goto failed; + } + + break; + case IMPORT_KIND_GLOBAL: + global = wasm_extern_as_global(import); + if (!interp_link_global(module_interp, import_global_i++, + global)) { + goto failed; + } + + break; + case IMPORT_KIND_MEMORY: + if (!interp_link_memory(module_interp, import_memory_i++, + wasm_extern_as_memory(import))) { + goto failed; + }; + break; + case IMPORT_KIND_TABLE: + if (!interp_link_table(module_interp, import_table_i++, + wasm_extern_as_table(import))) { + goto failed; + } + break; + default: + NOT_REACHED(); + break; + } + } + + return module_interp->import_count; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return -1; +} + +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_func_t *func = NULL; + wasm_global_t *global = NULL; + wasm_extern_t *external = NULL; + uint32 export_cnt = 0; + uint32 i = 0; + + bh_assert(store && inst_interp && 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: + func = wasm_func_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp); + if (!func) { + goto failed; + } + + external = wasm_func_as_extern(func); + break; + case EXPORT_KIND_GLOBAL: + global = wasm_global_new_internal( + store, export->index, + (WASMModuleInstanceCommon *)inst_interp); + if (!global) { + goto failed; + } + + external = wasm_global_as_extern(global); + break; + // TODO: + case EXPORT_KIND_MEMORY: + case EXPORT_KIND_TABLE: + break; + default: + goto failed; + } + + if (!bh_vector_append((Vector *)externals, &external)) { + goto failed; + } + } + + return true; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + 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; + wasm_func_t *cloned = NULL; + + bh_assert(inst && module_aot && import); + + import_aot_func = module_aot->import_funcs + import_func_idx_rt; + bh_assert(import_aot_func); + + cloned = wasm_func_copy(import); + if (!cloned || !bh_vector_append((Vector *)inst->imports, &cloned)) { + return false; + } + + import_aot_func->call_conv_raw = true; + import_aot_func->attachment = wasm_func_copy(import); + import_aot_func->func_ptr_linked = native_func_trampoline; + 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); + + val_type = wasm_globaltype_content(wasm_global_type(import)); + bh_assert(val_type); + + switch (wasm_valtype_kind(val_type)) { + case WASM_I32: + bh_assert(VALUE_TYPE_I32 == import_aot_global->type); + import_aot_global->global_data_linked.i32 = import->init->of.i32; + break; + case WASM_I64: + bh_assert(VALUE_TYPE_I64 == import_aot_global->type); + import_aot_global->global_data_linked.i64 = import->init->of.i64; + break; + case WASM_F32: + bh_assert(VALUE_TYPE_F32 == import_aot_global->type); + import_aot_global->global_data_linked.f32 = import->init->of.f32; + break; + case WASM_F64: + bh_assert(VALUE_TYPE_F64 == import_aot_global->type); + import_aot_global->global_data_linked.f64 = import->init->of.f64; + break; + default: + goto failed; + } + + import->global_idx_rt = global_idx_rt; + return true; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return false; +} + +static int32 +aot_link(const wasm_instance_t *inst, + const AOTModule *module_aot, + wasm_extern_t *imports[]) +{ + uint32 i = 0; + uint32 import_func_i = 0; + uint32 import_global_i = 0; + wasm_extern_t *import = NULL; + wasm_func_t *func = NULL; + wasm_global_t *global = NULL; + + bh_assert(inst && module_aot && imports); + + while (import_func_i < module_aot->import_func_count + || import_global_i < module_aot->import_global_count) { + import = imports[i++]; + + bh_assert(import); + + switch (wasm_extern_kind(import)) { + case WASM_EXTERN_FUNC: + bh_assert(import_func_i < module_aot->import_func_count); + func = wasm_extern_as_func((wasm_extern_t *)import); + if (!aot_link_func(inst, module_aot, import_func_i++, func)) { + goto failed; + } + + break; + case WASM_EXTERN_GLOBAL: + bh_assert(import_global_i < module_aot->import_global_count); + global = wasm_extern_as_global((wasm_extern_t *)import); + if (!aot_link_global(module_aot, import_global_i++, global)) { + goto failed; + } + + break; + case WASM_EXTERN_MEMORY: + break; + case WASM_EXTERN_TABLE: + break; + default: + goto failed; + } + } + + return i; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return -1; +} + +static bool +aot_process_export(wasm_store_t *store, + const AOTModuleInstance *inst_aot, + wasm_extern_vec_t *externals) +{ + uint32 i = 0; + uint32 export_func_i = 0; + wasm_extern_t *external = NULL; + AOTModule *module_aot = NULL; + + bh_assert(store && inst_aot && externals); + + module_aot = (AOTModule *)inst_aot->aot_module.ptr; + bh_assert(module_aot); + + for (i = 0; i < module_aot->export_count; ++i) { + AOTExport *export = module_aot->exports + i; + wasm_func_t *func = NULL; + wasm_global_t *global = NULL; + + switch (export->kind) { + case EXPORT_KIND_FUNC: + func = + wasm_func_new_internal(store, export_func_i++, + (WASMModuleInstanceCommon *)inst_aot); + if (!func) { + goto failed; + } + + external = wasm_func_as_extern(func); + break; + case EXPORT_KIND_GLOBAL: + global = wasm_global_new_internal( + store, export->index, (WASMModuleInstanceCommon *)inst_aot); + if (!global) { + goto failed; + } + + external = wasm_global_as_extern(global); + break; + case EXPORT_KIND_MEMORY: + case EXPORT_KIND_TABLE: + break; + default: + NOT_REACHED(); + goto failed; + } + + if (!bh_vector_append((Vector *)externals, &external)) { + goto failed; + } + } + + return true; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return false; +} +#endif /* WASM_ENABLE_AOT */ + +wasm_instance_t * +wasm_instance_new(wasm_store_t *store, + const wasm_module_t *module, + const wasm_extern_t *const imports[], + wasm_trap_t **traps) +{ + char error[128] = { 0 }; + const uint32 stack_size = 16 * 1024; + const uint32 heap_size = 16 * 1024; + int32 import_count = 0; + wasm_instance_t *instance = NULL; + uint32 i = 0; + (void)traps; + + check_engine_and_store(singleton_engine, store); + + instance = malloc_internal(sizeof(wasm_instance_t)); + if (!instance) { + goto failed; + } + + /* link module and imports */ + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + import_count = ((WASMModule *)*module)->import_count; + INIT_VEC(instance->imports, wasm_extern_vec, import_count); + if (!instance->imports) { + goto failed; + } + + import_count = interp_link(instance, (WASMModule *)*module, + (wasm_extern_t **)imports); +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + import_count = ((AOTModule *)*module)->import_func_count + + ((AOTModule *)*module)->import_global_count + + ((AOTModule *)*module)->import_memory_count + + ((AOTModule *)*module)->import_table_count; + INIT_VEC(instance->imports, wasm_extern_vec, import_count); + if (!instance->imports) { + goto failed; + } + + import_count = + aot_link(instance, (AOTModule *)*module, (wasm_extern_t **)imports); +#endif + } + if (import_count < 0) { + goto failed; + } + + instance->inst_comm_rt = wasm_runtime_instantiate( + *module, stack_size, heap_size, error, sizeof(error)); + if (!instance->inst_comm_rt) { + LOG_ERROR(error); + goto failed; + } + + /* fill in inst */ + for (i = 0; i < (uint32)import_count; ++i) { + wasm_extern_t *import = (wasm_extern_t *)imports[i]; + 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: + goto failed; + } + } + + /* build the exports list */ + if (INTERP_MODE == current_runtime_mode()) { +#if WASM_ENABLE_INTERP != 0 + uint32 export_cnt = + ((WASMModuleInstance *)instance->inst_comm_rt)->module->export_count; + + INIT_VEC(instance->exports, wasm_extern_vec, export_cnt); + + if (!interp_process_export( + store, (WASMModuleInstance *)instance->inst_comm_rt, + instance->exports)) { + goto failed; + } +#endif + } + else { +#if WASM_ENABLE_AOT != 0 + uint32 export_cnt = + ((AOTModuleInstance *)instance->inst_comm_rt)->export_func_count; + + INIT_VEC(instance->exports, wasm_extern_vec, export_cnt); + + if (!aot_process_export(store, + (AOTModuleInstance *)instance->inst_comm_rt, + instance->exports)) { + goto failed; + } +#endif + } + + /* add it to a watching list in store */ + if (!bh_vector_append((Vector *)store->instances, &instance)) { + goto failed; + } + + return instance; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_instance_delete_internal(instance); + return NULL; +} + +void +wasm_instance_delete_internal(wasm_instance_t *instance) +{ + if (!instance) { + return; + } + + DEINIT_VEC(instance->imports, wasm_extern_vec_delete); + 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); +} + +/* will release instance when releasing the store */ +void +wasm_instance_delete(wasm_instance_t *module) +{ + /* pass */ +} + +void +wasm_instance_exports(const wasm_instance_t *instance, wasm_extern_vec_t *out) +{ + bh_assert(instance && out); + wasm_extern_vec_copy(out, instance->exports); +} + +void +wasm_instance_vec_new_uninitialized(wasm_instance_vec_t *out, size_t size) +{ + generic_vec_init_data((Vector *)out, size, sizeof(wasm_instance_t)); +} + +void +wasm_instance_vec_delete(wasm_instance_vec_t *instance_vec) +{ + size_t i = 0; + if (!instance_vec || !instance_vec->data) { + return; + } + + FREE_VEC_ELEMS(instance_vec, wasm_instance_delete_internal); + bh_vector_destroy((Vector *)instance_vec); +} + +wasm_extern_t * +wasm_extern_copy(const wasm_extern_t *src) +{ + wasm_extern_t *dst = NULL; + wasm_func_t *func = NULL; + wasm_global_t *global = NULL; + bh_assert(src); + + switch (wasm_extern_kind(src)) { + case WASM_EXTERN_FUNC: + func = wasm_func_copy(wasm_extern_as_func_const(src)); + dst = wasm_func_as_extern(func); + break; + case WASM_EXTERN_GLOBAL: + global = wasm_global_copy(wasm_extern_as_global_const(src)); + dst = wasm_global_as_extern(global); + break; + case WASM_EXTERN_MEMORY: + case WASM_EXTERN_TABLE: + default: + 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; + } + + 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: + case WASM_EXTERN_TABLE: + default: + break; + } +} + +wasm_externkind_t +wasm_extern_kind(const wasm_extern_t *extrenal) +{ + return extrenal->kind; +} + +wasm_func_t * +wasm_extern_as_func(wasm_extern_t *external) +{ + return (wasm_func_t *)external; +} + +const wasm_func_t * +wasm_extern_as_func_const(const wasm_extern_t *external) +{ + return (const wasm_func_t *)external; +} + +wasm_global_t * +wasm_extern_as_global(wasm_extern_t *external) +{ + return (wasm_global_t *)external; +} + +const wasm_global_t * +wasm_extern_as_global_const(const wasm_extern_t *external) +{ + return (const wasm_global_t *)external; +} + +wasm_memory_t * +wasm_extern_as_memory(wasm_extern_t *external) +{ + return (wasm_memory_t *)external; +} + +const wasm_memory_t * +wasm_extern_as_memory_const(const wasm_extern_t *external) +{ + return (const wasm_memory_t *)external; +} + +wasm_table_t * +wasm_extern_as_table(wasm_extern_t *external) +{ + return (wasm_table_t *)external; +} + +const wasm_table_t * +wasm_extern_as_table_const(const wasm_extern_t *external) +{ + return (const wasm_table_t *)external; +} + +void +wasm_extern_vec_copy(wasm_extern_vec_t *out, const wasm_extern_vec_t *src) +{ + size_t i = 0; + bh_assert(out && src); + + generic_vec_init_data((Vector *)out, src->size, src->size_of_elem); + if (!out->data) { + goto failed; + } + + for (i = 0; i < src->num_elems; ++i) { + wasm_extern_t *orig = *(src->data + i); + wasm_extern_t *cloned = wasm_extern_copy(orig); + if (!cloned) { + goto failed; + } + + if (!bh_vector_append((Vector *)out, &cloned)) { + goto failed; + } + } + + return; + +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_extern_vec_delete(out); + return; +} + +void +wasm_extern_vec_new_uninitialized(wasm_extern_vec_t *out, size_t size) +{ + generic_vec_init_data((Vector *)out, size, sizeof(wasm_extern_t *)); +} + +void +wasm_extern_vec_delete(wasm_extern_vec_t *extern_vec) +{ + size_t i = 0; + if (!extern_vec || !extern_vec->data) { + return; + } + + FREE_VEC_ELEMS(extern_vec, wasm_extern_delete); + bh_vector_destroy((Vector *)extern_vec); +} diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h new file mode 100644 index 00000000..b321ff87 --- /dev/null +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_C_API_INTERNAL_H +#define _WASM_C_API_INTERNAL_H + +#include "wasm_c_api.h" +#include "wasm_runtime_common.h" + +#ifndef own +#define own +#endif + +/* Vectors */ +/* we will malloc resource for the vector's data field */ +/* we will release resource of data */ +/* caller needs to take care resource for the vector itself */ +#define DEFAULT_VECTOR_INIT_LENGTH (64) + +WASM_DECLARE_VEC(store, *) +WASM_DECLARE_VEC(module, *) +WASM_DECLARE_VEC(instance, *) + +/* Runtime Environment */ +typedef enum runtime_mode_e { + INTERP_MODE = 0, + JIT_MODE, + AOT_MODE +} runtime_mode_e; + +struct wasm_engine_t { + // support one store for now + wasm_store_vec_t *stores; + // Interpreter by deault + runtime_mode_e mode; +}; + +struct wasm_store_t { + wasm_module_vec_t *modules; + wasm_instance_vec_t *instances; +}; + +/* Type Representations */ +struct wasm_valtype_t { + wasm_valkind_t kind; +}; + +struct wasm_functype_t { + uint32 extern_kind; + // gona to new and delete own + wasm_valtype_vec_t *params; + wasm_valtype_vec_t *results; +}; + +struct wasm_globaltype_t { + uint32 extern_kind; + // gona to new and delete own + wasm_valtype_t *val_type; + wasm_mutability_t mutability; +}; + +struct wasm_tabletype_t { + uint32 extern_kind; + // always be WASM_FUNCREF + wasm_valtype_t *type; + wasm_limits_t *limits; +}; + +struct wasm_memorytype_t { + uint32 extern_kind; + wasm_limits_t *limits; +}; + +struct wasm_externtype_t { + uint32 extern_kind; + uint8 data[1]; +}; + +struct wasm_import_type_t { + uint32 extern_kind; + wasm_name_t *module_name; + wasm_name_t *name; +}; + +struct wasm_export_type_t { + uint32 extern_kind; + wasm_name_t *module_name; + wasm_name_t *name; +}; + +/* Runtime Objects */ +struct wasm_ref_t {}; + +struct wasm_trap_t { + wasm_byte_vec_t *message; +}; + +struct wasm_func_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + wasm_functype_t *func_type; + + bool with_env; + union { + wasm_func_callback_t cb; + struct callback_ext { + void *env; + wasm_func_callback_with_env_t cb; + void (*finalizer)(void *); + } cb_env; + } u; + /* + * an index in both functions runtime instance lists + * of interpreter mode and aot mode + */ + uint16 func_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_global_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + wasm_globaltype_t *type; + wasm_val_t *init; + /* + * an index in both global runtime instance lists + * of interpreter mode and aot mode + */ + uint16 global_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_memory_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + wasm_memorytype_t *type; + /* + * an index in both memory runtime instance lists + * of interpreter mode and aot mode + */ + uint16 memory_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_table_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + + wasm_tabletype_t *type; + /* + * an index in both table runtime instance lists + * of interpreter mode and aot mode + */ + uint16 table_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +struct wasm_extern_t { + wasm_name_t *module_name; + wasm_name_t *name; + uint16 kind; + uint8 data[1]; +}; + +struct wasm_instance_t { + wasm_extern_vec_t *imports; + wasm_extern_vec_t *exports; + WASMModuleInstanceCommon *inst_comm_rt; +}; + +#endif /* _WASM_C_API_INTERNAL_H */ diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 57bb591f..95f4fb7f 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -67,14 +67,11 @@ typedef struct WASMRegisteredModule { } WASMRegisteredModule; #endif -#if WASM_ENABLE_SHARED_MEMORY != 0 typedef struct WASMMemoryInstanceCommon { uint32 module_type; uint8 memory_inst_data[1]; } WASMMemoryInstanceCommon; -#endif - typedef package_type_t PackageType; typedef wasm_section_t WASMSection, AOTSection; diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index be99e6fe..8d2f88db 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -3,8 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#if WASM_ENABLE_SHARED_MEMORY != 0 - #include "bh_log.h" #include "wasm_shared_memory.h" @@ -120,5 +118,3 @@ shared_memory_set_memory_inst(WASMModuleCommon *module, (void)ret; return node; } - -#endif /* end of WASM_ENABLE_SHARED_MEMORY */ diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h new file mode 100644 index 00000000..5b5bd79e --- /dev/null +++ b/core/iwasm/include/wasm_c_api.h @@ -0,0 +1,679 @@ +// WebAssembly C API + +#ifndef WASM_H +#define WASM_H + +#include +#include +#include +#include +#include + +#ifndef WASM_API_EXTERN +#ifdef _WIN32 +#define WASM_API_EXTERN __declspec(dllimport) +#else +#define WASM_API_EXTERN +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Auxiliaries + +// Machine types +#if (__STDC_VERSION__ > 199901L) +inline void assertions() { + static_assert(sizeof(float) == sizeof(uint32_t), "incompatible float type"); + static_assert(sizeof(double) == sizeof(uint64_t), "incompatible double type"); + static_assert(sizeof(intptr_t) == sizeof(uint32_t) || + sizeof(intptr_t) == sizeof(uint64_t), + "incompatible pointer type"); +} +#endif /* __STDC_VERSION__ > 199901L */ + +typedef char byte_t; +typedef float float32_t; +typedef double float64_t; + + +// Ownership + +#define own + +// The qualifier `own` is used to indicate ownership of data in this API. +// It is intended to be interpreted similar to a `const` qualifier: +// +// - `own wasm_xxx_t*` owns the pointed-to data +// - `own wasm_xxx_t` distributes to all fields of a struct or union `xxx` +// - `own wasm_xxx_vec_t` owns the vector as well as its elements(!) +// - an `own` function parameter passes ownership from caller to callee +// - an `own` function result passes ownership from callee to caller +// - an exception are `own` pointer parameters named `out`, which are copy-back +// output parameters passing back ownership from callee to caller +// +// Own data is created by `wasm_xxx_new` functions and some others. +// It must be released with the corresponding `wasm_xxx_delete` function. +// +// Deleting a reference does not necessarily delete the underlying object, +// it merely indicates that this owner no longer uses it. +// +// For vectors, `const wasm_xxx_vec_t` is used informally to indicate that +// neither the vector nor its elements should be modified. +// TODO: introduce proper `wasm_xxx_const_vec_t`? + + +#define WASM_DECLARE_OWN(name) \ + typedef struct wasm_##name##_t wasm_##name##_t; \ + \ + WASM_API_EXTERN void wasm_##name##_delete(own wasm_##name##_t*); + + +// Vectors +// size: capacity +// num_elems: current number of elements +// size_of_elem: size of one element +#define WASM_DECLARE_VEC(name, ptr_or_none) \ + typedef struct wasm_##name##_vec_t { \ + size_t size; \ + wasm_##name##_t ptr_or_none* data; \ + size_t num_elems; \ + size_t size_of_elem; \ + } wasm_##name##_vec_t; \ + \ + WASM_API_EXTERN void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out); \ + WASM_API_EXTERN void wasm_##name##_vec_new_uninitialized( \ + own wasm_##name##_vec_t* out, size_t); \ + WASM_API_EXTERN void wasm_##name##_vec_new( \ + own wasm_##name##_vec_t* out, \ + size_t, own wasm_##name##_t ptr_or_none const[]); \ + WASM_API_EXTERN void wasm_##name##_vec_copy( \ + own wasm_##name##_vec_t* out, const wasm_##name##_vec_t*); \ + WASM_API_EXTERN void wasm_##name##_vec_delete(own wasm_##name##_vec_t*); + + +// Byte vectors + +typedef byte_t wasm_byte_t; +WASM_DECLARE_VEC(byte, ) + +typedef wasm_byte_vec_t wasm_name_t; + +#define wasm_name wasm_byte_vec +#define wasm_name_new wasm_byte_vec_new +#define wasm_name_new_empty wasm_byte_vec_new_empty +#define wasm_name_new_new_uninitialized wasm_byte_vec_new_uninitialized +#define wasm_name_copy wasm_byte_vec_copy +#define wasm_name_delete wasm_byte_vec_delete + +static inline void wasm_name_new_from_string( + own wasm_name_t* out, const char* s +) { + wasm_name_new(out, strlen(s) + 1, s); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Environment + +// Engine + +WASM_DECLARE_OWN(engine) + +WASM_API_EXTERN own wasm_engine_t* wasm_engine_new(); + + +// Store + +WASM_DECLARE_OWN(store) + +WASM_API_EXTERN own wasm_store_t* wasm_store_new(wasm_engine_t*); + + +/////////////////////////////////////////////////////////////////////////////// +// Type Representations + +// Type attributes + +typedef uint8_t wasm_mutability_t; +enum wasm_mutability_enum { + WASM_CONST, + WASM_VAR, +}; + +typedef struct wasm_limits_t { + uint32_t min; + uint32_t max; +} wasm_limits_t; + +static const uint32_t wasm_limits_max_default = 0xffffffff; + + +// Generic + +#define WASM_DECLARE_TYPE(name) \ + WASM_DECLARE_OWN(name) \ + WASM_DECLARE_VEC(name, *) \ + \ + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t*); + + +// Value Types + +WASM_DECLARE_TYPE(valtype) + +typedef uint8_t wasm_valkind_t; +enum wasm_valkind_enum { + WASM_I32, + WASM_I64, + WASM_F32, + WASM_F64, + WASM_ANYREF = 128, + WASM_FUNCREF, +}; + +WASM_API_EXTERN own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t); + +WASM_API_EXTERN wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t*); + +static inline bool wasm_valkind_is_num(wasm_valkind_t k) { + return k < WASM_ANYREF; +} +static inline bool wasm_valkind_is_ref(wasm_valkind_t k) { + return k >= WASM_ANYREF; +} + +static inline bool wasm_valtype_is_num(const wasm_valtype_t* t) { + return wasm_valkind_is_num(wasm_valtype_kind(t)); +} +static inline bool wasm_valtype_is_ref(const wasm_valtype_t* t) { + return wasm_valkind_is_ref(wasm_valtype_kind(t)); +} + + +// Function Types + +WASM_DECLARE_TYPE(functype) + +WASM_API_EXTERN own wasm_functype_t* wasm_functype_new( + own wasm_valtype_vec_t* params, own wasm_valtype_vec_t* results); + +WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t*); +WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t*); + + +// Global Types + +WASM_DECLARE_TYPE(globaltype) + +WASM_API_EXTERN own wasm_globaltype_t* wasm_globaltype_new( + own wasm_valtype_t*, wasm_mutability_t); + +WASM_API_EXTERN const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t*); +WASM_API_EXTERN wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t*); + + +// Table Types + +WASM_DECLARE_TYPE(tabletype) + +WASM_API_EXTERN own wasm_tabletype_t* wasm_tabletype_new( + own wasm_valtype_t*, const wasm_limits_t*); + +WASM_API_EXTERN const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t*); +WASM_API_EXTERN const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t*); + + +// Memory Types + +WASM_DECLARE_TYPE(memorytype) + +WASM_API_EXTERN own wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t*); + +WASM_API_EXTERN const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t*); + + +// Extern Types + +WASM_DECLARE_TYPE(externtype) + +typedef uint8_t wasm_externkind_t; +enum wasm_externkind_enum { + WASM_EXTERN_FUNC, + WASM_EXTERN_GLOBAL, + WASM_EXTERN_TABLE, + WASM_EXTERN_MEMORY, +}; + +WASM_API_EXTERN wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t*); + +WASM_API_EXTERN wasm_externtype_t* wasm_functype_as_externtype(wasm_functype_t*); +WASM_API_EXTERN wasm_externtype_t* wasm_globaltype_as_externtype(wasm_globaltype_t*); +WASM_API_EXTERN wasm_externtype_t* wasm_tabletype_as_externtype(wasm_tabletype_t*); +WASM_API_EXTERN wasm_externtype_t* wasm_memorytype_as_externtype(wasm_memorytype_t*); + +WASM_API_EXTERN wasm_functype_t* wasm_externtype_as_functype(wasm_externtype_t*); +WASM_API_EXTERN wasm_globaltype_t* wasm_externtype_as_globaltype(wasm_externtype_t*); +WASM_API_EXTERN wasm_tabletype_t* wasm_externtype_as_tabletype(wasm_externtype_t*); +WASM_API_EXTERN wasm_memorytype_t* wasm_externtype_as_memorytype(wasm_externtype_t*); + +WASM_API_EXTERN const wasm_externtype_t* wasm_functype_as_externtype_const(const wasm_functype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_globaltype_as_externtype_const(const wasm_globaltype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_tabletype_as_externtype_const(const wasm_tabletype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_memorytype_as_externtype_const(const wasm_memorytype_t*); + +WASM_API_EXTERN const wasm_functype_t* wasm_externtype_as_functype_const(const wasm_externtype_t*); +WASM_API_EXTERN const wasm_globaltype_t* wasm_externtype_as_globaltype_const(const wasm_externtype_t*); +WASM_API_EXTERN const wasm_tabletype_t* wasm_externtype_as_tabletype_const(const wasm_externtype_t*); +WASM_API_EXTERN const wasm_memorytype_t* wasm_externtype_as_memorytype_const(const wasm_externtype_t*); + + +// Import Types + +WASM_DECLARE_TYPE(importtype) + +WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new( + own wasm_name_t* module, own wasm_name_t* name, own wasm_externtype_t*); + +WASM_API_EXTERN const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*); +WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*); + + +// Export Types + +WASM_DECLARE_TYPE(exporttype) + +WASM_API_EXTERN own wasm_exporttype_t* wasm_exporttype_new( + own wasm_name_t*, own wasm_externtype_t*); + +WASM_API_EXTERN const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t*); +WASM_API_EXTERN const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t*); + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Objects + +// Values + +struct wasm_ref_t; + +typedef struct wasm_val_t { + wasm_valkind_t kind; + union { + int32_t i32; + int64_t i64; + float32_t f32; + float64_t f64; + struct wasm_ref_t* ref; + } of; +} wasm_val_t; + +WASM_API_EXTERN void wasm_val_delete(own wasm_val_t* v); +WASM_API_EXTERN void wasm_val_copy(own wasm_val_t* out, const wasm_val_t*); + +WASM_DECLARE_VEC(val, ) + + +// References + +#define WASM_DECLARE_REF_BASE(name) \ + WASM_DECLARE_OWN(name) \ + \ + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); \ + WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); + +#define WASM_DECLARE_REF(name) \ + WASM_DECLARE_REF_BASE(name) \ + \ + WASM_API_EXTERN wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t*); \ + WASM_API_EXTERN wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t*); \ + WASM_API_EXTERN const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t*); \ + WASM_API_EXTERN const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t*); + +#define WASM_DECLARE_SHARABLE_REF(name) \ + WASM_DECLARE_REF(name) \ + WASM_DECLARE_OWN(shared_##name) \ + \ + WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \ + WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*); + + +WASM_DECLARE_REF_BASE(ref) + +// Traps + +typedef wasm_name_t wasm_message_t; // null terminated + +WASM_DECLARE_REF_BASE(trap) + +WASM_API_EXTERN own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*); + +WASM_API_EXTERN void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out); + +// Modules +#ifndef WASM_MODULE_T_DEFINED +#define WASM_MODULE_T_DEFINED +struct WASMModuleCommon; +typedef struct WASMModuleCommon *wasm_module_t; +#endif + +WASM_API_EXTERN own wasm_module_t* wasm_module_new( + wasm_store_t*, const wasm_byte_vec_t* binary); + +WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); + +WASM_API_EXTERN void wasm_module_delete(own wasm_module_t*); + +WASM_API_EXTERN own wasm_module_t* wasm_module_copy(const wasm_module_t*); +WASM_API_EXTERN bool wasm_module_same(const wasm_module_t*, const wasm_module_t*); + +WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); +WASM_API_EXTERN void wasm_module_exports(const wasm_module_t*, own wasm_exporttype_vec_t* out); + +WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); +WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); + + +// Function Instances + +WASM_DECLARE_REF(func) + +typedef own wasm_trap_t* (*wasm_func_callback_t)( + const wasm_val_t args[], wasm_val_t results[]); +typedef own wasm_trap_t* (*wasm_func_callback_with_env_t)( + void* env, const wasm_val_t args[], wasm_val_t results[]); + +WASM_API_EXTERN own wasm_func_t* wasm_func_new( + wasm_store_t*, const wasm_functype_t*, wasm_func_callback_t); +WASM_API_EXTERN own wasm_func_t* wasm_func_new_with_env( + wasm_store_t*, const wasm_functype_t* type, wasm_func_callback_with_env_t, + void* env, void (*finalizer)(void*)); + +WASM_API_EXTERN own wasm_functype_t* wasm_func_type(const wasm_func_t*); +WASM_API_EXTERN size_t wasm_func_param_arity(const wasm_func_t*); +WASM_API_EXTERN size_t wasm_func_result_arity(const wasm_func_t*); + +WASM_API_EXTERN own wasm_trap_t* wasm_func_call( + const wasm_func_t*, const wasm_val_t args[], wasm_val_t results[]); + + +// Global Instances + +WASM_DECLARE_REF_BASE(global) + +WASM_API_EXTERN own wasm_global_t* wasm_global_new( + wasm_store_t*, const wasm_globaltype_t*, const wasm_val_t*); + +WASM_API_EXTERN own wasm_globaltype_t* wasm_global_type(const wasm_global_t*); + +WASM_API_EXTERN void wasm_global_get(const wasm_global_t*, own wasm_val_t* out); +WASM_API_EXTERN void wasm_global_set(wasm_global_t*, const wasm_val_t*); + + +// Table Instances + +WASM_DECLARE_REF_BASE(table) + +typedef uint32_t wasm_table_size_t; + +WASM_API_EXTERN own wasm_table_t* wasm_table_new( + wasm_store_t*, const wasm_tabletype_t*, wasm_ref_t* init); + +WASM_API_EXTERN own wasm_tabletype_t* wasm_table_type(const wasm_table_t*); + +WASM_API_EXTERN own wasm_ref_t* wasm_table_get(const wasm_table_t*, wasm_table_size_t index); +WASM_API_EXTERN bool wasm_table_set(wasm_table_t*, wasm_table_size_t index, wasm_ref_t*); + +WASM_API_EXTERN wasm_table_size_t wasm_table_size(const wasm_table_t*); +WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init); + + +// Memory Instances + +WASM_DECLARE_REF_BASE(memory) + +typedef uint32_t wasm_memory_pages_t; + +static const size_t MEMORY_PAGE_SIZE = 0x10000; + +WASM_API_EXTERN own wasm_memory_t* wasm_memory_new(wasm_store_t*, const wasm_memorytype_t*); + +WASM_API_EXTERN own wasm_memorytype_t* wasm_memory_type(const wasm_memory_t*); + +WASM_API_EXTERN byte_t* wasm_memory_data(wasm_memory_t*); +WASM_API_EXTERN size_t wasm_memory_data_size(const wasm_memory_t*); + +WASM_API_EXTERN wasm_memory_pages_t wasm_memory_size(const wasm_memory_t*); +WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta); + + +// Externals + +WASM_DECLARE_REF_BASE(extern) +WASM_DECLARE_VEC(extern, *) + +WASM_API_EXTERN wasm_externkind_t wasm_extern_kind(const wasm_extern_t*); +WASM_API_EXTERN own wasm_externtype_t* wasm_extern_type(const wasm_extern_t*); + +WASM_API_EXTERN wasm_extern_t* wasm_func_as_extern(wasm_func_t*); +WASM_API_EXTERN wasm_extern_t* wasm_global_as_extern(wasm_global_t*); +WASM_API_EXTERN wasm_extern_t* wasm_table_as_extern(wasm_table_t*); +WASM_API_EXTERN wasm_extern_t* wasm_memory_as_extern(wasm_memory_t*); + +WASM_API_EXTERN wasm_func_t* wasm_extern_as_func(wasm_extern_t*); +WASM_API_EXTERN wasm_global_t* wasm_extern_as_global(wasm_extern_t*); +WASM_API_EXTERN wasm_table_t* wasm_extern_as_table(wasm_extern_t*); +WASM_API_EXTERN wasm_memory_t* wasm_extern_as_memory(wasm_extern_t*); + +WASM_API_EXTERN const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t*); +WASM_API_EXTERN const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t*); +WASM_API_EXTERN const wasm_extern_t* wasm_table_as_extern_const(const wasm_table_t*); +WASM_API_EXTERN const wasm_extern_t* wasm_memory_as_extern_const(const wasm_memory_t*); + +WASM_API_EXTERN const wasm_func_t* wasm_extern_as_func_const(const wasm_extern_t*); +WASM_API_EXTERN const wasm_global_t* wasm_extern_as_global_const(const wasm_extern_t*); +WASM_API_EXTERN const wasm_table_t* wasm_extern_as_table_const(const wasm_extern_t*); +WASM_API_EXTERN const wasm_memory_t* wasm_extern_as_memory_const(const wasm_extern_t*); + + +// Module Instances + +WASM_DECLARE_REF_BASE(instance) + +WASM_API_EXTERN own wasm_instance_t* wasm_instance_new( + wasm_store_t*, const wasm_module_t*, const wasm_extern_t* const imports[], + own wasm_trap_t** +); + +WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out); + + +/////////////////////////////////////////////////////////////////////////////// +// Convenience + +// Value Type construction short-hands + +static inline own wasm_valtype_t* wasm_valtype_new_i32() { + return wasm_valtype_new(WASM_I32); +} +static inline own wasm_valtype_t* wasm_valtype_new_i64() { + return wasm_valtype_new(WASM_I64); +} +static inline own wasm_valtype_t* wasm_valtype_new_f32() { + return wasm_valtype_new(WASM_F32); +} +static inline own wasm_valtype_t* wasm_valtype_new_f64() { + return wasm_valtype_new(WASM_F64); +} + +static inline own wasm_valtype_t* wasm_valtype_new_anyref() { + return wasm_valtype_new(WASM_ANYREF); +} +static inline own wasm_valtype_t* wasm_valtype_new_funcref() { + return wasm_valtype_new(WASM_FUNCREF); +} + + +// Function Types construction short-hands + +static inline own wasm_functype_t* wasm_functype_new_0_0() { + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_0( + own wasm_valtype_t* p +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_0( + own wasm_valtype_t* p1, own wasm_valtype_t* p2 +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_0( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3 +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_0_1( + own wasm_valtype_t* r +) { + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_1( + own wasm_valtype_t* p, own wasm_valtype_t* r +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_1( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* r +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_1( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3, + own wasm_valtype_t* r +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_0_2( + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_2( + own wasm_valtype_t* p, own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_2( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_2( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3, + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + + +// Value construction short-hands + +static inline void wasm_val_init_ptr(own wasm_val_t* out, void* p) { +#if UINTPTR_MAX == UINT32_MAX + out->kind = WASM_I32; + out->of.i32 = (intptr_t)p; +#elif UINTPTR_MAX == UINT64_MAX + out->kind = WASM_I64; + out->of.i64 = (intptr_t)p; +#endif +} + +static inline void* wasm_val_ptr(const wasm_val_t* val) { +#if UINTPTR_MAX == UINT32_MAX + return (void*)(intptr_t)val->of.i32; +#elif UINTPTR_MAX == UINT64_MAX + return (void*)(intptr_t)val->of.i64; +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// + +#undef own + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // #ifdef WASM_H diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 8c4ff927..eb48a0e3 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -43,10 +43,13 @@ extern "C" { #define native_raw_set_return(val) *raw_ret = (val) +#ifndef WASM_MODULE_T_DEFINED +#define WASM_MODULE_T_DEFINED /* Uninstantiated WASM module loaded from WASM binary file or AoT binary file*/ struct WASMModuleCommon; typedef struct WASMModuleCommon *wasm_module_t; +#endif /* Instantiated WASM module */ struct WASMModuleInstanceCommon; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 7d75a31b..b1bbd1e4 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1095,9 +1095,11 @@ load_global_import(const WASMModule *parent_module, #endif if (!ret) { +#if WASM_ENABLE_SPEC_TEST != 0 set_error_buf_v(error_buf, error_buf_size, "unknown import or incompatible import type"); return false; +#endif } global->module_name = sub_module_name; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 4f8007a1..c2d9ab9c 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -995,9 +995,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, error_buf, error_buf_size))) { return NULL; } - - LOG_DEBUG("Instantiate a module %p -> %p", module, module_inst); - memset(module_inst, 0, (uint32)sizeof(WASMModuleInstance)); module_inst->module = module; diff --git a/core/shared/utils/bh_platform.h b/core/shared/utils/bh_platform.h index 6d7bd114..94b156f4 100644 --- a/core/shared/utils/bh_platform.h +++ b/core/shared/utils/bh_platform.h @@ -15,6 +15,7 @@ #include "bh_list.h" #include "bh_log.h" #include "bh_queue.h" +#include "bh_vector.h" #include "runtime_timer.h" diff --git a/core/shared/utils/bh_vector.c b/core/shared/utils/bh_vector.c index 15fc9fc2..dfb8339b 100644 --- a/core/shared/utils/bh_vector.c +++ b/core/shared/utils/bh_vector.c @@ -27,7 +27,7 @@ extend_vector(Vector *vector, uint32 length) { uint8 *data; - if (length <= vector->max_elements) + if (length <= vector->max_elems) return true; if (length < vector->size_elem * 3 / 2) @@ -37,10 +37,10 @@ extend_vector(Vector *vector, uint32 length) return false; } - memcpy(data, vector->data, vector->size_elem * vector->max_elements); + memcpy(data, vector->data, vector->size_elem * vector->max_elems); BH_FREE(vector->data); vector->data = data; - vector->max_elements = length; + vector->max_elems = length; return true; } @@ -62,8 +62,8 @@ bh_vector_init(Vector *vector, uint32 init_length, uint32 size_elem) } vector->size_elem = size_elem; - vector->max_elements = init_length; - vector->num_elements = 0; + vector->max_elems = init_length; + vector->num_elems = 0; return true; } @@ -75,7 +75,7 @@ bh_vector_set(Vector *vector, uint32 index, const void *elem_buf) return false; } - if (index >= vector->num_elements) { + if (index >= vector->num_elems) { LOG_ERROR("Set vector elem failed: invalid elem index.\n"); return false; } @@ -92,7 +92,7 @@ bool bh_vector_get(const Vector *vector, uint32 index, void *elem_buf) return false; } - if (index >= vector->num_elements) { + if (index >= vector->num_elems) { LOG_ERROR("Get vector elem failed: invalid elem index.\n"); return false; } @@ -112,24 +112,24 @@ bool bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf) return false; } - if (index >= vector->num_elements) { + if (index >= vector->num_elems) { LOG_ERROR("Insert vector elem failed: invalid elem index.\n"); return false; } - if (!extend_vector(vector, vector->num_elements + 1)) { + if (!extend_vector(vector, vector->num_elems + 1)) { LOG_ERROR("Insert vector elem failed: extend vector failed.\n"); return false; } - p = vector->data + vector->size_elem * vector->num_elements; - for (i = vector->num_elements - 1; i > index; i--) { + p = vector->data + vector->size_elem * vector->num_elems; + for (i = vector->num_elems - 1; i > index; i--) { memcpy(p, p - vector->size_elem, vector->size_elem); p -= vector->size_elem; } memcpy(p, elem_buf, vector->size_elem); - vector->num_elements++; + vector->num_elems++; return true; } @@ -140,14 +140,14 @@ bool bh_vector_append(Vector *vector, const void *elem_buf) return false; } - if (!extend_vector(vector, vector->num_elements + 1)) { + if (!extend_vector(vector, vector->num_elems + 1)) { LOG_ERROR("Append ector elem failed: extend vector failed.\n"); return false; } - memcpy(vector->data + vector->size_elem * vector->num_elements, + memcpy(vector->data + vector->size_elem * vector->num_elems, elem_buf, vector->size_elem); - vector->num_elements++; + vector->num_elems++; return true; } @@ -162,7 +162,7 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf) return false; } - if (index >= vector->num_elements) { + if (index >= vector->num_elems) { LOG_ERROR("Remove vector elem failed: invalid elem index.\n"); return false; } @@ -173,19 +173,19 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf) memcpy(old_elem_buf, p, vector->size_elem); } - for (i = index; i < vector->num_elements - 1; i++) { + for (i = index; i < vector->num_elems - 1; i++) { memcpy(p, p + vector->size_elem, vector->size_elem); p += vector->size_elem; } - vector->num_elements--; + vector->num_elems--; return true; } uint32 bh_vector_size(const Vector *vector) { - return vector ? vector->num_elements : 0; + return vector ? vector->num_elems : 0; } bool diff --git a/core/shared/utils/bh_vector.h b/core/shared/utils/bh_vector.h index 548c8497..1ae7c279 100644 --- a/core/shared/utils/bh_vector.h +++ b/core/shared/utils/bh_vector.h @@ -15,14 +15,14 @@ extern "C" { #define DEFAULT_VECTOR_INIT_SIZE 8 typedef struct Vector { - /* size of each element */ - uint32 size_elem; /* max element number */ - uint32 max_elements; - /* current element num */ - uint32 num_elements; + size_t max_elems; /* vector data allocated */ uint8 *data; + /* current element num */ + size_t num_elems; + /* size of each element */ + size_t size_elem; } Vector; /** diff --git a/doc/wasm_c_api.md b/doc/wasm_c_api.md new file mode 100644 index 00000000..6d227874 --- /dev/null +++ b/doc/wasm_c_api.md @@ -0,0 +1,77 @@ +All samples come from the commit 340fd9528cc3b26d22fe30ee1628c8c3f2b8c53b +of [wasm-c-api][https://github.com/WebAssembly/wasm-c-api]. + +Every user should be familiar with *APIs* listed in +[wasm.h][https://github.com/WebAssembly/wasm-c-api/blob/master/include/wasm.h]. + +all [examples][https://github.com/WebAssembly/wasm-c-api/tree/master/example] are +very helpful for learning. + +Currently, we support partial of *APIs* and are going to support the rest of +them in next releases. + +Supported APIs: + +``` c +/* wasm_bytevec_t APIs ... */ + +wasm_engine_t *wasm_engine_new(); +wasm_engine_t *wasm_engine_new_with_args(mem_alloc_type_t, const MemAllocOption*, runtime_mode_e); +void wasm_engine_delete(wasm_engine_t *); + +wasm_store_t *wasm_store_new(wasm_engine_t *); +void wasm_store_delete(wasm_store_t *); + +/* wasm_valtype_t APIs ... */ +/* wasm_valtype_vec_t APIs ... */ +/* wasm_functype_vec_t APIs ... */ +/* wasm_globaltype_vec_t APIs ... */ +/* wasm_val_t APIs ... */ +/* wasm_trap_t partial APIs ... */ + +wasm_module_t *wasm_module_new(wasm_store_t *, const wasm_byte_vec_t *); +void wasm_module_delete(wasm_module_t *); + +wasm_func_t *wasm_func_new(wasm_store_t *, const wasm_functype_t *, wasm_func_callback_t); +wasm_func_t *wasm_func_new_with_env(wasm_store_t *store, const wasm_functype_t *, wasm_func_callback_with_env_t, void *env, void (*finalizer)(void *)); +void wasm_func_delete(wasm_func_t *); +wasm_fucn_t *wasm_func_copy(const wasm_func_t *); +wasm_functype_t *wasm_func_type(const wasm_func_t *); +wasm_trap_t * wasm_func_call(const wasm_func_t *, const wasm_val_t params[], wasm_val_t results[]); +size_t wasm_func_param_arity(const wasm_func_t *); +size_t wasm_func_result_arity(const wasm_func_t *); + +wasm_global_t *wasm_global_new(wasm_store_t *, const wasm_globaltype_t *, const wasm_val_t *); +wasm_global_t * wasm_global_copy(const wasm_global_t *); +void wasm_global_delete(wasm_global_t *); +bool wasm_global_same(const wasm_global_t *, const wasm_global_t *); +void wasm_global_set(wasm_global_t *, const wasm_val_t *); +void wasm_global_get(const wasm_global_t *, wasm_val_t *out); +wasm_globaltype_t * wasm_global_type(const wasm_global_t *); + +wasm_instance_t *wasm_instance_new(wasm_store_t *, const wasm_module_t *, const wasm_extern_t *const imports[], wasm_trap_t **traps); +void wasm_instance_delete(wasm_instance_t *); +void wasm_instance_exports(const wasm_instance_t *, wasm_extern_vec_t *out); + +/* wasm_extern_t APIs */ +``` + +Unsupported APIs: + +``` c +/* wasm_tabletype_t APIs */ +/* wasm_memorytype_t APIs */ +/* wasm_externtype_t APIs */ +/* wasm_importtype_t APIs */ +/* wasm_exporttype_t APIs */ +/* wasm_ref_t APIs */ +/* wasm_shared_##name##_t APIs */ + +WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); +WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); +WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); +WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); + +/* wasm_table_t APIs */ +/* wasm_memory_t APIs */ +``` diff --git a/samples/multi-module/CMakeLists.txt b/samples/multi-module/CMakeLists.txt index 774524c6..ac06fcb3 100644 --- a/samples/multi-module/CMakeLists.txt +++ b/samples/multi-module/CMakeLists.txt @@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 2.8) project(multi_module) -set(CMAKE_VERBOSE_MAKEFILE on) ################ runtime settings ################ set(WAMR_BUILD_PLATFORM "linux") @@ -18,7 +17,7 @@ set(WAMR_BUILD_INTERP 1) set(WAMR_BUILD_AOT 0) set(WAMR_BUILD_JIT 0) set(WAMR_BUILD_LIBC_BUILTIN 1) -set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_LIBC_WASI 0) set(WAMR_BUILD_FAST_INTERP 0) set(WAMR_BUILD_MULTI_MODULE 1) diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt new file mode 100644 index 00000000..6e0a4722 --- /dev/null +++ b/samples/wasm-c-api/CMakeLists.txt @@ -0,0 +1,89 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8) +project(c-api) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() +################ runtime settings ################ +set(WAMR_BUILD_PLATFORM "linux") + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch +set(WAMR_BUILD_TARGET "X86_64") + +if(NOT DEFINED WAMR_BUILD_INTERP) + set(WAMR_BUILD_INTERP 1) +endif() + +if(NOT DEFINED WAMR_BUILD_AOT) + set(WAMR_BUILD_AOT 0) +endif() + +if(NOT DEFINED WAMR_BUILD_JOT) + set(WAMR_BUILD_JIT 0) +endif() + +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_LIBC_WASI 0) + +if(NOT DEFINED WAMR_BUILD_FAST_INTERP) + set(WAMR_BUILD_FAST_INTERP 0) +endif() + +# compiling and linking flags +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -mindirect-branch-register") + +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +set(WAMRC ${WAMR_ROOT_DIR}/wamr-compiler/build/wamrc) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) +################################################ + +################ application related ################ +file(GLOB SOURCES src/*.c) +add_library(c-api ${SOURCES}) +target_include_directories(c-api + PRIVATE ${C_API_PATH}/include +) +target_link_libraries(c-api PRIVATE vmlib -lpthread -lm) + +foreach(SRC ${SOURCES}) + get_filename_component(APPNAME ${SRC} NAME_WE) + + # build executable for each .c + add_executable(${APPNAME} ${SRC}) + message("create executable about ${APPNAME}") + target_link_libraries(${APPNAME} c-api) + + # copy .wasm + add_custom_command(TARGET ${APPNAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/src/${APPNAME}.wasm + ${PROJECT_BINARY_DIR}/ + BYPRODUCTS ${APPNAME}.wasm + COMMENT "Copy ${SRC} to the output directory" + ) + + # generate .aot file + if(${WAMR_BUILD_AOT} EQUAL 1) + if(EXISTS ${WAMRC}) + add_custom_command(TARGET ${APPNAME} POST_BUILD + COMMAND ${WAMRC} -o ${APPNAME}.aot + ${CMAKE_CURRENT_SOURCE_DIR}/src/${APPNAME}.wasm + BYPRODUCTS ${APPNAME}.aot + COMMENT "generate a aot file ${APPNAME}.aot" + ) + endif() + endif() + +endforeach(SRC ${SOURCES}) +################################################ diff --git a/samples/wasm-c-api/README.md b/samples/wasm-c-api/README.md new file mode 100644 index 00000000..31d2aea0 --- /dev/null +++ b/samples/wasm-c-api/README.md @@ -0,0 +1,39 @@ +WAMR supports *wasm-c-api* in both *interpreter* mode and *aot* mode. By default, +all samples are compiled and run in "interpreter" mode. + +``` shell +$ mkdir build +$ cd build +$ cmake .. +$ make +$ # it will build a library with c-api supporting. +$ # Also copy *.wasm from ../src/ +$ # and generate executable files +$ # now, it is ok to run samples +$ ./hello +$ ... +$ ./global +$ ... +$ ./callback +$ ... +``` + +They can be compiled and run in *aot* mode when some compiling flags are given. + +``` shell +$ mkdir build +$ cd build +$ cmake -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 .. +$ make +$ # it will build a library with c-api supporting. +$ # Also copy *.wasm from ../src/ +$ # and transform *.wasm to *.aot +$ # and generate executable files +$ # now, it is ok to run samples +$ ./hello +$ ... +$ ./global +$ ... +$ ./callback +$ ... +``` \ No newline at end of file diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c new file mode 100644 index 00000000..df2e6559 --- /dev/null +++ b/samples/wasm-c-api/src/callback.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +// Print a Wasm value +void wasm_val_print(wasm_val_t val) { + switch (val.kind) { + case WASM_I32: { + printf("%" PRIu32, val.of.i32); + } break; + case WASM_I64: { + printf("%" PRIu64, val.of.i64); + } break; + case WASM_F32: { + printf("%f", val.of.f32); + } break; + case WASM_F64: { + printf("%g", val.of.f64); + } break; + case WASM_ANYREF: + case WASM_FUNCREF: { + if (val.of.ref == NULL) { + printf("null"); + } else { + printf("ref(%p)", val.of.ref); + } + } break; + } +} + +// A function to be called from Wasm code. +own wasm_trap_t* print_callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n> "); + wasm_val_print(args[0]); + printf("\n"); + + wasm_val_copy(&results[0], &args[0]); + return NULL; +} + + +// A function closure. +own wasm_trap_t* closure_callback( + void* env, const wasm_val_t args[], wasm_val_t results[] +) { + int i = *(int*)env; + printf("Calling back closure...\n"); + printf("> %d\n", i); + + results[0].kind = WASM_I32; + results[0].of.i32 = (int32_t)i; + return NULL; +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("callback.wasm", "rb"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* print_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32()); + own wasm_func_t* print_func = wasm_func_new(store, print_type, print_callback); + + int i = 42; + own wasm_functype_t* closure_type = wasm_functype_new_0_1(wasm_valtype_new_i32()); + own wasm_func_t* closure_func = wasm_func_new_with_env(store, closure_type, closure_callback, &i, NULL); + + wasm_functype_delete(print_type); + wasm_functype_delete(closure_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { + wasm_func_as_extern(print_func), wasm_func_as_extern(closure_func) + }; + own wasm_instance_t* instance = + wasm_instance_new(store, module, imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(print_func); + wasm_func_delete(closure_func); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return 1; + } + const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + wasm_val_t args[2]; + args[0].kind = WASM_I32; + args[0].of.i32 = 3; + args[1].kind = WASM_I32; + args[1].of.i32 = 4; + wasm_val_t results[1]; + if (wasm_func_call(run_func, args, results)) { + printf("> Error calling function!\n"); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Print result. + printf("Printing result...\n"); + printf("> %u\n", results[0].of.i32); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/callback.wasm b/samples/wasm-c-api/src/callback.wasm new file mode 100644 index 00000000..7e00b580 Binary files /dev/null and b/samples/wasm-c-api/src/callback.wasm differ diff --git a/samples/wasm-c-api/src/callback.wat b/samples/wasm-c-api/src/callback.wat new file mode 100644 index 00000000..d86195f5 --- /dev/null +++ b/samples/wasm-c-api/src/callback.wat @@ -0,0 +1,10 @@ +(module + (func $print (import "" "print") (param i32) (result i32)) + (func $closure (import "" "closure") (result i32)) + (func (export "run") (param $x i32) (param $y i32) (result i32) + (i32.add + (call $print (i32.add (local.get $x) (local.get $y))) + (call $closure) + ) + ) +) diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c new file mode 100644 index 00000000..ba73d95e --- /dev/null +++ b/samples/wasm-c-api/src/global.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +wasm_global_t* get_export_global(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_global(exports->data[i])) { + printf("> Error accessing global export %zu!\n", i); + exit(1); + } + return wasm_extern_as_global(exports->data[i]); +} + +wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) { + printf("> Error accessing function export %zu!\n", i); + exit(1); + } + return wasm_extern_as_func(exports->data[i]); +} + + +#define check(val, type, expected) \ + if (val.of.type != expected) { \ + printf("> Error reading value\n"); \ + exit(1); \ + } + +#define check_global(global, type, expected) \ + { \ + wasm_val_t val; \ + wasm_global_get(global, &val); \ + check(val, type, expected); \ + } + +#define check_call(func, type, expected) \ + { \ + wasm_val_t results[1]; \ + wasm_func_call(func, NULL, results); \ + check(results[0], type, expected); \ + } + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("global.aot", "rb"); +#else + FILE* file = fopen("global.wasm", "rb"); +#endif + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external globals. + printf("Creating globals...\n"); + own wasm_globaltype_t* const_f32_type = wasm_globaltype_new( + wasm_valtype_new(WASM_F32), WASM_CONST); + own wasm_globaltype_t* const_i64_type = wasm_globaltype_new( + wasm_valtype_new(WASM_I64), WASM_CONST); + own wasm_globaltype_t* var_f32_type = wasm_globaltype_new( + wasm_valtype_new(WASM_F32), WASM_VAR); + own wasm_globaltype_t* var_i64_type = wasm_globaltype_new( + wasm_valtype_new(WASM_I64), WASM_VAR); + + wasm_val_t val_f32_1 = {.kind = WASM_F32, .of = {.f32 = 1}}; + own wasm_global_t* const_f32_import = + wasm_global_new(store, const_f32_type, &val_f32_1); + wasm_val_t val_i64_2 = {.kind = WASM_I64, .of = {.i64 = 2}}; + own wasm_global_t* const_i64_import = + wasm_global_new(store, const_i64_type, &val_i64_2); + wasm_val_t val_f32_3 = {.kind = WASM_F32, .of = {.f32 = 3}}; + own wasm_global_t* var_f32_import = + wasm_global_new(store, var_f32_type, &val_f32_3); + wasm_val_t val_i64_4 = {.kind = WASM_I64, .of = {.i64 = 4}}; + own wasm_global_t* var_i64_import = + wasm_global_new(store, var_i64_type, &val_i64_4); + + wasm_globaltype_delete(const_f32_type); + wasm_globaltype_delete(const_i64_type); + wasm_globaltype_delete(var_f32_type); + wasm_globaltype_delete(var_i64_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { + wasm_global_as_extern(const_f32_import), + wasm_global_as_extern(const_i64_import), + wasm_global_as_extern(var_f32_import), + wasm_global_as_extern(var_i64_import) + }; + own wasm_instance_t* instance = + wasm_instance_new(store, module, imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_module_delete(module); + + // Extract export. + printf("Extracting exports...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + size_t i = 0; + wasm_global_t* const_f32_export = get_export_global(&exports, i++); + wasm_global_t* const_i64_export = get_export_global(&exports, i++); + wasm_global_t* var_f32_export = get_export_global(&exports, i++); + wasm_global_t* var_i64_export = get_export_global(&exports, i++); + wasm_func_t* get_const_f32_import = get_export_func(&exports, i++); + wasm_func_t* get_const_i64_import = get_export_func(&exports, i++); + wasm_func_t* get_var_f32_import = get_export_func(&exports, i++); + wasm_func_t* get_var_i64_import = get_export_func(&exports, i++); + wasm_func_t* get_const_f32_export = get_export_func(&exports, i++); + wasm_func_t* get_const_i64_export = get_export_func(&exports, i++); + wasm_func_t* get_var_f32_export = get_export_func(&exports, i++); + wasm_func_t* get_var_i64_export = get_export_func(&exports, i++); + wasm_func_t* set_var_f32_import = get_export_func(&exports, i++); + wasm_func_t* set_var_i64_import = get_export_func(&exports, i++); + wasm_func_t* set_var_f32_export = get_export_func(&exports, i++); + wasm_func_t* set_var_i64_export = get_export_func(&exports, i++); + + // Try cloning. + own wasm_global_t* copy = wasm_global_copy(var_f32_import); + assert(wasm_global_same(var_f32_import, copy)); + wasm_global_delete(copy); + + // Interact. + printf("Accessing globals...\n"); + + // Check initial values. + check_global(const_f32_import, f32, 1); + check_global(const_i64_import, i64, 2); + check_global(var_f32_import, f32, 3); + check_global(var_i64_import, i64, 4); + check_global(const_f32_export, f32, 5); + check_global(const_i64_export, i64, 6); + check_global(var_f32_export, f32, 7); + check_global(var_i64_export, i64, 8); + + check_call(get_const_f32_import, f32, 1); + check_call(get_const_i64_import, i64, 2); + check_call(get_var_f32_import, f32, 3); + check_call(get_var_i64_import, i64, 4); + check_call(get_const_f32_export, f32, 5); + check_call(get_const_i64_export, i64, 6); + check_call(get_var_f32_export, f32, 7); + check_call(get_var_i64_export, i64, 8); + + // Modify variables through API and check again. + wasm_val_t val33 = {.kind = WASM_F32, .of = {.f32 = 33}}; + wasm_global_set(var_f32_import, &val33); + wasm_val_t val34 = {.kind = WASM_I64, .of = {.i64 = 34}}; + wasm_global_set(var_i64_import, &val34); + wasm_val_t val37 = {.kind = WASM_F32, .of = {.f32 = 37}}; + wasm_global_set(var_f32_export, &val37); + wasm_val_t val38 = {.kind = WASM_I64, .of = {.i64 = 38}}; + wasm_global_set(var_i64_export, &val38); + + check_global(var_f32_import, f32, 33); + check_global(var_i64_import, i64, 34); + check_global(var_f32_export, f32, 37); + check_global(var_i64_export, i64, 38); + + check_call(get_var_f32_import, f32, 33); + check_call(get_var_i64_import, i64, 34); + check_call(get_var_f32_export, f32, 37); + check_call(get_var_i64_export, i64, 38); + + // Modify variables through calls and check again. + wasm_val_t args73[] = { {.kind = WASM_F32, .of = {.f32 = 73}} }; + wasm_func_call(set_var_f32_import, args73, NULL); + wasm_val_t args74[] = { {.kind = WASM_I64, .of = {.i64 = 74}} }; + wasm_func_call(set_var_i64_import, args74, NULL); + wasm_val_t args77[] = { {.kind = WASM_F32, .of = {.f32 = 77}} }; + wasm_func_call(set_var_f32_export, args77, NULL); + wasm_val_t args78[] = { {.kind = WASM_I64, .of = {.i64 = 78}} }; + wasm_func_call(set_var_i64_export, args78, NULL); + + check_global(var_f32_import, f32, 73); + check_global(var_i64_import, i64, 74); + check_global(var_f32_export, f32, 77); + check_global(var_i64_export, i64, 78); + + check_call(get_var_f32_import, f32, 73); + check_call(get_var_i64_import, i64, 74); + check_call(get_var_f32_export, f32, 77); + check_call(get_var_i64_export, i64, 78); + + wasm_global_delete(const_f32_import); + wasm_global_delete(const_i64_import); + wasm_global_delete(var_f32_import); + wasm_global_delete(var_i64_import); + wasm_extern_vec_delete(&exports); + wasm_instance_delete(instance); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/global.wasm b/samples/wasm-c-api/src/global.wasm new file mode 100644 index 00000000..0e768632 Binary files /dev/null and b/samples/wasm-c-api/src/global.wasm differ diff --git a/samples/wasm-c-api/src/global.wat b/samples/wasm-c-api/src/global.wat new file mode 100644 index 00000000..dea08577 --- /dev/null +++ b/samples/wasm-c-api/src/global.wat @@ -0,0 +1,27 @@ +(module + (global $f32_import (import "" "const f32") f32) + (global $i64_import (import "" "const i64") i64) + (global $mut_f32_import (import "" "var f32") (mut f32)) + (global $mut_i64_import (import "" "var i64") (mut i64)) + + (global $f32_export (export "const f32") f32 (f32.const 5)) + (global $i64_export (export "const i64") i64 (i64.const 6)) + (global $mut_f32_export (export "var f32") (mut f32) (f32.const 7)) + (global $mut_i64_export (export "var i64") (mut i64) (i64.const 8)) + + (func (export "get const f32 import") (result f32) (global.get $f32_import)) + (func (export "get const i64 import") (result i64) (global.get $i64_import)) + (func (export "get var f32 import") (result f32) (global.get $mut_f32_import)) + (func (export "get var i64 import") (result i64) (global.get $mut_i64_import)) + + (func (export "get const f32 export") (result f32) (global.get $f32_export)) + (func (export "get const i64 export") (result i64) (global.get $i64_export)) + (func (export "get var f32 export") (result f32) (global.get $mut_f32_export)) + (func (export "get var i64 export") (result i64) (global.get $mut_i64_export)) + + (func (export "set var f32 import") (param f32) (global.set $mut_f32_import (local.get 0))) + (func (export "set var i64 import") (param i64) (global.set $mut_i64_import (local.get 0))) + + (func (export "set var f32 export") (param f32) (global.set $mut_f32_export (local.get 0))) + (func (export "set var f64 export") (param i64) (global.set $mut_i64_export (local.get 0))) +) diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c new file mode 100644 index 00000000..491a24b3 --- /dev/null +++ b/samples/wasm-c-api/src/hello.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t* hello_callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n"); + printf("> Hello World!\n"); + return NULL; +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("hello.aot", "rb"); +#else + FILE* file = fopen("hello.wasm", "rb"); +#endif + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* hello_type = wasm_functype_new_0_0(); + own wasm_func_t* hello_func = + wasm_func_new(store, hello_type, hello_callback); + + wasm_functype_delete(hello_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) }; + own wasm_instance_t* instance = + wasm_instance_new(store, module, imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(hello_func); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return 1; + } + const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + if (wasm_func_call(run_func, NULL, NULL)) { + printf("> Error calling function!\n"); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/samples/wasm-c-api/src/hello.wasm b/samples/wasm-c-api/src/hello.wasm new file mode 100644 index 00000000..2207c03e Binary files /dev/null and b/samples/wasm-c-api/src/hello.wasm differ diff --git a/samples/wasm-c-api/src/hello.wat b/samples/wasm-c-api/src/hello.wat new file mode 100644 index 00000000..1c56c558 --- /dev/null +++ b/samples/wasm-c-api/src/hello.wat @@ -0,0 +1,4 @@ +(module + (func $hello (import "" "hello")) + (func (export "run") (call $hello)) +)