Implement most missing wasm-c-api APIs (#303) (#676)

Remove unnecessary functions and implement more APIs:
- wasm_##name##same
- wasm##name##as_ref
- wasm_ref_as##name##
- wasm_ref_delete
- wasm_module_validate
- wasm_table_get/set/size
- wasm_memory_size
- wasm_config_new
- wasm_foreign_new

And add more wasm-c-api samples, update the related documen, add more CI rules.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang 2021-07-28 21:53:37 +08:00 committed by GitHub
parent 4193949ef5
commit edb184f709
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1872 additions and 450 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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** <liang.he@intel.com>
- [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin** <xiaokang.qxk@antgroup.com>

View File

@ -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

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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 **)&param->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;
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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)
///////////////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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;
}

View File

@ -456,4 +456,3 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env);
#endif
#endif /* end of _WASM_RUNTIME_H */

View File

@ -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);
```
```

View File

@ -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

View File

@ -0,0 +1,263 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#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;
}

View File

@ -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))
)
)

View File

@ -0,0 +1,209 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#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;
}

View File

@ -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")
)

View File

@ -0,0 +1,182 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#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;
}

View File

@ -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)
)