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

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

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