diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 717cbbed..f55e66eb 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -33,14 +33,14 @@ jobs: cmake .. make -j $(nproc) cd .. && rm -rf build - - name: Build iwasm [Classic interp] + - name: Build iwasm [classic interp] run: | cd product-mini/platforms/android mkdir build && cd build cmake .. -DWAMR_BUILD_FAST_INTERP=0 make -j $(nproc) cd .. && rm -rf build - - name: Build iwasm [Multi module] + - name: Build iwasm [multi module] run: | cd product-mini/platforms/android mkdir build && cd build @@ -89,3 +89,24 @@ jobs: cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 make -j $(nproc) cd .. && rm -rf build + - name: Build iwasm [disable hardware boundary check] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_DISABLE_HW_BOUND_CHECK=1 + make -j $(nproc) + cd .. && rm -rf build + - name: Build iwasm [reference types] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_REF_TYPES=1 + make -j $(nproc) + cd .. && rm -rf build + - name: Build iwasm [128-bit SIMD] + run: | + cd product-mini/platforms/android + mkdir build && cd build + cmake .. -DWAMR_BUILD_SIMD=1 + make -j $(nproc) + cd .. && rm -rf build diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 6f5e5942..c73b3a86 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -31,14 +31,14 @@ jobs: cmake .. make -j $(nproc) cd .. && rm -rf build - - name: Build iwasm [Classic interp] + - name: Build iwasm [classic interp] run: | cd product-mini/platforms/linux mkdir build && cd build cmake .. -DWAMR_BUILD_FAST_INTERP=0 make -j $(nproc) cd .. && rm -rf build - - name: Build iwasm [Multi module] + - name: Build iwasm [multi module] run: | cd product-mini/platforms/linux mkdir build && cd build @@ -87,6 +87,27 @@ jobs: cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 make -j $(nproc) cd .. && rm -rf build + - name: Build iwasm [disable hardware boundary check] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_DISABLE_HW_BOUND_CHECK=1 + make -j $(nproc) + cd .. && rm -rf build + - name: Build iwasm [reference types] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_REF_TYPES=1 + make -j $(nproc) + cd .. && rm -rf build + - name: Build iwasm [128-bit SIMD] + run: | + cd product-mini/platforms/linux + mkdir build && cd build + cmake .. -DWAMR_BUILD_SIMD=1 + make -j $(nproc) + cd .. && rm -rf build - name: Cache LLVM libraries uses: actions/cache@v2 id: cache_llvm @@ -132,7 +153,10 @@ jobs: ./callback_chain ./global ./hello + ./hostref + ./memory ./reflect + ./table ./trap cd .. && rm -r build - name: Build Sample [wasm-c-api] [Jit] @@ -145,7 +169,10 @@ jobs: ./callback_chain ./global ./hello + ./hostref + ./memory ./reflect + ./table ./trap cd .. && rm -r build - name: Build Sample [wasm-c-api] [Aot] @@ -158,7 +185,10 @@ jobs: ./callback_chain ./global ./hello + ./hostref + ./memory ./reflect + ./table ./trap cd .. && rm -r build - name: Build Sample [basic] @@ -187,3 +217,10 @@ jobs: cmake .. make -j $(nproc) ./spawn_thread + - name: Build Sample [ref-types] + run: | + cd samples/ref-types + mkdir build && cd build + cmake .. + make -j $(nproc) + ./hello diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 6c8704b2..7422d84f 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -26,63 +26,84 @@ jobs: cd product-mini/platforms/darwin mkdir build && cd build cmake .. - make + make -j $(nproc) cd .. && rm -rf build - - name: Build iwasm [Classic interp] + - name: Build iwasm [classic interp] run: | cd product-mini/platforms/darwin mkdir build && cd build cmake .. -DWAMR_BUILD_FAST_INTERP=0 - make + make -j $(nproc) cd .. && rm -rf build - - name: Build iwasm [Multi module] + - name: Build iwasm [multi module] run: | cd product-mini/platforms/darwin mkdir build && cd build cmake .. -DWAMR_BUILD_MULTI_MODULE=1 - make + make -j $(nproc) cd .. && rm -rf build - name: Build iwasm [lib-pthread] run: | cd product-mini/platforms/darwin mkdir build && cd build cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 - make + make -j $(nproc) cd .. && rm -rf build - name: Build iwasm [aot only] run: | cd product-mini/platforms/darwin mkdir build && cd build cmake .. -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0 - make + make -j $(nproc) cd .. && rm -rf build - name: Build iwasm [interp only] run: | cd product-mini/platforms/darwin mkdir build && cd build cmake .. -DWAMR_BUILD_AOT=0 - make + make -j $(nproc) cd .. && rm -rf build - name: Build iwasm [memory profiling] run: | cd product-mini/platforms/darwin mkdir build && cd build cmake .. -DWAMR_BUILD_MEMORY_PROFILING=1 - make + make -j $(nproc) cd .. && rm -rf build - name: Build iwasm [tail call] run: | cd product-mini/platforms/darwin mkdir build && cd build cmake .. -DWAMR_BUILD_TAIL_CALL=1 - make + make -j $(nproc) cd .. && rm -rf build - name: Build iwasm [custom name section] run: | cd product-mini/platforms/darwin mkdir build && cd build cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 - make + make -j $(nproc) + cd .. && rm -rf build + - name: Build iwasm [disable hardware boundary check] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_DISABLE_HW_BOUND_CHECK=1 + make -j $(nproc) + cd .. && rm -rf build + - name: Build iwasm [ref types] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_REF_TYPES=1 + make -j $(nproc) + cd .. && rm -rf build + - name: Build iwasm [128-bit SIMD] + run: | + cd product-mini/platforms/darwin + mkdir build && cd build + cmake .. -DWAMR_BUILD_SIMD=1 + make -j $(nproc) cd .. && rm -rf build - name: download and install wabt run: | @@ -96,6 +117,12 @@ jobs: mkdir build && cd build cmake .. make - ./hello - ./global ./callback + ./callback_chain + ./global + ./hello + ./hostref + ./memory + ./reflect + ./table + ./trap diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 3ae374f9..b5c0eeaf 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -60,4 +60,25 @@ jobs: cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 cmake --build . --config Release cd .. && rm -force -r build + - name: Build iwasm [disable hardware boundary check] + run: | + cd product-mini/platforms/windows + mkdir build && cd build + cmake .. -DWAMR_DISABLE_HW_BOUND_CHECK=1 + cmake --build . --config Release + cd .. && rm -force -r build + - name: Build iwasm [reference types] + run: | + cd product-mini/platforms/windows + mkdir build && cd build + cmake .. -DWAMR_BUILD_REF_TYPES=1 + cmake --build . --config Release + cd .. && rm -force -r build + - name: Build iwasm [128-bit SIMD] + run: | + cd product-mini/platforms/windows + mkdir build && cd build + cmake .. -DWAMR_BUILD_SIMD=1 + cmake --build . --config Release + cd .. && rm -force -r build diff --git a/README.md b/README.md index 5a0e04e9..29e1c9a9 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a Project Technical Steering Committee ==================================== -The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC. +The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC. The current TSC members: - [lum1n0us](https://github.com/lum1n0us) - **Liang He**, - [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin**, diff --git a/TSC_Charter.md b/TSC_Charter.md index 3ede0ce8..56c4a024 100644 --- a/TSC_Charter.md +++ b/TSC_Charter.md @@ -2,9 +2,9 @@ ## Section 1. Guiding Principle -The WebAssembly Micro Runtime (WAMR) project is part of the -Bytecode Alliance (BA) which operates transparently, openly, -collaboratively, and ethically. Project proposals, timelines, and status +The WebAssembly Micro Runtime (WAMR) project is part of the +Bytecode Alliance (BA) which operates transparently, openly, +collaboratively, and ethically. Project proposals, timelines, and status must not merely be open, but also easily visible to outsiders. ## Section 2. Project Governance under Bytecode Alliance @@ -17,8 +17,8 @@ there is misalignment between the project charter and the BA mission and values. -The PTSC structure described in this document may be overhauled as part of -establishing a BA TSC in order to adhere to constraints or requirements that +The PTSC structure described in this document may be overhauled as part of +establishing a BA TSC in order to adhere to constraints or requirements that TSC will impose on project-level governance. ## Section 3. Establishment of the PTSC diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 4cb2d342..8cdbf02f 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -2822,9 +2822,12 @@ aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx, return orig_tbl_sz; } + if (tbl_inst->cur_size > UINT32_MAX - inc_entries) { + return (uint32)-1; + } + entry_count = tbl_inst->cur_size + inc_entries; - /* prevent from integer overflow */ - if (entry_count < tbl_inst->cur_size || entry_count > tbl_inst->max_size) { + if (entry_count > tbl_inst->max_size) { return (uint32)-1; } diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 6de88510..8a128dda 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -5,6 +5,7 @@ #include "wasm_c_api_internal.h" #include "wasm_memory.h" +#include "wasm_runtime_common.h" #if WASM_ENABLE_INTERP != 0 #include "wasm_runtime.h" #endif @@ -13,6 +14,7 @@ #endif #define ASSERT_NOT_IMPLEMENTED() bh_assert(!"not implemented") +#define UNREACHABLE() bh_assert(!"unreachable") typedef struct wasm_module_ex_t wasm_module_ex_t; @@ -47,7 +49,8 @@ wasm_instance_copy(const wasm_instance_t *src) return NULL; } -static void * +/* ---------------------------------------------------------------------- */ +static inline void * malloc_internal(uint64 size) { void *mem = NULL; @@ -59,11 +62,6 @@ malloc_internal(uint64 size) return mem; } -#define FREEIF(p) \ - if (p) { \ - wasm_runtime_free(p); \ - } - /* clang-format off */ #define RETURN_OBJ(obj, obj_del_func) \ return obj; \ @@ -132,8 +130,8 @@ failed: \ } \ \ if (data) { \ - unsigned int size_in_bytes = 0; \ - size_in_bytes = size * sizeof(wasm_##name##_t); \ + uint32 size_in_bytes = 0; \ + size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t)); \ bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \ out->num_elems = size; \ } \ @@ -175,8 +173,8 @@ failed: \ } \ \ if (data) { \ - unsigned int size_in_bytes = 0; \ - size_in_bytes = size * sizeof(wasm_##name##_t *); \ + uint32 size_in_bytes = 0; \ + size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t *)); \ bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \ out->num_elems = size; \ } \ @@ -224,37 +222,15 @@ failed: \ WASM_DEFINE_VEC_PLAIN(byte) WASM_DEFINE_VEC_PLAIN(val) -WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) -WASM_DEFINE_VEC_OWN(functype, wasm_functype_delete) WASM_DEFINE_VEC_OWN(exporttype, wasm_exporttype_delete) -WASM_DEFINE_VEC_OWN(importtype, wasm_importtype_delete) -WASM_DEFINE_VEC_OWN(store, wasm_store_delete) -WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) -WASM_DEFINE_VEC_OWN(instance, wasm_instance_delete_internal) WASM_DEFINE_VEC_OWN(extern, wasm_extern_delete) WASM_DEFINE_VEC_OWN(frame, wasm_frame_delete) - -static inline bool -valid_module_type(uint32 module_type) -{ - bool result = false; - -#if WASM_ENABLE_INTERP != 0 - result = result || (module_type == Wasm_Module_Bytecode); -#endif - -#if WASM_ENABLE_AOT != 0 - result = result || (module_type == Wasm_Module_AoT); -#endif - - if (!result) { - LOG_VERBOSE( - "current building isn't compatiable with the module, may need " - "recompile"); - } - - return result; -} +WASM_DEFINE_VEC_OWN(functype, wasm_functype_delete) +WASM_DEFINE_VEC_OWN(importtype, wasm_importtype_delete) +WASM_DEFINE_VEC_OWN(instance, wasm_instance_delete_internal) +WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) +WASM_DEFINE_VEC_OWN(store, wasm_store_delete) +WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) /* conflicting declaration between aot_export.h and aot.h */ #if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 @@ -427,6 +403,11 @@ wasm_store_new(wasm_engine_t *engine) INIT_VEC(store->instances, wasm_instance_vec_new_uninitialized, DEFAULT_VECTOR_INIT_LENGTH); + if (!(store->foreigns = malloc_internal(sizeof(Vector))) + || !(bh_vector_init(store->foreigns, 24, sizeof(Vector *)))) { + goto failed; + } + /* append to a store list of engine */ if (!bh_vector_append((Vector *)singleton_engine->stores, &store)) { LOG_DEBUG("bh_vector_append failed"); @@ -453,43 +434,47 @@ wasm_store_delete(wasm_store_t *store) for (i = 0; i != store_count; ++i) { wasm_store_t *tmp; - if (!bh_vector_get((Vector *)singleton_engine->stores, i, &tmp)) { + if (!bh_vector_get((Vector *)singleton_engine->stores, + (uint32)i, &tmp)) { break; } if (tmp == store) { - bh_vector_remove((Vector *)singleton_engine->stores, i, NULL); + bh_vector_remove((Vector *)singleton_engine->stores, + (uint32)i, NULL); break; } } DEINIT_VEC(store->modules, wasm_module_vec_delete); DEINIT_VEC(store->instances, wasm_instance_vec_delete); + if (store->foreigns) { + bh_vector_destroy(store->foreigns); + wasm_runtime_free(store->foreigns); + } + wasm_runtime_free(store); wasm_runtime_destroy_thread_env(); } /* Type Representations */ -static wasm_valkind_t +static inline wasm_valkind_t val_type_rt_2_valkind(uint8 val_type_rt) { switch (val_type_rt) { - case VALUE_TYPE_I32: - return WASM_I32; - case VALUE_TYPE_I64: - return WASM_I64; - case VALUE_TYPE_F32: - return WASM_F32; - case VALUE_TYPE_F64: - return WASM_F64; - case VALUE_TYPE_ANY: - return WASM_ANYREF; - case VALUE_TYPE_FUNCREF: - return WASM_FUNCREF; +#define WAMR_VAL_TYPE_2_WASM_VAL_KIND(name) \ + case VALUE_TYPE_##name: \ + return WASM_##name; + + WAMR_VAL_TYPE_2_WASM_VAL_KIND(I32) + WAMR_VAL_TYPE_2_WASM_VAL_KIND(I64) + WAMR_VAL_TYPE_2_WASM_VAL_KIND(F32) + WAMR_VAL_TYPE_2_WASM_VAL_KIND(F64) + WAMR_VAL_TYPE_2_WASM_VAL_KIND(FUNCREF) +#undef WAMR_VAL_TYPE_2_WASM_VAL_KIND + default: - LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, - val_type_rt); return WASM_ANYREF; } } @@ -517,41 +502,21 @@ wasm_valtype_new(wasm_valkind_t kind) void wasm_valtype_delete(wasm_valtype_t *val_type) { - FREEIF(val_type); + if (val_type) { + wasm_runtime_free(val_type); + } } wasm_valtype_t * wasm_valtype_copy(const wasm_valtype_t *src) { - if (!src) { - return NULL; - } - - return wasm_valtype_new(src->kind); + return src ? wasm_valtype_new(src->kind) : NULL; } wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t *val_type) { - if (!val_type) { - return WASM_ANYREF; - } - - 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; + return val_type ? val_type->kind : WASM_ANYREF; } static wasm_functype_t * @@ -808,22 +773,6 @@ wasm_globaltype_mutability(const wasm_globaltype_t *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; -} - static wasm_tabletype_t * wasm_tabletype_new_internal(uint8 val_type_rt, uint32 init_size, @@ -961,7 +910,9 @@ wasm_memorytype_copy(const wasm_memorytype_t *src) void wasm_memorytype_delete(wasm_memorytype_t *memory_type) { - FREEIF(memory_type); + if (memory_type) { + wasm_runtime_free(memory_type); + } } const wasm_limits_t * @@ -1288,11 +1239,12 @@ wasm_exporttype_type(const wasm_exporttype_t *export_type) } /* Runtime Objects */ - void wasm_val_delete(wasm_val_t *v) { - FREEIF(v); + if (v) { + wasm_runtime_free(v); + } } void @@ -1306,37 +1258,246 @@ wasm_val_copy(wasm_val_t *out, const wasm_val_t *src) } bool -wasm_val_same(const wasm_val_t *v1, const wasm_val_t *v2) +rt_val_to_wasm_val(const uint8 *data, uint8 val_type_rt, wasm_val_t *out) { - 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; + bool ret = true; + switch (val_type_rt) { + case VALUE_TYPE_I32: + out->kind = WASM_I32; + out->of.i32 = *((int32 *)data); + break; + case VALUE_TYPE_F32: + out->kind = WASM_F32; + out->of.f32 = *((float32 *)data); + break; + case VALUE_TYPE_I64: + out->kind = WASM_I64; + out->of.i64 = *((int64 *)data); + break; + case VALUE_TYPE_F64: + out->kind = WASM_F64; + out->of.f64 = *((float64 *)data); + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + out->kind = WASM_ANYREF; + if (NULL_REF == *(uint32 *)data) { + out->of.ref = NULL; + } + else { + ret = wasm_externref_ref2obj(*(uint32 *)data, + (void **)&out->of.ref); + } + break; +#endif default: + LOG_WARNING("unexpected value type %d", val_type_rt); + ret = false; + } + return ret; +} + +bool +wasm_val_to_rt_val(WASMModuleInstanceCommon *inst_comm_rt, + uint8 val_type_rt, + const wasm_val_t *v, + uint8 *data) +{ + bool ret = true; + switch (val_type_rt) { + case VALUE_TYPE_I32: + bh_assert(WASM_I32 == v->kind); + *((int32 *)data) = v->of.i32; + break; + case VALUE_TYPE_F32: + bh_assert(WASM_F32 == v->kind); + *((float32 *)data) = v->of.f32; + break; + case VALUE_TYPE_I64: + bh_assert(WASM_I64 == v->kind); + *((int64 *)data) = v->of.i64; + break; + case VALUE_TYPE_F64: + bh_assert(WASM_F64 == v->kind); + *((float64 *)data) = v->of.f64; + break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + bh_assert(WASM_ANYREF == v->kind); + ret = + wasm_externref_obj2ref(inst_comm_rt, v->of.ref, (uint32 *)data); + break; +#endif + default: + LOG_WARNING("unexpected value type %d", val_type_rt); + ret = false; break; } - return false; + + return ret; } +wasm_ref_t * +wasm_ref_new_internal(wasm_store_t *store, + enum wasm_reference_kind kind, + uint32 ref_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_ref_t *ref; + + if (!store) { + return NULL; + } + + if (!(ref = malloc_internal(sizeof(wasm_ref_t)))) { + return NULL; + } + + ref->store = store; + ref->kind = kind; + ref->ref_idx_rt = ref_idx_rt; + ref->inst_comm_rt = inst_comm_rt; + + /* workaround */ + if (WASM_REF_foreign == kind) { + wasm_foreign_t *foreign; + + if (!(bh_vector_get(ref->store->foreigns, ref->ref_idx_rt, &foreign)) + || !foreign) { + wasm_runtime_free(ref); + return NULL; + } + + foreign->ref_cnt++; + } + /* others doesn't include ref counters */ + + return ref; +} + +own wasm_ref_t * +wasm_ref_copy(const wasm_ref_t *src) +{ + if (!src) + return NULL; + + /* host_info are different in wasm_ref_t(s) */ + return wasm_ref_new_internal(src->store, src->kind, src->ref_idx_rt, + src->inst_comm_rt); +} + +#define DELETE_HOST_INFO(obj) \ + if (obj->host_info.info) { \ + if (obj->host_info.finalizer) { \ + obj->host_info.finalizer(obj->host_info.info); \ + } \ + } + +void +wasm_ref_delete(own wasm_ref_t *ref) +{ + if (!ref) + return; + + DELETE_HOST_INFO(ref); + + if (WASM_REF_foreign == ref->kind) { + wasm_foreign_t *foreign = NULL; + + if (bh_vector_get(ref->store->foreigns, ref->ref_idx_rt, &foreign) + && foreign) { + wasm_foreign_delete(foreign); + } + } + + wasm_runtime_free(ref); +} + +#define WASM_DEFINE_REF_BASE(name) \ + bool wasm_##name##_same(const wasm_##name##_t *o1, \ + const wasm_##name##_t *o2) \ + { \ + return (!o1 && !o2) ? true \ + : (!o1 || !o2) ? false \ + : (o1->kind != o2->kind) \ + ? false \ + : o1->name##_idx_rt == o2->name##_idx_rt; \ + } \ + \ + void *wasm_##name##_get_host_info(const wasm_##name##_t *obj) \ + { \ + return obj ? obj->host_info.info : NULL; \ + } \ + \ + void wasm_##name##_set_host_info(wasm_##name##_t *obj, void *host_info) \ + { \ + if (obj) { \ + obj->host_info.info = host_info; \ + obj->host_info.finalizer = NULL; \ + } \ + } \ + \ + void wasm_##name##_set_host_info_with_finalizer( \ + wasm_##name##_t *obj, void *host_info, void (*finalizer)(void *)) \ + { \ + if (obj) { \ + obj->host_info.info = host_info; \ + obj->host_info.finalizer = finalizer; \ + } \ + } + +#define WASM_DEFINE_REF(name) \ + WASM_DEFINE_REF_BASE(name) \ + \ + wasm_ref_t *wasm_##name##_as_ref(wasm_##name##_t *name) \ + { \ + if (!name) { \ + return NULL; \ + } \ + \ + return wasm_ref_new_internal(name->store, WASM_REF_##name, \ + name->name##_idx_rt, \ + name->inst_comm_rt); \ + } \ + \ + const wasm_ref_t *wasm_##name##_as_ref_const(const wasm_##name##_t *name) \ + { \ + if (!name) { \ + return NULL; \ + } \ + \ + return wasm_ref_new_internal(name->store, WASM_REF_##name, \ + name->name##_idx_rt, \ + name->inst_comm_rt); \ + } \ + \ + wasm_##name##_t *wasm_ref_as_##name(wasm_ref_t *ref) \ + { \ + if (!ref || WASM_REF_##name != ref->kind) { \ + return NULL; \ + } \ + \ + return wasm_##name##_new_internal(ref->store, ref->ref_idx_rt, \ + ref->inst_comm_rt); \ + } \ + \ + const wasm_##name##_t *wasm_ref_as_##name##_const(const wasm_ref_t *ref) \ + { \ + if (!ref || WASM_REF_##name != ref->kind) { \ + return NULL; \ + } \ + \ + return wasm_##name##_new_internal(ref->store, ref->ref_idx_rt, \ + ref->inst_comm_rt); \ + } + +WASM_DEFINE_REF_BASE(ref) +WASM_DEFINE_REF(foreign) +WASM_DEFINE_REF(func) +WASM_DEFINE_REF(global) +WASM_DEFINE_REF(memory) +WASM_DEFINE_REF(table) + static wasm_frame_t * wasm_frame_new(wasm_instance_t *instance, size_t module_offset, @@ -1350,9 +1511,9 @@ wasm_frame_new(wasm_instance_t *instance, } frame->instance = instance; - frame->module_offset = module_offset; + frame->module_offset = (uint32)module_offset; frame->func_index = func_index; - frame->func_offset = func_offset; + frame->func_offset = (uint32)func_offset; return frame; } @@ -1370,11 +1531,9 @@ wasm_frame_copy(const wasm_frame_t *src) void wasm_frame_delete(own wasm_frame_t *frame) { - if (!frame) { - return; + if (frame) { + wasm_runtime_free(frame); } - - wasm_runtime_free(frame); } struct wasm_instance_t * @@ -1434,6 +1593,10 @@ wasm_trap_new_internal(WASMModuleInstanceCommon *inst_comm_rt, } #endif + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ if (!error_info && !(error_info = default_error_info)) { return NULL; } @@ -1564,7 +1727,7 @@ wasm_trap_trace(const wasm_trap_t *trap, own wasm_frame_vec_t *out) } wasm_frame_vec_new_uninitialized(out, trap->frames->num_elems); - if (out->size && !out->data) { + if (out->size == 0 || !out->data) { return; } @@ -1589,8 +1752,63 @@ failed: } } - if (out->data) { - wasm_runtime_free(out->data); + wasm_runtime_free(out->data); +} + +wasm_foreign_t * +wasm_foreign_new_internal(wasm_store_t *store, + uint32 foreign_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt) +{ + wasm_foreign_t *foreign = NULL; + + if (!store || !store->foreigns) + return NULL; + + if (!(bh_vector_get(store->foreigns, foreign_idx_rt, &foreign)) + || !foreign) { + return NULL; + } + + foreign->ref_cnt++; + return foreign; +} + +own wasm_foreign_t * +wasm_foreign_new(wasm_store_t *store) +{ + wasm_foreign_t *foreign; + + if (!store) + return NULL; + + if (!(foreign = malloc_internal(sizeof(wasm_foreign_t)))) + return NULL; + + foreign->store = store; + foreign->kind = WASM_REF_foreign; + foreign->foreign_idx_rt = (uint32)bh_vector_size(store->foreigns); + if (!(bh_vector_append(store->foreigns, &foreign))) { + wasm_runtime_free(foreign); + return NULL; + } + + return foreign; +} + +void +wasm_foreign_delete(wasm_foreign_t *foreign) +{ + if (!foreign) + return; + + if (foreign->ref_cnt < 1) { + return; + } + + foreign->ref_cnt--; + if (!foreign->ref_cnt) { + wasm_runtime_free(foreign); } } @@ -1612,11 +1830,11 @@ module_to_module_ext(wasm_module_t *module) } #if WASM_ENABLE_INTERP != 0 -#define MODULE_INTERP(module) ((WASMModule *)(*module)) +#define MODULE_INTERP(module_comm) ((WASMModule *)(*module_comm)) #endif #if WASM_ENABLE_AOT != 0 -#define MODULE_AOT(module) ((AOTModule *)(*module)) +#define MODULE_AOT(module_comm) ((AOTModule *)(*module_comm)) #endif wasm_module_t * @@ -1624,6 +1842,7 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) { char error_buf[128] = { 0 }; wasm_module_ex_t *module_ex = NULL; + PackageType pkg_type; #if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 uint8 *aot_file_buf = NULL; uint32 aot_file_size; @@ -1636,6 +1855,24 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) return NULL; } + pkg_type = get_package_type((uint8 *)binary->data, (uint32)binary->size); + + /* whether the combination of compilation flags are compatable with the package type */ + { + bool result = false; +#if WASM_ENABLE_INTERP != 0 + result = (pkg_type == Wasm_Module_Bytecode); +#endif + +#if WASM_ENABLE_AOT != 0 + result = result || (pkg_type == Wasm_Module_AoT); +#endif + if (!result) { + LOG_VERBOSE("current building isn't compatiable with the module," + "may need recompile"); + } + } + module_ex = malloc_internal(sizeof(wasm_module_ex_t)); if (!module_ex) { goto failed; @@ -1644,9 +1881,7 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data); #if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 - if (get_package_type((uint8 *)module_ex->binary->data, - (uint32)module_ex->binary->size) - == Wasm_Module_Bytecode) { + if (Wasm_Module_Bytecode == pkg_type) { if (!(aot_file_buf = aot_compile_wasm_file( (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, 3, 3, error_buf, @@ -1687,6 +1922,30 @@ failed: return NULL; } +bool +wasm_module_validate(wasm_store_t *store, const wasm_byte_vec_t *binary) +{ + struct WASMModuleCommon *module_rt; + char error_buf[128] = { 0 }; + + bh_assert(singleton_engine); + + if (!store || !binary || binary->size > UINT32_MAX) { + LOG_ERROR("%s failed", __FUNCTION__); + return false; + } + + if ((module_rt = wasm_runtime_load((uint8 *)binary->data, (uint32)binary->size, + error_buf, 128))) { + wasm_runtime_unload(module_rt); + return true; + } + else { + LOG_VERBOSE(error_buf); + return false; + } +} + static void wasm_module_delete_internal(wasm_module_t *module) { @@ -1724,7 +1983,7 @@ wasm_module_imports(const wasm_module_t *module, wasm_externtype_t *extern_type = NULL; wasm_importtype_t *import_type = NULL; - if (!module || !out || !valid_module_type((*module)->module_type)) { + if (!module || !out) { return; } @@ -1748,8 +2007,13 @@ wasm_module_imports(const wasm_module_t *module, import_count = import_func_count + import_global_count + import_table_count + import_memory_count; + wasm_importtype_vec_new_uninitialized(out, import_count); - if (import_count && !out->data) { + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ + if (!out->data) { return; } @@ -1964,7 +2228,7 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) wasm_externtype_t *extern_type = NULL; wasm_exporttype_t *export_type = NULL; - if (!module || !out || !valid_module_type((*module)->module_type)) { + if (!module || !out) { return; } @@ -1981,7 +2245,11 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) #endif wasm_exporttype_vec_new_uninitialized(out, export_count); - if (export_count && !out->data) { + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ + if (!out->data) { return; } @@ -1992,6 +2260,7 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) export = MODULE_INTERP(module)->exports + i; } #endif + #if WASM_ENABLE_AOT != 0 if ((*module)->module_type == Wasm_Module_AoT) { export = MODULE_AOT(module)->exports + i; @@ -2111,7 +2380,8 @@ failed_exporttype_new: } static wasm_func_t * -wasm_func_new_basic(const wasm_functype_t *type, +wasm_func_new_basic(wasm_store_t *store, + const wasm_functype_t *type, wasm_func_callback_t func_callback) { wasm_func_t *func = NULL; @@ -2120,7 +2390,9 @@ wasm_func_new_basic(const wasm_functype_t *type, goto failed; } + func->store = store; func->kind = WASM_EXTERN_FUNC; + func->func_idx_rt = (uint16)-1; func->with_env = false; func->u.cb = func_callback; @@ -2132,7 +2404,8 @@ wasm_func_new_basic(const wasm_functype_t *type, } static wasm_func_t * -wasm_func_new_with_env_basic(const wasm_functype_t *type, +wasm_func_new_with_env_basic(wasm_store_t *store, + const wasm_functype_t *type, wasm_func_callback_with_env_t callback, void *env, void (*finalizer)(void *)) @@ -2143,7 +2416,9 @@ wasm_func_new_with_env_basic(const wasm_functype_t *type, goto failed; } + func->store = store; func->kind = WASM_EXTERN_FUNC; + func->func_idx_rt = (uint16)-1; func->with_env = true; func->u.cb_env.cb = callback; func->u.cb_env.env = env; @@ -2162,7 +2437,7 @@ wasm_func_new(wasm_store_t *store, wasm_func_callback_t callback) { bh_assert(singleton_engine); - return wasm_func_new_basic(type, callback); + return wasm_func_new_basic(store, type, callback); } wasm_func_t * @@ -2173,10 +2448,10 @@ wasm_func_new_with_env(wasm_store_t *store, void (*finalizer)(void *)) { bh_assert(singleton_engine); - return wasm_func_new_with_env_basic(type, callback, env, finalizer); + return wasm_func_new_with_env_basic(store, type, callback, env, finalizer); } -static wasm_func_t * +wasm_func_t * wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt, WASMModuleInstanceCommon *inst_comm_rt) @@ -2186,7 +2461,7 @@ wasm_func_new_internal(wasm_store_t *store, bh_assert(singleton_engine); - if (!inst_comm_rt || !valid_module_type(inst_comm_rt->module_type)) { + if (!inst_comm_rt) { return NULL; } @@ -2226,6 +2501,10 @@ wasm_func_new_internal(wasm_store_t *store, } #endif + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ if (!type_rt) { goto failed; } @@ -2236,6 +2515,7 @@ wasm_func_new_internal(wasm_store_t *store, } /* will add name information when processing "exports" */ + func->store = store; func->module_name = NULL; func->name = NULL; func->func_idx_rt = func_idx_rt; @@ -2268,6 +2548,8 @@ wasm_func_delete(wasm_func_t *func) } } + DELETE_HOST_INFO(func) + wasm_runtime_free(func); } @@ -2280,11 +2562,11 @@ wasm_func_copy(const wasm_func_t *func) return NULL; } - if (!(cloned = func->with_env - ? wasm_func_new_with_env_basic( - func->type, func->u.cb_env.cb, func->u.cb_env.env, - func->u.cb_env.finalizer) - : wasm_func_new_basic(func->type, func->u.cb))) { + if (!(cloned = func->with_env ? wasm_func_new_with_env_basic( + func->store, func->type, func->u.cb_env.cb, + func->u.cb_env.env, func->u.cb_env.finalizer) + : wasm_func_new_basic( + func->store, func->type, func->u.cb))) { goto failed; } @@ -2304,7 +2586,8 @@ wasm_func_type(const wasm_func_t *func) } static uint32 -params_to_argv(const wasm_val_t *params, +params_to_argv(WASMModuleInstanceCommon *inst_comm_rt, + const wasm_val_t *params, const wasm_valtype_vec_t *param_defs, size_t param_arity, uint32 *out) @@ -2345,8 +2628,19 @@ params_to_argv(const wasm_val_t *params, out += 2; argc += 2; break; +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_ANYREF: + if (!wasm_externref_obj2ref(inst_comm_rt, param->of.ref, + out)) { + goto failed; + } + + out += 1; + argc += 1; + break; +#endif default: - LOG_DEBUG("unexpected parameter val type %d", param->kind); + LOG_WARNING("unexpected parameter val type %d", param->kind); goto failed; } } @@ -2408,6 +2702,25 @@ argv_to_results(const uint32 *results, result += 2; break; } +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_ANYREF: + { + out->kind = WASM_ANYREF; + + if (NULL_REF == *(uint32 *)result) { + out->of.ref = NULL; + } + else { + if (!wasm_externref_ref2obj(*(uint32 *)result, + (void **)&out->of.ref)) { + goto failed; + } + } + + result += 1; + break; + } +#endif default: LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, def->kind); @@ -2472,6 +2785,10 @@ wasm_func_call(const wasm_func_t *func, } #endif + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ if (!func_comm_rt) { goto failed; } @@ -2487,7 +2804,8 @@ wasm_func_call(const wasm_func_t *func, /* copy parametes */ if (param_count - && !(argc = params_to_argv(params, wasm_functype_params(func->type), + && !(argc = params_to_argv(func->inst_comm_rt, params, + wasm_functype_params(func->type), param_count, argv))) { goto failed; } @@ -2497,6 +2815,7 @@ wasm_func_call(const wasm_func_t *func, goto failed; } + wasm_runtime_set_exception(func->inst_comm_rt, NULL); if (!wasm_runtime_call_wasm(exec_env, func_comm_rt, argc, argv)) { if (wasm_runtime_get_exception(func->inst_comm_rt)) { LOG_DEBUG(wasm_runtime_get_exception(func->inst_comm_rt)); @@ -2562,6 +2881,7 @@ wasm_global_new(wasm_store_t *store, goto failed; } + global->store = store; global->kind = WASM_EXTERN_GLOBAL; global->type = wasm_globaltype_copy(global_type); if (!global->type) { @@ -2640,24 +2960,11 @@ wasm_global_delete(wasm_global_t *global) global->type = NULL; } + DELETE_HOST_INFO(global) + 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, @@ -2675,32 +2982,9 @@ interp_global_set(const WASMModuleInstance *inst_interp, #else uint8 *data = inst_interp->global_data + global_interp->data_offset; #endif - 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; + return wasm_val_to_rt_val((WASMModuleInstanceCommon *)inst_interp, + val_type_rt, v, data); } static bool @@ -2718,30 +3002,8 @@ interp_global_get(const WASMModuleInstance *inst_interp, #else uint8 *data = inst_interp->global_data + global_interp->data_offset; #endif - 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; + return rt_val_to_wasm_val(data, val_type_rt, out); } #endif @@ -2755,7 +3017,6 @@ aot_global_set(const AOTModuleInstance *inst_aot, 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; @@ -2771,28 +3032,8 @@ aot_global_set(const AOTModuleInstance *inst_aot, } data = (void *)((uint8 *)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; + return wasm_val_to_rt_val((WASMModuleInstanceCommon *)inst_aot, + val_type_rt, v, data); } static bool @@ -2803,8 +3044,7 @@ aot_global_get(const AOTModuleInstance *inst_aot, AOTModule *module_aot = inst_aot->aot_module.ptr; uint8 val_type_rt = 0; uint32 data_offset = 0; - void *data = NULL; - bool ret = true; + uint8 *data = NULL; if (global_idx_rt < module_aot->import_global_count) { data_offset = module_aot->import_globals[global_idx_rt].data_offset; @@ -2819,37 +3059,15 @@ aot_global_get(const AOTModuleInstance *inst_aot, .type; } - data = (void *)((uint8 *)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; + data = (uint8 *)inst_aot->global_data.ptr + data_offset; + return rt_val_to_wasm_val(data, val_type_rt, out); } #endif void wasm_global_set(wasm_global_t *global, const wasm_val_t *v) { - if (!global || !v - || !valid_module_type(global->inst_comm_rt->module_type)) { + if (!global || !v) { return; } @@ -2857,21 +3075,29 @@ wasm_global_set(wasm_global_t *global, const wasm_val_t *v) if (global->inst_comm_rt->module_type == Wasm_Module_Bytecode) { (void)interp_global_set((WASMModuleInstance *)global->inst_comm_rt, global->global_idx_rt, v); + return; } #endif + #if WASM_ENABLE_AOT != 0 if (global->inst_comm_rt->module_type == Wasm_Module_AoT) { (void)aot_global_set((AOTModuleInstance *)global->inst_comm_rt, global->global_idx_rt, v); + return; } #endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + UNREACHABLE(); } void wasm_global_get(const wasm_global_t *global, wasm_val_t *out) { - if (!global || !out - || !valid_module_type(global->inst_comm_rt->module_type)) { + if (!global || !out) { return; } @@ -2881,19 +3107,26 @@ wasm_global_get(const wasm_global_t *global, wasm_val_t *out) if (global->inst_comm_rt->module_type == Wasm_Module_Bytecode) { (void)interp_global_get((WASMModuleInstance *)global->inst_comm_rt, global->global_idx_rt, out); + return; } #endif + #if WASM_ENABLE_AOT != 0 if (global->inst_comm_rt->module_type == Wasm_Module_AoT) { (void)aot_global_get((AOTModuleInstance *)global->inst_comm_rt, global->global_idx_rt, out); + return; } #endif - bh_assert(global->init->kind == out->kind); + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + UNREACHABLE(); } -static wasm_global_t * +wasm_global_t * wasm_global_new_internal(wasm_store_t *store, uint16 global_idx_rt, WASMModuleInstanceCommon *inst_comm_rt) @@ -2901,10 +3134,11 @@ wasm_global_new_internal(wasm_store_t *store, wasm_global_t *global = NULL; uint8 val_type_rt = 0; bool is_mutable = 0; + bool init = false; bh_assert(singleton_engine); - if (!inst_comm_rt || !valid_module_type(inst_comm_rt->module_type)) { + if (!inst_comm_rt) { return NULL; } @@ -2913,10 +3147,7 @@ wasm_global_new_internal(wasm_store_t *store, goto failed; } - /* - * global->module_name = NULL; - * global->name = NULL; - */ + global->store = store; global->kind = WASM_EXTERN_GLOBAL; #if WASM_ENABLE_INTERP != 0 @@ -2925,6 +3156,7 @@ wasm_global_new_internal(wasm_store_t *store, ((WASMModuleInstance *)inst_comm_rt)->globals + global_idx_rt; val_type_rt = global_interp->type; is_mutable = global_interp->is_mutable; + init = true; } #endif @@ -2932,6 +3164,9 @@ wasm_global_new_internal(wasm_store_t *store, if (inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; AOTModule *module_aot = inst_aot->aot_module.ptr; + + init = true; + if (global_idx_rt < module_aot->import_global_count) { AOTImportGlobal *global_import_aot = module_aot->import_globals + global_idx_rt; @@ -2948,6 +3183,14 @@ wasm_global_new_internal(wasm_store_t *store, } #endif + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + if (!init) { + goto failed; + } + global->type = wasm_globaltype_new_internal(val_type_rt, is_mutable); if (!global->type) { goto failed; @@ -2993,7 +3236,7 @@ wasm_global_type(const wasm_global_t *global) } static wasm_table_t * -wasm_table_new_basic(const wasm_tabletype_t *type) +wasm_table_new_basic(wasm_store_t *store, const wasm_tabletype_t *type) { wasm_table_t *table = NULL; @@ -3001,6 +3244,7 @@ wasm_table_new_basic(const wasm_tabletype_t *type) goto failed; } + table->store = store; table->kind = WASM_EXTERN_TABLE; if (!(table->type = wasm_tabletype_copy(type))) { @@ -3010,7 +3254,7 @@ wasm_table_new_basic(const wasm_tabletype_t *type) RETURN_OBJ(table, wasm_table_delete); } -static wasm_table_t * +wasm_table_t * wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, WASMModuleInstanceCommon *inst_comm_rt) @@ -3018,10 +3262,11 @@ wasm_table_new_internal(wasm_store_t *store, wasm_table_t *table = NULL; uint8 val_type_rt = 0; uint32 init_size = 0, max_size = 0; + bool init_flag = false; bh_assert(singleton_engine); - if (!inst_comm_rt || !valid_module_type(inst_comm_rt->module_type)) { + if (!inst_comm_rt) { return NULL; } @@ -3029,6 +3274,7 @@ wasm_table_new_internal(wasm_store_t *store, goto failed; } + table->store = store; table->kind = WASM_EXTERN_TABLE; #if WASM_ENABLE_INTERP != 0 @@ -3038,6 +3284,7 @@ wasm_table_new_internal(wasm_store_t *store, val_type_rt = table_interp->elem_type; init_size = table_interp->cur_size; max_size = table_interp->max_size; + init_flag = true; } #endif @@ -3061,9 +3308,18 @@ wasm_table_new_internal(wasm_store_t *store, init_size = table_aot->table_init_size; max_size = table_aot->table_max_size; } + init_flag = true; } #endif + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + if (!init_flag) { + goto failed; + } + if (!(table->type = wasm_tabletype_new_internal(val_type_rt, init_size, max_size))) { goto failed; @@ -3075,20 +3331,36 @@ wasm_table_new_internal(wasm_store_t *store, RETURN_OBJ(table, wasm_table_delete); } +/* will not actually apply this new table into the runtime */ wasm_table_t * wasm_table_new(wasm_store_t *store, const wasm_tabletype_t *table_type, wasm_ref_t *init) { + wasm_table_t *table; (void)init; + bh_assert(singleton_engine); - return wasm_table_new_basic(table_type); + + if ((table = wasm_table_new_basic(store, table_type))) { + table->store = store; + } + + return table; } wasm_table_t * wasm_table_copy(const wasm_table_t *src) { - return wasm_table_new_basic(src->type); + wasm_table_t *table; + + if (!(table = wasm_table_new_basic(src->store, src->type))) { + return NULL; + } + + table->table_idx_rt = src->table_idx_rt; + table->inst_comm_rt = src->inst_comm_rt; + return table; } void @@ -3103,6 +3375,8 @@ wasm_table_delete(wasm_table_t *table) table->type = NULL; } + DELETE_HOST_INFO(table) + wasm_runtime_free(table); } @@ -3115,8 +3389,181 @@ wasm_table_type(const wasm_table_t *table) return wasm_tabletype_copy(table->type); } +own wasm_ref_t * +wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) +{ + uint32 func_idx_rt = NULL_REF; + + if (!table) { + return NULL; + } + + /* index -> func_idx_rt */ +#if WASM_ENABLE_INTERP != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMTableInstance *table_interp = + ((WASMModuleInstance *)table->inst_comm_rt) + ->tables[table->table_idx_rt]; + if (index >= table_interp->cur_size) { + return NULL; + } + func_idx_rt = ((uint32 *)table_interp->base_addr)[index]; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt; + AOTTableInstance *table_aot = + (AOTTableInstance*)inst_aot->tables.ptr + table->table_idx_rt; + if (index >= table_aot->cur_size) { + return NULL; + } + func_idx_rt = table_aot->data[index]; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ + if (func_idx_rt == NULL_REF) { + return NULL; + } + + return wasm_ref_new_internal(table->store, WASM_REF_func, func_idx_rt, + table->inst_comm_rt); +} + +bool +wasm_table_set(wasm_table_t *table, + wasm_table_size_t index, + own wasm_ref_t *func_ref) +{ + uint32 *p_func_idx_rt = NULL; + uint32 function_count = 0, ref_idx_rt = NULL_REF; + + if (!table) { + return false; + } + + if (func_ref && func_ref->kind != WASM_REF_func) { + return false; + } + + if (func_ref) { + ref_idx_rt = func_ref->ref_idx_rt; + wasm_ref_delete(func_ref); + } + + /* index -> *p_func_idx_rt */ +#if WASM_ENABLE_INTERP != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMTableInstance *table_interp = + ((WASMModuleInstance *)table->inst_comm_rt) + ->tables[table->table_idx_rt]; + + if (index >= table_interp->cur_size) { + return false; + } + + p_func_idx_rt = ((uint32 *)table_interp->base_addr) + index; + function_count = + ((WASMModuleInstance *)table->inst_comm_rt)->function_count; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; + AOTTableInstance *table_aot = + (AOTTableInstance *)inst_aot->tables.ptr + table->table_idx_rt; + + if (index >= table_aot->cur_size) { + return false; + } + + p_func_idx_rt = table_aot->data + index; + function_count = module_aot->func_count; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + if (!p_func_idx_rt) { + return false; + } + + if (NULL_REF != ref_idx_rt) { + if (ref_idx_rt >= function_count) { + return false; + } + } + + *p_func_idx_rt = ref_idx_rt; + return true; +} + +wasm_table_size_t +wasm_table_size(const wasm_table_t *table) +{ + if (!table) { + return 0; + } + +#if WASM_ENABLE_INTERP != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMTableInstance *table_interp = + ((WASMModuleInstance *)table->inst_comm_rt) + ->tables[table->table_idx_rt]; + return table_interp->cur_size; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (table->inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; + + if (table->table_idx_rt < module_aot->import_table_count) { + AOTImportTable *table_aot = + module_aot->import_tables + table->table_idx_rt; + return table_aot->table_init_size; + } + else { + AOTTable *table_aot = + module_aot->tables + + (table->table_idx_rt - module_aot->import_table_count); + return table_aot->table_init_size; + } + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + return 0; +} + +bool +wasm_table_grow(wasm_table_t *table, + wasm_table_size_t delta, + own wasm_ref_t *init) +{ + (void)table; + (void)delta; + (void)init; + LOG_WARNING("Calling wasm_table_grow() by host is not supported." + "Only allow growing a table via the opcode table.grow"); + return false; +} + static wasm_memory_t * -wasm_memory_new_basic(const wasm_memorytype_t *type) +wasm_memory_new_basic(wasm_store_t *store, const wasm_memorytype_t *type) { wasm_memory_t *memory = NULL; @@ -3124,6 +3571,7 @@ wasm_memory_new_basic(const wasm_memorytype_t *type) goto failed; } + memory->store = store; memory->kind = WASM_EXTERN_MEMORY; memory->type = wasm_memorytype_copy(type); @@ -3134,7 +3582,7 @@ wasm_memory_t * wasm_memory_new(wasm_store_t *store, const wasm_memorytype_t *type) { bh_assert(singleton_engine); - return wasm_memory_new_basic(type); + return wasm_memory_new_basic(store, type); } wasm_memory_t * @@ -3146,7 +3594,7 @@ wasm_memory_copy(const wasm_memory_t *src) return NULL; } - if (!(dst = wasm_memory_new_basic(src->type))) { + if (!(dst = wasm_memory_new_basic(src->store, src->type))) { goto failed; } @@ -3156,17 +3604,18 @@ wasm_memory_copy(const wasm_memory_t *src) RETURN_OBJ(dst, wasm_memory_delete) } -static wasm_memory_t * +wasm_memory_t * wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt, WASMModuleInstanceCommon *inst_comm_rt) { wasm_memory_t *memory = NULL; uint32 min_pages = 0, max_pages = 0; + bool init_flag = false; bh_assert(singleton_engine); - if (!inst_comm_rt || !valid_module_type(inst_comm_rt->module_type)) { + if (!inst_comm_rt) { return NULL; } @@ -3174,6 +3623,7 @@ wasm_memory_new_internal(wasm_store_t *store, goto failed; } + memory->store = store; memory->kind = WASM_EXTERN_MEMORY; #if WASM_ENABLE_INTERP != 0 @@ -3182,6 +3632,7 @@ wasm_memory_new_internal(wasm_store_t *store, ((WASMModuleInstance *)inst_comm_rt)->memories[memory_idx_rt]; min_pages = memory_interp->cur_page_count; max_pages = memory_interp->max_page_count; + init_flag = true; } #endif @@ -3198,9 +3649,18 @@ wasm_memory_new_internal(wasm_store_t *store, min_pages = module_aot->memories->mem_init_page_count; max_pages = module_aot->memories->mem_max_page_count; } + init_flag = true; } #endif + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + if (!init_flag) { + goto failed; + } + if (!(memory->type = wasm_memorytype_new_internal(min_pages, max_pages))) { goto failed; } @@ -3223,6 +3683,8 @@ wasm_memory_delete(wasm_memory_t *memory) memory->type = NULL; } + DELETE_HOST_INFO(memory) + wasm_runtime_free(memory); } @@ -3239,15 +3701,107 @@ wasm_memory_type(const wasm_memory_t *memory) byte_t * wasm_memory_data(wasm_memory_t *memory) { - return (byte_t *)wasm_runtime_get_memory_data(memory->inst_comm_rt, - memory->memory_idx_rt); + WASMModuleInstanceCommon *module_inst_comm = memory->inst_comm_rt; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst = + module_inst->memories[memory->memory_idx_rt]; + return (byte_t *)memory_inst->memory_data; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + AOTMemoryInstance *memory_inst = + ((AOTMemoryInstance **) + module_inst->memories.ptr)[memory->memory_idx_rt]; + return (byte_t *)memory_inst->memory_data.ptr; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + return NULL; } size_t wasm_memory_data_size(const wasm_memory_t *memory) { - return wasm_runtime_get_memory_data_size(memory->inst_comm_rt, - memory->memory_idx_rt); + WASMModuleInstanceCommon *module_inst_comm = memory->inst_comm_rt; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst = + module_inst->memories[memory->memory_idx_rt]; + return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + AOTMemoryInstance *memory_inst = + ((AOTMemoryInstance **) + module_inst->memories.ptr)[memory->memory_idx_rt]; + return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + return 0; +} + +wasm_memory_pages_t +wasm_memory_size(const wasm_memory_t *memory) +{ + WASMModuleInstanceCommon *module_inst_comm = memory->inst_comm_rt; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst = + module_inst->memories[memory->memory_idx_rt]; + return memory_inst->cur_page_count; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + AOTMemoryInstance *memory_inst = + ((AOTMemoryInstance **) + module_inst->memories.ptr)[memory->memory_idx_rt]; + return memory_inst->cur_page_count; + } +#endif + + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + return 0; +} + +bool +wasm_memory_grow(wasm_memory_t *memory, wasm_memory_pages_t delta) +{ + (void)memory; + (void)delta; + LOG_WARNING("Calling wasm_memory_grow() by host is not supported." + "Only allow growing a memory via the opcode memory.grow"); + return false; } #if WASM_ENABLE_INTERP != 0 @@ -3525,7 +4079,6 @@ aot_link_global(const AOTModule *module_aot, import_aot_global = module_aot->import_globals + global_idx_rt; bh_assert(import_aot_global); - //TODO: import->type ? val_type = wasm_globaltype_content(import->type); bh_assert(val_type); @@ -3710,18 +4263,29 @@ wasm_instance_new(wasm_store_t *store, const wasm_module_t *module, const wasm_extern_t *const imports[], own wasm_trap_t **traps) +{ + return wasm_instance_new_with_args(store, module, imports, traps, + KILOBYTE(32), KILOBYTE(32)); +} + +wasm_instance_t * +wasm_instance_new_with_args(wasm_store_t *store, + const wasm_module_t *module, + const wasm_extern_t *const imports[], + own wasm_trap_t **traps, + const uint32 stack_size, + const uint32 heap_size) { char error_buf[128] = { 0 }; - const uint32 stack_size = 32 * 1024; - const uint32 heap_size = 32 * 1024; uint32 import_count = 0; wasm_instance_t *instance = NULL; uint32 i = 0; + bool processed = false; (void)traps; bh_assert(singleton_engine); - if (!module || !valid_module_type((*module)->module_type)) { + if (!module) { return NULL; } @@ -3770,6 +4334,14 @@ wasm_instance_new(wasm_store_t *store, } } #endif + + /* + * a wrong combination of module filetype and compilation flags + * also leads to below branch + */ + if (!import_count) { + goto failed; + } } instance->inst_comm_rt = wasm_runtime_instantiate( @@ -3822,6 +4394,8 @@ wasm_instance_new(wasm_store_t *store, instance->exports)) { goto failed; } + + processed = true; } #endif @@ -3841,9 +4415,19 @@ wasm_instance_new(wasm_store_t *store, instance->exports)) { goto failed; } + + processed = true; } #endif + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ + if (!processed) { + goto failed; + } + /* add it to a watching list in store */ if (!bh_vector_append((Vector *)store->instances, &instance)) { goto failed; @@ -3875,8 +4459,9 @@ wasm_instance_delete_internal(wasm_instance_t *instance) } void -wasm_instance_delete(wasm_instance_t *module) +wasm_instance_delete(wasm_instance_t *inst) { + DELETE_HOST_INFO(inst) /* will release instance when releasing the store */ } diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h index dc9fc452..0b6da5a6 100644 --- a/core/iwasm/common/wasm_c_api_internal.h +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -6,7 +6,7 @@ #ifndef _WASM_C_API_INTERNAL_H #define _WASM_C_API_INTERNAL_H -#include "wasm_c_api.h" +#include "../include/wasm_c_api.h" #include "wasm_runtime_common.h" #ifndef own @@ -19,9 +19,9 @@ /* 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, *) +WASM_DECLARE_VEC(module, *) +WASM_DECLARE_VEC(store, *) /* Runtime Environment */ struct wasm_engine_t { @@ -32,6 +32,7 @@ struct wasm_engine_t { struct wasm_store_t { wasm_module_vec_t *modules; wasm_instance_vec_t *instances; + Vector *foreigns; }; /* Type Representations */ @@ -82,8 +83,25 @@ struct wasm_exporttype_t { }; /* Runtime Objects */ +enum wasm_reference_kind { + WASM_REF_foreign, + WASM_REF_func, + WASM_REF_global, + WASM_REF_memory, + WASM_REF_table, +}; + +struct wasm_host_info { + void *info; + void (*finalizer)(void *); +}; + struct wasm_ref_t { - uint32 obj; + wasm_store_t *store; + enum wasm_reference_kind kind; + struct wasm_host_info host_info; + uint32 ref_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; }; struct wasm_trap_t { @@ -91,11 +109,22 @@ struct wasm_trap_t { Vector *frames; }; +struct wasm_foreign_t { + wasm_store_t *store; + enum wasm_reference_kind kind; + struct wasm_host_info host_info; + int32 ref_cnt; + uint32 foreign_idx_rt; + WASMModuleInstanceCommon *inst_comm_rt; +}; + struct wasm_func_t { + wasm_store_t *store; wasm_name_t *module_name; wasm_name_t *name; uint16 kind; + struct wasm_host_info host_info; wasm_functype_t *type; bool with_env; @@ -117,10 +146,12 @@ struct wasm_func_t { }; struct wasm_global_t { + wasm_store_t *store; wasm_name_t *module_name; wasm_name_t *name; uint16 kind; + struct wasm_host_info host_info; wasm_globaltype_t *type; wasm_val_t *init; /* @@ -132,10 +163,12 @@ struct wasm_global_t { }; struct wasm_memory_t { + wasm_store_t *store; wasm_name_t *module_name; wasm_name_t *name; uint16 kind; + struct wasm_host_info host_info; wasm_memorytype_t *type; /* * an index in both memory runtime instance lists @@ -146,10 +179,12 @@ struct wasm_memory_t { }; struct wasm_table_t { + wasm_store_t *store; wasm_name_t *module_name; wasm_name_t *name; uint16 kind; + struct wasm_host_info host_info; wasm_tabletype_t *type; /* * an index in both table runtime instance lists @@ -160,16 +195,49 @@ struct wasm_table_t { }; struct wasm_extern_t { + wasm_store_t *store; wasm_name_t *module_name; wasm_name_t *name; wasm_externkind_t kind; - uint8 data[1]; + uint8 data[4]; }; struct wasm_instance_t { + wasm_store_t *store; wasm_extern_vec_t *imports; wasm_extern_vec_t *exports; + struct wasm_host_info host_info; WASMModuleInstanceCommon *inst_comm_rt; }; +wasm_ref_t * +wasm_ref_new_internal(wasm_store_t *store, + enum wasm_reference_kind kind, + uint32 obj_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_foreign_t * +wasm_foreign_new_internal(wasm_store_t *store, + uint32 foreign_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_func_t * +wasm_func_new_internal(wasm_store_t *store, + uint16 func_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_global_t * +wasm_global_new_internal(wasm_store_t *store, + uint16 global_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_memory_t * +wasm_memory_new_internal(wasm_store_t *store, + uint16 memory_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); + +wasm_table_t * +wasm_table_new_internal(wasm_store_t *store, + uint16 table_idx_rt, + WASMModuleInstanceCommon *inst_comm_rt); #endif /* _WASM_C_API_INTERNAL_H */ diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index fb1a3bb5..ee5cd3dd 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -3977,57 +3977,6 @@ wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm, return false; } -uint8 * -wasm_runtime_get_memory_data(const WASMModuleInstanceCommon *module_inst_comm, - uint32 memory_inst_idx) -{ -#if WASM_ENABLE_INTERP != 0 - if (module_inst_comm->module_type == Wasm_Module_Bytecode) { - WASMModuleInstance *module_inst = - (WASMModuleInstance *)module_inst_comm; - WASMMemoryInstance *memory_inst = - module_inst->memories[memory_inst_idx]; - return memory_inst->memory_data; - } -#endif - -#if WASM_ENABLE_AOT != 0 - if (module_inst_comm->module_type == Wasm_Module_AoT) { - AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; - AOTMemoryInstance *memory_inst = - ((AOTMemoryInstance**)module_inst->memories.ptr)[memory_inst_idx]; - return memory_inst->memory_data.ptr; - } -#endif - return NULL; -} - -uint32 -wasm_runtime_get_memory_data_size( - const WASMModuleInstanceCommon *module_inst_comm, - uint32 memory_inst_idx) -{ -#if WASM_ENABLE_INTERP != 0 - if (module_inst_comm->module_type == Wasm_Module_Bytecode) { - WASMModuleInstance *module_inst = - (WASMModuleInstance *)module_inst_comm; - WASMMemoryInstance *memory_inst = - module_inst->memories[memory_inst_idx]; - return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; - } -#endif - -#if WASM_ENABLE_AOT != 0 - if (module_inst_comm->module_type == Wasm_Module_AoT) { - AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; - AOTMemoryInstance *memory_inst = - ((AOTMemoryInstance**)module_inst->memories.ptr)[memory_inst_idx]; - return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; - } -#endif - return 0; -} - static inline bool argv_to_params(wasm_val_t *out_params, const uint32 *argv, @@ -4058,6 +4007,23 @@ argv_to_params(wasm_val_t *out_params, u32[0] = *argv++; u32[1] = *argv++; break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + param->kind = WASM_ANYREF; + + if (NULL_REF == *argv) { + param->of.ref = NULL; + } + else { + if (!wasm_externref_ref2obj(*argv, + (void **)¶m->of.ref)) { + return false; + } + } + + argv++; + break; +#endif default: return false; } @@ -4067,7 +4033,8 @@ argv_to_params(wasm_val_t *out_params, } static inline bool -results_to_argv(uint32 *out_argv, +results_to_argv(WASMModuleInstanceCommon *module_inst, + uint32 *out_argv, const wasm_val_t *results, WASMType *func_type) { @@ -4087,6 +4054,15 @@ results_to_argv(uint32 *out_argv, *argv++ = u32[0]; *argv++ = u32[1]; break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + if (!wasm_externref_obj2ref(module_inst, result->of.ref, + argv)) { + return false; + } + argv++; + break; +#endif default: return false; } @@ -4134,7 +4110,7 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, char trap_message[128] = { 0 }; bh_memcpy_s( trap_message, 127, trap->message->data, - (trap->message->size < 127 ? trap->message->size : 127)); + (trap->message->size < 127 ? (uint32)trap->message->size : 127)); wasm_runtime_set_exception(module_inst, trap_message); } else { @@ -4152,7 +4128,7 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, goto fail; } - if (!results_to_argv(argv, results, func_type)) { + if (!results_to_argv(module_inst, argv, results, func_type)) { wasm_runtime_set_exception(module_inst, "unsupported result type"); goto fail; } diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 4b515bf8..36dae951 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -796,14 +796,6 @@ wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm, uint32 *out_min_size, uint32 *out_max_size); -uint8 * -wasm_runtime_get_memory_data(const WASMModuleInstanceCommon *module_inst_comm, - uint32 memory_inst_idx); - -uint32 -wasm_runtime_get_memory_data_size(const WASMModuleInstanceCommon *module_inst_comm, - uint32 memory_inst_idx); - bool wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, void *func_ptr, WASMType *func_type, diff --git a/core/iwasm/compilation/aot_emit_table.c b/core/iwasm/compilation/aot_emit_table.c index e84cad5d..5ce7d5a7 100644 --- a/core/iwasm/compilation/aot_emit_table.c +++ b/core/iwasm/compilation/aot_emit_table.c @@ -25,6 +25,7 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx, while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) { offset += offsetof(AOTTableInstance, data); + /* avoid loading from current AOTTableInstance */ offset += sizeof(uint32) * aot_get_imp_tbl_data_slots(imp_tbls + i); ++i; } @@ -37,6 +38,7 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx, i -= comp_ctx->comp_data->import_table_count; while (i < tbl_idx && i < comp_ctx->comp_data->table_count) { offset += offsetof(AOTTableInstance, data); + /* avoid loading from current AOTTableInstance */ offset += sizeof(uint32) * aot_get_tbl_data_slots(tbls + i); ++i; } diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h index 6079773e..0133606a 100644 --- a/core/iwasm/include/wasm_c_api.h +++ b/core/iwasm/include/wasm_c_api.h @@ -573,6 +573,12 @@ WASM_API_EXTERN own wasm_instance_t* wasm_instance_new( own wasm_trap_t** ); +// please refer to wasm_runtime_instantiate(...) in core/iwasm/include/wasm_export.h +WASM_API_EXTERN own wasm_instance_t* wasm_instance_new_with_args( + wasm_store_t*, const wasm_module_t*, const wasm_extern_t *const imports[], + own wasm_trap_t**, const uint32_t stack_size, const uint32_t heap_size +); + WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out); @@ -764,6 +770,7 @@ static inline void* wasm_val_ptr(const wasm_val_t* val) { #define WASM_REF_VAL(r) {.kind = WASM_ANYREF, .of = {.ref = r}} #define WASM_INIT_VAL {.kind = WASM_ANYREF, .of = {.ref = NULL}} +#define KILOBYTE(n) ((n) * 1024) /////////////////////////////////////////////////////////////////////////////// diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 854911ff..0f365657 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -7881,7 +7881,7 @@ fail_data_cnt_sec_require: #if WASM_ENABLE_REF_TYPES != 0 case WASM_OP_TABLE_INIT: { - uint8 seg_ref_type, tbl_ref_type; + uint8 seg_ref_type = 0, tbl_ref_type = 0; if (!wasm_get_ref_types_flag()) { goto unsupported_opcode; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 17951691..1a2eb2eb 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -476,9 +476,11 @@ tables_instantiate(const WASMModule *module, /* instantiate tables from import section */ import = module->import_tables; for (i = 0; i < module->import_table_count; i++, import++) { + uint32 max_size_fixed = 0; #if WASM_ENABLE_MULTI_MODULE != 0 WASMTableInstance *table_inst_linked = NULL; WASMModuleInstance *module_inst_linked = NULL; + if (import->u.table.import_module) { if (!(module_inst_linked = get_sub_module_inst(module_inst, import->u.table.import_module))) { @@ -499,12 +501,14 @@ tables_instantiate(const WASMModule *module, else #endif { + /* in order to save memory, alloc resource as few as possible */ + max_size_fixed = import->u.table.possible_grow + ? import->u.table.max_size + : import->u.table.init_size; + /* it is a built-in table, every module has its own */ total_size = offsetof(WASMTableInstance, base_addr); - total_size += - import->u.table.possible_grow - ? sizeof(uint32) * (uint64)import->u.table.max_size - : sizeof(uint32) * (uint64)import->u.table.init_size; + total_size += (uint64)max_size_fixed * sizeof(uint32); } if (!(table = tables[table_index++] = runtime_malloc @@ -515,6 +519,7 @@ tables_instantiate(const WASMModule *module, /* Set all elements to -1 to mark them as uninitialized elements */ memset(table, -1, (uint32)total_size); + #if WASM_ENABLE_MULTI_MODULE != 0 table->table_inst_linked = table_inst_linked; if (table_inst_linked != NULL) { @@ -527,21 +532,26 @@ tables_instantiate(const WASMModule *module, { table->elem_type = import->u.table.elem_type; table->cur_size = import->u.table.init_size; - table->max_size = import->u.table.max_size; + table->max_size = max_size_fixed; } } /* instantiate tables from table section */ for (i = 0; i < module->table_count; i++) { + uint32 max_size_fixed = 0; + total_size = offsetof(WASMTableInstance, base_addr); #if WASM_ENABLE_MULTI_MODULE != 0 /* in case, a module which imports this table will grow it */ - total_size += sizeof(uint32) * (uint64)module->tables[i].max_size; + max_size_fixed = module->tables[i].max_size; #else - total_size += module->tables[i].possible_grow - ? sizeof(uint32) * (uint64)module->tables[i].max_size - : sizeof(uint32) * (uint64)module->tables[i].init_size; + max_size_fixed = + module->tables[i].possible_grow + ? module->tables[i].max_size + : module->tables[i].init_size; #endif + total_size += sizeof(uint32) * (uint64)max_size_fixed; + if (!(table = tables[table_index++] = runtime_malloc (total_size, error_buf, error_buf_size))) { tables_deinstantiate(tables, table_count); @@ -552,7 +562,7 @@ tables_instantiate(const WASMModule *module, memset(table, -1, (uint32)total_size); table->elem_type = module->tables[i].elem_type; table->cur_size = module->tables[i].init_size; - table->max_size = module->tables[i].max_size; + table->max_size = max_size_fixed; #if WASM_ENABLE_MULTI_MODULE != 0 table->table_inst_linked = NULL; #endif @@ -2150,10 +2160,12 @@ wasm_enlarge_table(WASMModuleInstance *module_inst, return false; } + if (inc_entries > UINT32_MAX - table_inst->cur_size) { + return false; + } + entry_count = table_inst->cur_size + inc_entries; - /* prevent from integer overflow */ - if (entry_count < table_inst->cur_size - || entry_count > table_inst->max_size) { + if (entry_count > table_inst->max_size) { return false; } diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index fb568812..745f6faf 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -456,4 +456,3 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env); #endif #endif /* end of _WASM_RUNTIME_H */ - diff --git a/doc/wasm_c_api.md b/doc/wasm_c_api.md index a23096e5..bd678a95 100644 --- a/doc/wasm_c_api.md +++ b/doc/wasm_c_api.md @@ -12,59 +12,26 @@ them in next releases. a summary of unsupported APIs -- Configuration - -``` c -WASM_API_EXTERN own wasm_config_t* wasm_config_new(void); -``` - - References ``` c -WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); \ -WASM_API_EXTERN void* wasm_##name##_get_host_info(const wasm_##name##_t*); \ -WASM_API_EXTERN void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \ -WASM_API_EXTERN void wasm_##name##_set_host_info_with_finalizer( \ -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*); -WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \ +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*); ``` -- Frames - -``` c -WASM_API_EXTERN own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*); -WASM_API_EXTERN struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*); -WASM_API_EXTERN uint32_t wasm_frame_func_index(const wasm_frame_t*); -WASM_API_EXTERN size_t wasm_frame_func_offset(const wasm_frame_t*); -WASM_API_EXTERN size_t wasm_frame_module_offset(const wasm_frame_t*); -WASM_API_EXTERN own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*); -WASM_API_EXTERN void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out); -``` - - Foreign Objects - -``` c -WASM_API_EXTERN own wasm_foreign_t* wasm_foreign_new(wasm_store_t*); -``` - - Several Module APIs ``` c -WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); -WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_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*); ``` -- Table Operations APIs +we tend to grow a table or a memory by opcode only and not support growing both +by host-side function callings. + +- Table Grow APIs ``` c -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); ``` @@ -72,4 +39,4 @@ WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, was ``` c WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta); -``` \ No newline at end of file +``` diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 2cf8d923..650dda2d 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -42,6 +42,7 @@ set(WAMR_BUILD_LIBC_BUILTIN 1) set(WAMR_BUILD_LIBC_WASI 0) set(WAMR_BUILD_MULTI_MODULE 1) set(WAMR_BUILD_DUMP_CALL_STACK 1) +set(WAMR_BUILD_REF_TYPES 1) if(NOT DEFINED WAMR_BUILD_FAST_INTERP) set(WAMR_BUILD_FAST_INTERP 1) @@ -101,12 +102,15 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) set(MM_UTIL src/utils/multi_module_utils.c) # build executable for each .c set(EXAMPLES - hello callback - global - reflect - trap callback_chain + global + hello + hostref + memory + reflect + table + trap ) foreach(EX ${EXAMPLES}) @@ -123,7 +127,7 @@ foreach(EX ${EXAMPLES}) set(WAT ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.wat) add_custom_target(${EX}_WASM - COMMAND ${WAT2WASM} ${WAT} -o ${PROJECT_BINARY_DIR}/${EX}.wasm + COMMAND ${WAT2WASM} ${WAT} --enable-reference-types -o ${PROJECT_BINARY_DIR}/${EX}.wasm DEPENDS ${WAT} BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.wasm VERBATIM @@ -133,7 +137,7 @@ foreach(EX ${EXAMPLES}) # generate .aot file if(${WAMR_BUILD_AOT} EQUAL 1) add_custom_target(${EX}_AOT - COMMAND ${WAMRC} -o ${PROJECT_BINARY_DIR}/${EX}.aot + COMMAND ${WAMRC} --enable-ref-types -o ${PROJECT_BINARY_DIR}/${EX}.aot ${PROJECT_BINARY_DIR}/${EX}.wasm DEPENDS ${EX}_WASM BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.aot diff --git a/samples/wasm-c-api/src/hostref.c b/samples/wasm-c-api/src/hostref.c new file mode 100644 index 00000000..f86c4754 --- /dev/null +++ b/samples/wasm-c-api/src/hostref.c @@ -0,0 +1,263 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + + +// A function to be called from Wasm code. +own wasm_trap_t* callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n> "); + printf("> %p\n", + args[0].of.ref ? wasm_ref_get_host_info(args[0].of.ref) : NULL); + wasm_val_copy(&results[0], &args[0]); + return NULL; +} + + +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]); +} + +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_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) { + printf("> Error accessing table export %zu!\n", i); + exit(1); + } + return wasm_extern_as_table(exports->data[i]); +} + + +own wasm_ref_t* call_v_r(const wasm_func_t* func) { + printf("call_v_r... "); fflush(stdout); + wasm_val_t rs[] = { WASM_INIT_VAL }; + if (wasm_func_call(func, NULL, rs)) { + printf("> Error calling function!\n"); + exit(1); + } + printf("okay\n"); + return rs[0].of.ref; +} + +void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) { + printf("call_r_v... "); fflush(stdout); + wasm_val_t vs[1] = { WASM_REF_VAL(ref) }; + if (wasm_func_call(func, vs, NULL)) { + printf("> Error calling function!\n"); + exit(1); + } + printf("okay\n"); +} + +own wasm_ref_t* call_r_r(const wasm_func_t* func, wasm_ref_t* ref) { + printf("call_r_r... "); fflush(stdout); + wasm_val_t vs[1] = { WASM_REF_VAL(ref) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + if (wasm_func_call(func, vs, rs)) { + printf("> Error calling function!\n"); + exit(1); + } + printf("okay\n"); + return rs[0].of.ref; +} + +void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) { + printf("call_ir_v... "); fflush(stdout); + wasm_val_t vs[2] = { WASM_I32_VAL(i), WASM_REF_VAL(ref) }; + if (wasm_func_call(func, vs, NULL)) { + printf("> Error calling function!\n"); + exit(1); + } + printf("okay\n"); +} + +own wasm_ref_t* call_i_r(const wasm_func_t* func, int32_t i) { + printf("call_i_r... "); fflush(stdout); + wasm_val_t vs[1] = { WASM_I32_VAL(i) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + if (wasm_func_call(func, vs, rs)) { + printf("> Error calling function!\n"); + exit(1); + } + printf("okay\n"); + return rs[0].of.ref; +} + +void +check(own wasm_ref_t *actual, const wasm_ref_t *expected, bool release_ref) +{ + if (actual != expected + && !(actual && expected && wasm_ref_same(actual, expected))) { + printf("> Error reading reference, expected %p, got %p\n", + expected ? wasm_ref_get_host_info(expected) : NULL, + actual ? wasm_ref_get_host_info(actual) : NULL); + exit(1); + } + if (release_ref && actual) + wasm_ref_delete(actual); +} + +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("hostref.aot", "rb"); +#else + FILE* file = fopen("hostref.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"); + fclose(file); + 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 callback function. + printf("Creating callback...\n"); + own wasm_functype_t* callback_type = wasm_functype_new_1_1( + wasm_valtype_new(WASM_ANYREF), wasm_valtype_new(WASM_ANYREF)); + own wasm_func_t* callback_func = + wasm_func_new(store, callback_type, callback); + + wasm_functype_delete(callback_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { wasm_func_as_extern(callback_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(callback_func); + 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* global = get_export_global(&exports, i++); + wasm_table_t* table = get_export_table(&exports, i++); + wasm_func_t* global_set = get_export_func(&exports, i++); + wasm_func_t* global_get = get_export_func(&exports, i++); + wasm_func_t* table_set = get_export_func(&exports, i++); + wasm_func_t* table_get = get_export_func(&exports, i++); + wasm_func_t* func_call = get_export_func(&exports, i++); + + wasm_instance_delete(instance); + + // Create host references. + printf("Creating host references...\n"); + own wasm_ref_t* host1 = wasm_foreign_as_ref(wasm_foreign_new(store)); + own wasm_ref_t* host2 = wasm_foreign_as_ref(wasm_foreign_new(store)); + wasm_ref_set_host_info(host1, (void*)1); + wasm_ref_set_host_info(host2, (void*)2); + + // Some sanity checks. + check(NULL, NULL, true); + check(wasm_ref_copy(host1), host1, true); + check(wasm_ref_copy(host2), host2, true); + + own wasm_val_t val; + val.kind = WASM_ANYREF; + val.of.ref = wasm_ref_copy(host1); + check(wasm_ref_copy(val.of.ref), host1, true); + own wasm_ref_t* ref = val.of.ref; + check(wasm_ref_copy(ref), host1, true); + wasm_ref_delete(val.of.ref); + + // Interact. + printf("Accessing global...\n"); + check(call_v_r(global_get), NULL, false); + call_r_v(global_set, host1); + check(call_v_r(global_get), host1, false); + call_r_v(global_set, host2); + check(call_v_r(global_get), host2, false); + call_r_v(global_set, NULL); + check(call_v_r(global_get), NULL, false); + + wasm_global_get(global, &val); + assert(val.kind == WASM_ANYREF); + check(val.of.ref, NULL, false); + val.of.ref = host2; + wasm_global_set(global, &val); + check(call_v_r(global_get), host2, false); + wasm_global_get(global, &val); + assert(val.kind == WASM_ANYREF); + check(val.of.ref, host2, false); + + printf("Accessing table...\n"); + check(call_i_r(table_get, 0), NULL, false); + check(call_i_r(table_get, 1), NULL, false); + call_ir_v(table_set, 0, host1); + call_ir_v(table_set, 1, host2); + check(call_i_r(table_get, 0), host1, false); + check(call_i_r(table_get, 1), host2, false); + call_ir_v(table_set, 0, NULL); + check(call_i_r(table_get, 0), NULL, false); + + check(wasm_table_get(table, 2), NULL, false); + + printf("Accessing function...\n"); + check(call_r_r(func_call, NULL), NULL, false); + check(call_r_r(func_call, host1), host1, false); + check(call_r_r(func_call, host2), host2, false); + + wasm_ref_delete(host1); + wasm_ref_delete(host2); + + 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/hostref.wat b/samples/wasm-c-api/src/hostref.wat new file mode 100644 index 00000000..9ed43dbc --- /dev/null +++ b/samples/wasm-c-api/src/hostref.wat @@ -0,0 +1,24 @@ +(module + (import "" "f" (func $fun (param externref) (result externref))) + + (global $glob (export "global") (mut externref) (ref.null extern)) + (table $tab (export "table") 10 externref) + + (func (export "global.set") (param $r externref) + (global.set $glob (local.get $r)) + ) + (func (export "global.get") (result externref) + (global.get $glob) + ) + + (func (export "table.set") (param $i i32) (param $r externref) + (table.set $tab (local.get $i) (local.get $r)) + ) + (func (export "table.get") (param $i i32) (result externref) + (table.get $tab (local.get $i)) + ) + + (func (export "func.call") (param $r externref) (result externref) + (call $fun (local.get $r)) + ) +) diff --git a/samples/wasm-c-api/src/memory.c b/samples/wasm-c-api/src/memory.c new file mode 100644 index 00000000..2e1c9015 --- /dev/null +++ b/samples/wasm-c-api/src/memory.c @@ -0,0 +1,209 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + + +wasm_memory_t* get_export_memory(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_memory(exports->data[i])) { + printf("> Error accessing memory export %zu!\n", i); + exit(1); + } + return wasm_extern_as_memory(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]); +} + + +void check(bool success) { + if (!success) { + printf("> Error, expected success\n"); + exit(1); + } +} + +void check_call(wasm_func_t* func, int i, wasm_val_t args[], int32_t expected) { + wasm_val_t results[1] = { WASM_INIT_VAL }; + if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) { + printf("> Error on result\n"); + exit(1); + } +} + +void check_call0(wasm_func_t* func, int32_t expected) { + check_call(func, 0, NULL, expected); +} + +void check_call1(wasm_func_t* func, int32_t arg, int32_t expected) { + wasm_val_t args[] = { WASM_I32_VAL(arg) }; + check_call(func, 1, args, expected); +} + +void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) { + wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + check_call(func, 2, args, expected); +} + +void check_ok(wasm_func_t* func, int i, wasm_val_t args[]) { + if (wasm_func_call(func, args, NULL)) { + printf("> Error on result, expected empty\n"); + exit(1); + } +} + +void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { + wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + check_ok(func, 2, args); +} + +void check_trap(wasm_func_t* func, int i, wasm_val_t args[]) { + wasm_val_t results[1] = { WASM_INIT_VAL }; + own wasm_trap_t* trap = wasm_func_call(func, args, results); + if (! trap) { + printf("> Error on result, expected trap\n"); + exit(1); + } + wasm_trap_delete(trap); +} + +void check_trap1(wasm_func_t* func, int32_t arg) { + wasm_val_t args[] = { WASM_I32_VAL(arg) }; + check_trap(func, 1, args); +} + +void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) { + wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + check_trap(func, 2, args); +} + + +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("memory.aot", "rb"); +#else + FILE* file = fopen("memory.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"); + fclose(file); + 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); + + // Instantiate. + printf("Instantiating module...\n"); + own wasm_instance_t* instance = + wasm_instance_new_with_args(store, module, NULL, NULL, KILOBYTE(8), 0); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + // Extract export. + printf("Extracting exports...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + size_t i = 0; + wasm_memory_t* memory = get_export_memory(&exports, i++); + wasm_func_t* size_func = get_export_func(&exports, i++); + wasm_func_t* load_func = get_export_func(&exports, i++); + wasm_func_t* store_func = get_export_func(&exports, i++); + + wasm_module_delete(module); + + if (!memory || !wasm_memory_data(memory)) { + printf("> Error getting memory!\n"); + wasm_extern_vec_delete(&exports); + wasm_instance_delete(instance); + wasm_store_delete(store); + wasm_engine_delete(engine); + return 1; + } + + // Try cloning. + own wasm_memory_t* copy = wasm_memory_copy(memory); + assert(wasm_memory_same(memory, copy)); + wasm_memory_delete(copy); + + // Check initial memory. + printf("Checking memory...\n"); + check(wasm_memory_size(memory) >= 2); + check(wasm_memory_data_size(memory) >= 0x20000); + check(wasm_memory_data(memory)[0] == 0); + check(wasm_memory_data(memory)[0x1000] == 1); + check(wasm_memory_data(memory)[0x1003] == 4); + + (void)size_func; + check_call1(load_func, 0, 0); + check_call1(load_func, 0x1000, 1); + check_call1(load_func, 0x1003, 4); + check_call1(load_func, 0x1ffff, 0); + check_trap1(load_func, 0x20000); + + // Mutate memory. + printf("Mutating memory...\n"); + wasm_memory_data(memory)[0x1003] = 5; + check_ok2(store_func, 0x1002, 6); + check_trap2(store_func, 0x20000, 0); + + check(wasm_memory_data(memory)[0x1002] == 6); + check(wasm_memory_data(memory)[0x1003] == 5); + check_call1(load_func, 0x1002, 6); + check_call1(load_func, 0x1003, 5); + + // Grow memory. + // DO NOT SUPPORT + printf("Bypass Growing memory...\n"); + wasm_extern_vec_delete(&exports); + wasm_instance_delete(instance); + + // Create stand-alone memory. + // DO NOT SUPPORT + // TODO(wasm+): Once Wasm allows multiple memories, turn this into import. + printf("Bypass Creating stand-alone memory...\n"); + + // 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/memory.wat b/samples/wasm-c-api/src/memory.wat new file mode 100644 index 00000000..4cf43e2c --- /dev/null +++ b/samples/wasm-c-api/src/memory.wat @@ -0,0 +1,11 @@ +(module + (memory (export "memory") 2 3) + + (func (export "size") (result i32) (memory.size)) + (func (export "load") (param i32) (result i32) (i32.load8_s (local.get 0))) + (func (export "store") (param i32 i32) + (i32.store8 (local.get 0) (local.get 1)) + ) + + (data (i32.const 0x1000) "\01\02\03\04") +) diff --git a/samples/wasm-c-api/src/table.c b/samples/wasm-c-api/src/table.c new file mode 100644 index 00000000..034c5891 --- /dev/null +++ b/samples/wasm-c-api/src/table.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t* neg_callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n"); + results[0].kind = WASM_I32; + results[0].of.i32 = -args[0].of.i32; + return NULL; +} + + +wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) { + printf("> Error accessing table export %zu!\n", i); + exit(1); + } + return wasm_extern_as_table(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]); +} + + +void check(bool success) { + if (!success) { + printf("> Error, expected success\n"); + exit(1); + } +} + +void check_table(wasm_table_t* table, int32_t i, bool expect_set) { + own wasm_ref_t* ref = wasm_table_get(table, i); + check((ref != NULL) == expect_set); + if (ref) wasm_ref_delete(ref); +} + +void check_call(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) { + wasm_val_t args[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + wasm_val_t results[1] = { WASM_INIT_VAL }; + if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) { + printf("> Error on result\n"); + exit(1); + } +} + +void check_trap(wasm_func_t* func, int32_t arg1, int32_t arg2) { + wasm_val_t args[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + wasm_val_t results[1] = { WASM_INIT_VAL }; + own wasm_trap_t* trap = wasm_func_call(func, args, results); + if (! trap) { + printf("> Error on result, expected trap\n"); + exit(1); + } + wasm_trap_delete(trap); +} + + +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("table.aot", "rb"); +#else + FILE* file = fopen("table.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"); + fclose(file); + 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); + + // Instantiate. + printf("Instantiating module...\n"); + own wasm_instance_t *instance = + wasm_instance_new(store, module, NULL, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + // Extract export. + printf("Extracting exports...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + size_t i = 0; + wasm_table_t* table = get_export_table(&exports, i++); + wasm_func_t* call_indirect = get_export_func(&exports, i++); + wasm_func_t* f = get_export_func(&exports, i++); + wasm_func_t* g = get_export_func(&exports, i++); + + wasm_module_delete(module); + + // Create external function. + printf("Creating callback...\n"); + own wasm_functype_t* neg_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32()); + + wasm_functype_delete(neg_type); + + // Try cloning. + own wasm_table_t* copy = wasm_table_copy(table); + assert(wasm_table_same(table, copy)); + wasm_table_delete(copy); + + // Check initial table. + printf("Checking table...\n"); + check(wasm_table_size(table) == 2); + check_table(table, 0, false); + check_table(table, 1, true); + check_trap(call_indirect, 0, 0); + check_call(call_indirect, 7, 1, 7); + check_trap(call_indirect, 0, 2); + + // Mutate table. + printf("Mutating table...\n"); + check(wasm_table_set(table, 0, wasm_func_as_ref(g))); + check(wasm_table_set(table, 1, NULL)); + check(! wasm_table_set(table, 2, wasm_func_as_ref(f))); + check_table(table, 0, true); + check_table(table, 1, false); + check_call(call_indirect, 7, 0, 666); + check_trap(call_indirect, 0, 1); + check_trap(call_indirect, 0, 2); + + // Grow table. + // DO NOT SUPPORT + printf("Bypass Growing table...\n"); + wasm_extern_vec_delete(&exports); + wasm_instance_delete(instance); + + // Create stand-alone table. + // DO NOT SUPPORT + // TODO(wasm+): Once Wasm allows multiple tables, turn this into import. + printf("Bypass Creating stand-alone table...\n"); + + // 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/table.wat b/samples/wasm-c-api/src/table.wat new file mode 100644 index 00000000..d3e3a945 --- /dev/null +++ b/samples/wasm-c-api/src/table.wat @@ -0,0 +1,12 @@ +(module + (table (export "table") 2 10 funcref) + + (func (export "call_indirect") (param i32 i32) (result i32) + (call_indirect (param i32) (result i32) (local.get 0) (local.get 1)) + ) + + (func $f (export "f") (param i32) (result i32) (local.get 0)) + (func (export "g") (param i32) (result i32) (i32.const 666)) + + (elem (i32.const 1) $f) +)