Import reference-types feature (#612)

Implement spec reference-types proposal for interpreter, AOT and JIT, update documents and add sample. And upgrade AOT_CURRENT_VERSION to 3 as AOT file format and AOT module instance layout are changed.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang 2021-04-15 11:29:20 +08:00 committed by GitHub
parent 7706e4b151
commit 03d45f1d62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 5557 additions and 856 deletions

View File

@ -25,8 +25,8 @@ iwasm VM core
- Choices of WASM application libc support: the built-in libc subset for the embedded environment or [WASI](https://github.com/WebAssembly/WASI) for standard libc
- [Embeddable with the supporting C API's](./doc/embed_wamr.md)
- [The mechanism for exporting native API's to WASM applications](./doc/export_native_api.md)
- [Multiple modules as dependencies](./doc/multi_module.md)
- [Thread management and pthread library](./doc/pthread_library.md)
- [Multiple modules as dependencies](./doc/multi_module.md), ref to [sample](samples/multi-module)
- [Thread management and pthread library](./doc/pthread_library.md), ref to [sample](samples/multi-thread)
### post-MVP features
- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions)
@ -34,9 +34,10 @@ iwasm VM core
- [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations)
- [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory)
- [Multi-value](https://github.com/WebAssembly/multi-value)
- [wasm-c-api](https://github.com/WebAssembly/wasm-c-api)
- [wasm-c-api](https://github.com/WebAssembly/wasm-c-api), ref to [document](doc/wasm_c_api.md) and [sample](samples/wasm-c-api)
- [Tail-call](https://github.com/WebAssembly/tail-call)
- [128-bit SIMD](https://github.com/WebAssembly/simd)
- [128-bit SIMD](https://github.com/WebAssembly/simd), ref to [samples/workload](samples/workload)
- [Reference Types](https://github.com/WebAssembly/reference-types), ref to [document](doc/ref_types.md) and [sample](samples/ref-types)
### Supported architectures and platforms
@ -124,6 +125,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a
- **[multi-thread](./samples/multi-thread/)**: Demonstrating how to run wasm application which creates multiple threads to execute wasm functions concurrently, and uses mutex/cond by calling pthread related API's.
- **[spawn-thread](./samples/spawn-thread)**: Demonstrating how to execute wasm functions of the same wasm application concurrently, in threads created by host embedder or runtime, but not the wasm application itself.
- **[multi-module](./samples/multi-module)**: Demonstrating the [multiple modules as dependencies](./doc/multi_module.md) feature which implements the [load-time dynamic linking](https://webassembly.org/docs/dynamic-linking/).
- **[ref-types](./samples/ref-types)**: Demonstrating how to call wasm functions with argument of externref type introduced by [reference types proposal](https://github.com/WebAssembly/reference-types).
- **[wasm-c-api](./samples/wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's.
- **[workload](./samples/workload/README.md)**: Demonstrating how to build and run some complex workloads, e.g. tensorflow-lite, XNNPACK, wasm-av1, meshoptimizer and bwa.

View File

@ -206,6 +206,12 @@ if (WAMR_BUILD_TAIL_CALL EQUAL 1)
add_definitions (-DWASM_ENABLE_TAIL_CALL=1)
message (" Tail call enabled")
endif ()
if (WAMR_BUILD_REF_TYPES EQUAL 1)
add_definitions (-DWASM_ENABLE_REF_TYPES=1)
message (" Reference types enabled")
else ()
message (" Reference types disabled")
endif ()
if (DEFINED WAMR_BH_VPRINTF)
add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF})
endif ()

View File

@ -66,7 +66,7 @@
#endif
#define AOT_MAGIC_NUMBER 0x746f6100
#define AOT_CURRENT_VERSION 2
#define AOT_CURRENT_VERSION 3
#ifndef WASM_ENABLE_JIT
#define WASM_ENABLE_JIT 0
@ -289,5 +289,9 @@
#define WASM_ENABLE_CUSTOM_NAME_SECTION 0
#endif
#ifndef WASM_ENABLE_REF_TYPES
#define WASM_ENABLE_REF_TYPES 0
#endif
#endif /* end of _CONFIG_H_ */

View File

@ -506,6 +506,39 @@ destroy_table_init_data_list(AOTTableInitData **data_list, uint32 count,
}
}
static bool
load_import_table_list(const uint8 **p_buf,
const uint8 *buf_end,
AOTModule *module,
char *error_buf,
uint32 error_buf_size)
{
const uint8 *buf = *p_buf;
AOTImportTable *import_table;
uint64 size;
uint32 i, possible_grow;
/* Allocate memory */
size = sizeof(AOTImportTable) * (uint64)module->import_table_count;
if (!(module->import_tables = import_table =
loader_malloc(size, error_buf, error_buf_size))) {
return false;
}
/* keep sync with aot_emit_table_info() aot_emit_aot_file */
for (i = 0; i < module->import_table_count; i++, import_table++) {
read_uint32(buf, buf_end, import_table->table_init_size);
read_uint32(buf, buf_end, import_table->table_max_size);
read_uint32(buf, buf_end, possible_grow);
import_table->possible_grow = (possible_grow & 0x1);
}
*p_buf = buf;
return true;
fail:
return false;
}
static bool
load_table_list(const uint8 **p_buf, const uint8 *buf_end,
AOTModule *module, char *error_buf, uint32 error_buf_size)
@ -513,7 +546,7 @@ load_table_list(const uint8 **p_buf, const uint8 *buf_end,
const uint8 *buf = *p_buf;
AOTTable *table;
uint64 size;
uint32 i;
uint32 i, possible_grow;
/* Allocate memory */
size = sizeof(AOTTable) * (uint64)module->table_count;
@ -528,6 +561,8 @@ load_table_list(const uint8 **p_buf, const uint8 *buf_end,
read_uint32(buf, buf_end, table->table_flags);
read_uint32(buf, buf_end, table->table_init_size);
read_uint32(buf, buf_end, table->table_max_size);
read_uint32(buf, buf_end, possible_grow);
table->possible_grow = (possible_grow & 0x1);
}
*p_buf = buf;
@ -555,9 +590,12 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
/* Create each table data segment */
for (i = 0; i < module->table_init_data_count; i++) {
uint32 mode, elem_type;
uint32 table_index, init_expr_type, func_index_count;
uint64 init_expr_value, size1;
read_uint32(buf, buf_end, mode);
read_uint32(buf, buf_end, elem_type);
read_uint32(buf, buf_end, table_index);
read_uint32(buf, buf_end, init_expr_type);
read_uint64(buf, buf_end, init_expr_value);
@ -570,6 +608,9 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
return false;
}
data_list[i]->mode = mode;
data_list[i]->elem_type = elem_type;
data_list[i]->is_dropped = false;
data_list[i]->table_index = table_index;
data_list[i]->offset.init_expr_type = (uint8)init_expr_type;
data_list[i]->offset.u.i64 = (int64)init_expr_value;
@ -591,13 +632,14 @@ load_table_info(const uint8 **p_buf, const uint8 *buf_end,
const uint8 *buf = *p_buf;
read_uint32(buf, buf_end, module->import_table_count);
/* We don't support import_table_count > 0 currently */
bh_assert(module->import_table_count == 0);
if (module->import_table_count > 0
&& !load_import_table_list(&buf, buf_end, module, error_buf,
error_buf_size))
return false;
read_uint32(buf, buf_end, module->table_count);
if (module->table_count > 0
&& !load_table_list(&buf, buf_end, module,
error_buf, error_buf_size))
&& !load_table_list(&buf, buf_end, module, error_buf, error_buf_size))
return false;
read_uint32(buf, buf_end, module->table_init_data_count);
@ -2457,11 +2499,15 @@ aot_convert_wasm_module(WASMModule *wasm_module,
#endif
#if WASM_ENABLE_SIMD != 0
option.enable_simd = true;
#endif
#if WASM_ENABLE_REF_TYPES != 0
option.enable_ref_types = true;
#endif
option.enable_aux_stack_check = true;
#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
option.enable_aux_stack_frame = true;
#endif
comp_ctx = aot_create_comp_context(comp_data, &option);
if (!comp_ctx) {
aot_last_error = aot_get_last_error();

View File

@ -29,6 +29,17 @@ typedef struct {
#define REG_ATOMIC_WAIT_SYM()
#endif
#if WASM_ENABLE_REF_TYPES != 0
#define REG_REF_TYPES_SYM() \
REG_SYM(aot_drop_table_seg), \
REG_SYM(aot_table_init), \
REG_SYM(aot_table_copy), \
REG_SYM(aot_table_fill), \
REG_SYM(aot_table_grow),
#else
#define REG_REF_TYPES_SYM()
#endif
#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
#define REG_AOT_TRACE_SYM() \
REG_SYM(aot_alloc_frame), \
@ -41,8 +52,8 @@ typedef struct {
REG_SYM(aot_set_exception_with_id), \
REG_SYM(aot_invoke_native), \
REG_SYM(aot_call_indirect), \
REG_SYM(wasm_runtime_enlarge_memory), \
REG_SYM(wasm_runtime_set_exception), \
REG_SYM(aot_enlarge_memory), \
REG_SYM(aot_set_exception), \
{"memset", (void*)aot_memset}, \
{"memmove", (void*)aot_memmove}, \
REG_SYM(fmin), \
@ -59,6 +70,7 @@ typedef struct {
REG_SYM(rintf), \
REG_BULK_MEMORY_SYM() \
REG_ATOMIC_WAIT_SYM() \
REG_REF_TYPES_SYM() \
REG_AOT_TRACE_SYM()
#define CHECK_RELOC_OFFSET(data_size) do { \

View File

@ -89,6 +89,10 @@ init_global_data(uint8 *global_data, uint8 type,
switch (type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
*(int32*)global_data = initial_value->i32;
break;
case VALUE_TYPE_I64:
@ -143,6 +147,13 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
.global_data_linked);
break;
}
#if WASM_ENABLE_REF_TYPES != 0
case INIT_EXPR_TYPE_REFNULL_CONST:
{
*(uint32 *)p = NULL_REF;
break;
}
#endif
default:
{
init_global_data(p, global->type, &init_expr->u);
@ -157,22 +168,86 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
return true;
}
AOTTableInstance *
aot_next_tbl_inst(const AOTTableInstance *tbl_inst)
{
uint32 offset = offsetof(AOTTableInstance, data);
offset += tbl_inst->max_size * sizeof(uint32);
return (AOTTableInstance *)((uint8 *)tbl_inst + offset);
}
static inline AOTTableInstance *
aot_get_table_inst(const AOTModuleInstance *module_inst, uint32 tbl_idx)
{
uint32 i = 0;
AOTTableInstance *tbl_inst = (AOTTableInstance*)module_inst->tables.ptr;
while (i != tbl_idx) {
tbl_inst = aot_next_tbl_inst(tbl_inst);
++i;
}
return tbl_inst;
}
static bool
table_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
char *error_buf, uint32 error_buf_size)
{
uint32 i, global_index, global_data_offset, base_offset, length;
AOTTableInitData *table_seg;
AOTTableInstance *tbl_inst = (AOTTableInstance*)module_inst->tables.ptr;
/*
* treat import table like a local one until we enable module linking
* in AOT mode
*/
for (i = 0; i != module_inst->table_count; ++i) {
if (i < module->import_table_count) {
AOTImportTable *import_table = module->import_tables + i;
tbl_inst->cur_size = import_table->table_init_size;
tbl_inst->max_size = aot_get_imp_tbl_data_slots(import_table);
}
else {
AOTTable *table =
module->tables + (i - module->import_table_count);
tbl_inst->cur_size = table->table_init_size;
tbl_inst->max_size = aot_get_tbl_data_slots(table);
}
tbl_inst = aot_next_tbl_inst(tbl_inst);
}
/* fill table with element segment content */
for (i = 0; i < module->table_init_data_count; i++) {
AOTTableInstance *tbl_inst;
table_seg = module->table_init_data_list[i];
bh_assert(table_seg->offset.init_expr_type ==
INIT_EXPR_TYPE_I32_CONST
|| table_seg->offset.init_expr_type ==
INIT_EXPR_TYPE_GET_GLOBAL);
#if WASM_ENABLE_REF_TYPES != 0
if (!wasm_elem_is_active(table_seg->mode))
continue;
#endif
bh_assert(table_seg->table_index < module_inst->table_count);
tbl_inst = aot_get_table_inst(module_inst, table_seg->table_index);
bh_assert(tbl_inst);
bh_assert(
table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST
|| table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL
#if WASM_ENABLE_REF_TYPES != 0
|| table_seg->offset.init_expr_type
== INIT_EXPR_TYPE_FUNCREF_CONST
|| table_seg->offset.init_expr_type
== INIT_EXPR_TYPE_REFNULL_CONST
#endif
);
/* Resolve table data base offset */
if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
if (table_seg->offset.init_expr_type
== INIT_EXPR_TYPE_GET_GLOBAL) {
global_index = table_seg->offset.u.global_index;
if (!check_global_init_expr(module, global_index,
@ -182,36 +257,42 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
if (global_index < module->import_global_count)
global_data_offset =
module->import_globals[global_index].data_offset;
module->import_globals[global_index].data_offset;
else
global_data_offset =
module->globals[global_index - module->import_global_count]
.data_offset;
module
->globals[global_index - module->import_global_count]
.data_offset;
base_offset = *(uint32*)
((uint8*)module_inst->global_data.ptr + global_data_offset);
base_offset = *(uint32 *)((uint8 *)module_inst->global_data.ptr
+ global_data_offset);
}
else
base_offset = (uint32)table_seg->offset.u.i32;
/* Copy table data */
bh_assert(module_inst->table_data.ptr);
/* base_offset only since length might negative */
if (base_offset > module_inst->table_size) {
LOG_DEBUG("base_offset(%d) > table_size(%d)", base_offset,
module_inst->table_size);
if (base_offset > tbl_inst->cur_size) {
#if WASM_ENABLE_REF_TYPES != 0
set_error_buf(error_buf, error_buf_size,
"out of bounds table access");
#else
set_error_buf(error_buf, error_buf_size,
"elements segment does not fit");
#endif
return false;
}
/* base_offset + length(could be zero) */
length = table_seg->func_index_count;
if (base_offset + length > module_inst->table_size) {
LOG_DEBUG("base_offset(%d) + length(%d) > table_size(%d)",
base_offset, length, module_inst->table_size);
if (base_offset + length > tbl_inst->cur_size) {
#if WASM_ENABLE_REF_TYPES != 0
set_error_buf(error_buf, error_buf_size,
"out of bounds table access");
#else
set_error_buf(error_buf, error_buf_size,
"elements segment does not fit");
#endif
return false;
}
@ -219,9 +300,9 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
* Check function index in the current module inst for now.
* will check the linked table inst owner in future
*/
memcpy((uint32 *)module_inst->table_data.ptr + base_offset,
table_seg->func_indexes,
length * sizeof(uint32));
bh_memcpy_s((uint32 *)tbl_inst->data + base_offset,
(tbl_inst->max_size - base_offset) * sizeof(uint32),
table_seg->func_indexes, length * sizeof(uint32));
}
return true;
@ -595,8 +676,13 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
if (base_offset > memory_inst->memory_data_size) {
LOG_DEBUG("base_offset(%d) > memory_data_size(%d)", base_offset,
memory_inst->memory_data_size);
#if WASM_ENABLE_REF_TYPES != 0
set_error_buf(error_buf, error_buf_size,
"out of bounds memory access");
#else
set_error_buf(error_buf, error_buf_size,
"data segment does not fit");
#endif
return false;
}
@ -605,8 +691,13 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
if (base_offset + length > memory_inst->memory_data_size) {
LOG_DEBUG("base_offset(%d) + length(%d) > memory_data_size(%d)",
base_offset, length, memory_inst->memory_data_size);
#if WASM_ENABLE_REF_TYPES != 0
set_error_buf(error_buf, error_buf_size,
"out of bounds memory access");
#else
set_error_buf(error_buf, error_buf_size,
"data segment does not fit");
#endif
return false;
}
@ -820,24 +911,39 @@ aot_instantiate(AOTModule *module, bool is_sub_inst,
char *error_buf, uint32 error_buf_size)
{
AOTModuleInstance *module_inst;
uint32 module_inst_struct_size =
const uint32 module_inst_struct_size =
offsetof(AOTModuleInstance, global_table_data.bytes);
uint64 module_inst_mem_inst_size =
const uint64 module_inst_mem_inst_size =
(uint64)module->memory_count * sizeof(AOTMemoryInstance);
uint32 table_size = module->table_count > 0 ?
module->tables[0].table_init_size : 0;
uint64 table_data_size = (uint64)table_size * sizeof(uint32);
uint64 total_size = (uint64)module_inst_struct_size
+ module_inst_mem_inst_size
+ module->global_data_size
+ table_data_size;
uint64 total_size, table_size = 0;
uint8 *p;
uint32 i;
/* Check heap size */
heap_size = align_uint(heap_size, 8);
if (heap_size > APP_HEAP_SIZE_MAX)
heap_size = APP_HEAP_SIZE_MAX;
total_size = (uint64)module_inst_struct_size + module_inst_mem_inst_size
+ module->global_data_size;
/*
* calculate size of table data
*/
for (i = 0; i != module->import_table_count; ++i) {
table_size += offsetof(AOTTableInstance, data);
table_size +=
(uint64)sizeof(uint32)
* (uint64)aot_get_imp_tbl_data_slots(module->import_tables + i);
}
for (i = 0; i != module->table_count; ++i) {
table_size += offsetof(AOTTableInstance, data);
table_size += (uint64)sizeof(uint32)
* (uint64)aot_get_tbl_data_slots(module->tables + i);
}
total_size += table_size;
/* Allocate module instance, global data, table data and heap data */
if (!(module_inst = runtime_malloc(total_size,
error_buf, error_buf_size))) {
@ -857,10 +963,11 @@ aot_instantiate(AOTModule *module, bool is_sub_inst,
/* Initialize table info */
p += module->global_data_size;
module_inst->table_data.ptr = p;
module_inst->table_size = table_size;
module_inst->tables.ptr = p;
module_inst->table_count =
module->table_count + module->import_table_count;
/* Set all elements to -1 to mark them as uninitialized elements */
memset(module_inst->table_data.ptr, -1, (uint32)table_data_size);
memset(module_inst->tables.ptr, 0xff, (uint32)table_size);
if (!table_instantiate(module_inst, module, error_buf, error_buf_size))
goto fail;
@ -1254,12 +1361,21 @@ aot_call_function(WASMExecEnv *exec_env,
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret++;
break;
case VALUE_TYPE_I64:
case VALUE_TYPE_F64:
argv_ret += 2;
break;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
argv_ret += 4;
break;
#endif -
default:
bh_assert(0);
break;
@ -1326,8 +1442,16 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst,
}
#endif
#if WASM_ENABLE_REF_TYPES != 0
wasm_runtime_prepare_call_function(exec_env, func);
#endif
ret = aot_call_function(exec_env, func, argc, argv);
#if WASM_ENABLE_REF_TYPES != 0
wasm_runtime_finalize_call_function(exec_env, func, ret, argv);
#endif
#if WASM_ENABLE_THREAD_MGR != 0
/* don't destroy the exec_env if it's searched from the cluster */
if (!existing_exec_env)
@ -1399,6 +1523,9 @@ aot_set_exception_with_id(AOTModuleInstance *module_inst,
case EXCE_AUX_STACK_UNDERFLOW:
aot_set_exception(module_inst, "wasm auxiliary stack underflow");
break;
case EXCE_OUT_OF_BOUNDS_TABLE_ACCESS:
aot_set_exception(module_inst, "out of bounds table access");
break;
default:
break;
}
@ -2009,17 +2136,16 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
bool
aot_call_indirect(WASMExecEnv *exec_env,
uint32 table_elem_idx,
uint32 tbl_idx, uint32 table_elem_idx,
uint32 argc, uint32 *argv)
{
AOTModuleInstance *module_inst = (AOTModuleInstance*)
wasm_runtime_get_module_inst(exec_env);
AOTModule *aot_module = (AOTModule*)module_inst->aot_module.ptr;
uint32 *func_type_indexes = (uint32*)module_inst->func_type_indexes.ptr;
uint32 *table_data = (uint32*)module_inst->table_data.ptr;
AOTTableInstance *tbl_inst;
AOTFuncType *func_type;
void **func_ptrs = (void**)module_inst->func_ptrs.ptr, *func_ptr;
uint32 table_size = module_inst->table_size;
uint32 func_type_idx, func_idx, ext_ret_count;
AOTImportFunc *import_func;
const char *signature = NULL;
@ -2036,12 +2162,15 @@ aot_call_indirect(WASMExecEnv *exec_env,
return false;
}
if (table_elem_idx >= table_size) {
tbl_inst = aot_get_table_inst(module_inst, tbl_idx);
bh_assert(tbl_inst);
if (table_elem_idx >= tbl_inst->cur_size) {
aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT);
return false;
}
func_idx = table_data[table_elem_idx];
func_idx = ((uint32*)tbl_inst->data)[table_elem_idx];
if (func_idx == (uint32)-1) {
aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT);
return false;
@ -2122,12 +2251,21 @@ aot_call_indirect(WASMExecEnv *exec_env,
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret++;
break;
case VALUE_TYPE_I64:
case VALUE_TYPE_F64:
argv_ret += 2;
break;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
argv_ret += 4;
break;
#endif -
default:
bh_assert(0);
break;
@ -2281,16 +2419,17 @@ aot_get_aux_stack(WASMExecEnv *exec_env,
}
return false;
}
#endif
#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0)
static uint32 const_string_size;
void const_string_node_size_cb(void *key, void *value)
static void
const_string_node_size_cb(void *key, void *value,
void *p_const_string_size)
{
uint32 const_string_size = *(uint32*)p_const_string_size;
const_string_size += bh_hash_map_get_elem_struct_size();
const_string_size += strlen((const char *)value) + 1;
*(uint32*)p_const_string_size += const_string_size;
}
void
@ -2343,12 +2482,14 @@ aot_get_module_mem_consumption(const AOTModule *module,
}
if (module->const_str_set) {
uint32 const_string_size = 0;
mem_conspn->const_strs_size =
bh_hash_map_get_struct_size(module->const_str_set);
const_string_size = 0;
bh_hash_map_traverse(module->const_str_set,
const_string_node_size_cb);
const_string_node_size_cb,
(void*)&const_string_size);
mem_conspn->const_strs_size += const_string_size;
}
@ -2378,6 +2519,7 @@ void
aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
WASMModuleInstMemConsumption *mem_conspn)
{
AOTTableInstance *tbl_inst;
uint32 i;
memset(mem_conspn, 0, sizeof(*mem_conspn));
@ -2399,7 +2541,12 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
mem_allocator_get_heap_struct_size();
}
mem_conspn->tables_size = sizeof(uint32) * module_inst->table_size;
tbl_inst = module_inst->tables.ptr;
for (i = 0; i < module_inst->table_count; i++) {
mem_conspn->tables_size += offsetof(AOTTableInstance, data);
mem_conspn->tables_size += sizeof(uint32) * tbl_inst->max_size;
tbl_inst = aot_next_tbl_inst(tbl_inst);
}
/* func_ptrs and func_type_indexes */
mem_conspn->functions_size = (sizeof(void *) + sizeof(uint32)) *
@ -2421,6 +2568,144 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0)
|| (WASM_ENABLE_MEMORY_TRACING != 0) */
#if WASM_ENABLE_REF_TYPES != 0
void
aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx)
{
AOTModule *module = (AOTModule *)module_inst->aot_module.ptr;
AOTTableInitData *tbl_seg = module->table_init_data_list[tbl_seg_idx];
tbl_seg->is_dropped = true;
}
void
aot_table_init(AOTModuleInstance *module_inst,
uint32 tbl_idx, uint32 tbl_seg_idx,
uint32 length, uint32 src_offset, uint32 dst_offset)
{
AOTTableInstance *tbl_inst;
AOTTableInitData *tbl_seg;
const AOTModule *module = module_inst->aot_module.ptr;
tbl_inst = aot_get_table_inst(module_inst, tbl_idx);
bh_assert(tbl_inst);
tbl_seg = module->table_init_data_list[tbl_seg_idx];
bh_assert(tbl_seg);
if (!length) {
return;
}
if (length + src_offset > tbl_seg->func_index_count
|| dst_offset + length > tbl_inst->cur_size) {
aot_set_exception_with_id(module_inst,
EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
return;
}
if (tbl_seg->is_dropped) {
aot_set_exception_with_id(module_inst,
EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
return;
}
if (!wasm_elem_is_passive(tbl_seg->mode)) {
aot_set_exception_with_id(module_inst,
EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
return;
}
bh_memcpy_s((uint8 *)tbl_inst + offsetof(AOTTableInstance, data)
+ dst_offset * sizeof(uint32),
(tbl_inst->cur_size - dst_offset) * sizeof(uint32),
tbl_seg->func_indexes + src_offset, length * sizeof(uint32));
}
void
aot_table_copy(AOTModuleInstance *module_inst,
uint32 src_tbl_idx, uint32 dst_tbl_idx,
uint32 length, uint32 src_offset, uint32 dst_offset)
{
AOTTableInstance *src_tbl_inst, *dst_tbl_inst;
src_tbl_inst = aot_get_table_inst(module_inst, src_tbl_idx);
bh_assert(src_tbl_inst);
dst_tbl_inst = aot_get_table_inst(module_inst, dst_tbl_idx);
bh_assert(dst_tbl_inst);
if ((uint64)src_offset + length > dst_tbl_inst->cur_size
|| (uint64)dst_offset + length > src_tbl_inst->cur_size) {
aot_set_exception_with_id(module_inst,
EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
return;
}
/* if src_offset >= dst_offset, copy from front to back */
/* if src_offset < dst_offset, copy from back to front */
/* merge all together */
bh_memcpy_s((uint8 *)(dst_tbl_inst) + offsetof(AOTTableInstance, data)
+ dst_offset * sizeof(uint32),
(dst_tbl_inst->cur_size - dst_offset) * sizeof(uint32),
(uint8 *)(src_tbl_inst) + offsetof(AOTTableInstance, data)
+ src_offset * sizeof(uint32),
length * sizeof(uint32));
}
void
aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx,
uint32 length, uint32 val, uint32 data_offset)
{
AOTTableInstance *tbl_inst;
tbl_inst = aot_get_table_inst(module_inst, tbl_idx);
bh_assert(tbl_inst);
if (data_offset + length > tbl_inst->cur_size) {
aot_set_exception_with_id(module_inst,
EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
return;
}
for (; length != 0; data_offset++, length--) {
tbl_inst->data[data_offset] = val;
}
}
uint32
aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx,
uint32 inc_entries, uint32 init_val)
{
uint32 entry_count, i, orig_tbl_sz;
AOTTableInstance *tbl_inst;
tbl_inst = aot_get_table_inst(module_inst, tbl_idx);
if (!tbl_inst) {
return (uint32)-1;
}
orig_tbl_sz = tbl_inst->cur_size;
if (!inc_entries) {
return orig_tbl_sz;
}
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) {
return (uint32)-1;
}
/* fill in */
for (i = 0; i < inc_entries; ++i) {
tbl_inst->data[tbl_inst->cur_size + i] = init_val;
}
tbl_inst->cur_size = entry_count;
return orig_tbl_sz;
}
#endif /* WASM_ENABLE_REF_TYPES != 0 */
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
static const char *
get_func_name_from_index(const AOTModuleInstance *module_inst,
@ -2551,3 +2836,4 @@ aot_dump_perf_profiling(const AOTModuleInstance *module_inst)
}
}
#endif /* end of WASM_ENABLE_PERF_PROFILING */

View File

@ -34,6 +34,7 @@ typedef enum AOTExceptionID {
EXCE_UNALIGNED_ATOMIC,
EXCE_AUX_STACK_OVERFLOW,
EXCE_AUX_STACK_UNDERFLOW,
EXCE_OUT_OF_BOUNDS_TABLE_ACCESS,
EXCE_NUM,
} AOTExceptionID;
@ -251,6 +252,22 @@ typedef struct AOTMemoryInstance {
MemBound mem_bound_check_16bytes;
} AOTMemoryInstance;
typedef struct AOTTableInstance {
uint32 cur_size;
/*
* only grow in the range of [:max_size)
* if the table is growable, max_size equals to its declared maximum size
* otherwise, max_size equals to its declared minimum size
*/
uint32 max_size;
/*
* +------------------------------+ <--- data
* | ref.func[] or ref.extern[]
* +------------------------------+
*/
uint32 data[1];
} AOTTableInstance;
typedef struct AOTModuleInstance {
uint32 module_type;
@ -260,9 +277,17 @@ typedef struct AOTModuleInstance {
/* global and table info */
uint32 global_data_size;
uint32 table_size;
/*
* the count of AOTTableInstance.
* it includes imported tables and local tables.
*
* TODO: for now we treate imported table like a local table
*/
uint32 table_count;
/* points to global_data */
AOTPointer global_data;
AOTPointer table_data;
/* points to AOTTableInstance[] */
AOTPointer tables;
/* funciton pointer array */
AOTPointer func_ptrs;
@ -288,20 +313,26 @@ typedef struct AOTModuleInstance {
AOTPointer aot_module;
/* WASI context */
AOTPointer wasi_ctx;
/* function performance profiling info list */
AOTPointer func_perf_profilings;
/* others */
uint32 temp_ret;
uint32 llvm_stack;
uint32 default_wasm_stack_size;
uint32 __padding;
/* function performance profiling info list */
AOTPointer func_perf_profilings;
/* reserved */
uint32 reserved[8];
uint32 reserved[11];
/*
* +------------------------------+ <-- memories.ptr
* | #0 AOTMemoryInstance
* +------------------------------+ <-- global_data.ptr
* | global data
* +------------------------------+ <-- tables.ptr
* | AOTTableInstance[table_count]
* +------------------------------+
*/
union {
uint64 _make_it_8_byte_aligned_;
AOTMemoryInstance memory_instances[1];
@ -561,7 +592,7 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
bool
aot_call_indirect(WASMExecEnv *exec_env,
uint32 table_elem_idx,
uint32 tbl_idx, uint32 table_elem_idx,
uint32 argc, uint32 *argv);
uint32
@ -608,6 +639,32 @@ void
aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
WASMModuleInstMemConsumption *mem_conspn);
#if WASM_ENABLE_REF_TYPES != 0
void
aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx);
void
aot_table_init(AOTModuleInstance *module_inst,
uint32 tbl_idx, uint32 tbl_seg_idx,
uint32 length, uint32 src_offset, uint32 dst_offset);
void
aot_table_copy(AOTModuleInstance *module_inst,
uint32 src_tbl_idx, uint32 dst_tbl_idx,
uint32 length, uint32 src_offset, uint32 dst_offset);
void
aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx,
uint32 length, uint32 val, uint32 data_offset);
uint32
aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx,
uint32 inc_entries, uint32 init_val);
#endif
AOTTableInstance *
aot_next_tbl_inst(const AOTTableInstance *tbl_inst);
bool
aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index);

View File

@ -116,6 +116,10 @@ typedef struct WASMExecEnv {
WASMJmpBuf *jmpbuf_stack_top;
#endif
#if WASM_ENABLE_REF_TYPES != 0
uint16 nested_calling_depth;
#endif
#if WASM_ENABLE_MEMORY_PROFILING != 0
uint32 max_wasm_stack_used;
#endif

View File

@ -74,7 +74,13 @@ check_symbol_signature(const WASMType *type, const char *signature)
for (i = 0; i < type->param_count; i++) {
sig = *p++;
if (sig == sig_map[type->types[i] - VALUE_TYPE_F64])
if ((type->types[i] >= VALUE_TYPE_F64
&& type->types[i] <= VALUE_TYPE_I32
&& sig == sig_map[type->types[i] - VALUE_TYPE_F64])
#if WASM_ENABLE_REF_TYPES != 0
|| (sig == 'i' && type->types[i] == VALUE_TYPE_EXTERNREF)
#endif
)
/* normal parameter */
continue;

View File

@ -49,6 +49,16 @@ static void
wasm_runtime_destroy_registered_module_list();
#endif /* WASM_ENABLE_MULTI_MODULE */
#if WASM_ENABLE_REF_TYPES != 0
/* Initialize externref hashmap */
static bool
wasm_externref_map_init();
/* Destroy externref hashmap */
static void
wasm_externref_map_destroy();
#endif /* WASM_ENABLE_REF_TYPES */
static void
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
{
@ -119,10 +129,20 @@ wasm_runtime_env_init()
#endif
#endif
#if WASM_ENABLE_REF_TYPES != 0
if (!wasm_externref_map_init()) {
goto fail7;
}
#endif
return true;
#if WASM_ENABLE_REF_TYPES != 0
fail7:
#endif
#if WASM_ENABLE_AOT != 0
#ifdef OS_ENABLE_HW_BOUND_CHECK
aot_signal_destroy();
fail6:
#endif
#endif
@ -175,6 +195,10 @@ wasm_runtime_init()
void
wasm_runtime_destroy()
{
#if WASM_ENABLE_REF_TYPES != 0
wasm_externref_map_destroy();
#endif
#if WASM_ENABLE_AOT != 0
#ifdef OS_ENABLE_HW_BOUND_CHECK
aot_signal_destroy();
@ -997,10 +1021,35 @@ wasm_runtime_get_user_data(WASMExecEnv *exec_env)
return exec_env->user_data;
}
WASMType *
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
uint32 module_type)
{
WASMType *type = NULL;
#if WASM_ENABLE_INTERP != 0
if (module_type == Wasm_Module_Bytecode) {
WASMFunctionInstance *wasm_func = (WASMFunctionInstance *)function;
type = wasm_func->is_import_func
? wasm_func->u.func_import->func_type
: wasm_func->u.func->func_type;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_type == Wasm_Module_AoT) {
AOTFunctionInstance *aot_func = (AOTFunctionInstance *)function;
type = aot_func->is_import_func
? aot_func->u.func_import->func_type
: aot_func->u.func.func_type;
}
#endif
return type;
}
WASMFunctionInstanceCommon *
wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst,
const char *name,
const char *signature)
const char *name, const char *signature)
{
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode)
@ -1017,11 +1066,57 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst,
return NULL;
}
#if WASM_ENABLE_REF_TYPES != 0
static void
wasm_runtime_reclaim_externref(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
uint32 *argv)
{
uint32 i = 0, cell_num = 0;
WASMType *func_type = wasm_runtime_get_function_type(
function, exec_env->module_inst->module_type);
bh_assert(func_type);
while (i < func_type->result_count) {
uint8 result_type = func_type->types[func_type->param_count + i];
if (result_type == VALUE_TYPE_EXTERNREF && argv[i] != NULL_REF) {
/* Retain the externref returned to runtime embedder */
(void)wasm_externref_retain(argv[i]);
}
cell_num += wasm_value_type_cell_num(result_type);
i++;
}
wasm_externref_reclaim(exec_env->module_inst);
}
void
wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function)
{
exec_env->nested_calling_depth++;
}
void
wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
bool ret, uint32 *argv)
{
exec_env->nested_calling_depth--;
if (!exec_env->nested_calling_depth && ret) {
wasm_runtime_reclaim_externref(exec_env, function, argv);
}
}
#endif
bool
wasm_runtime_call_wasm(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
uint32 argc, uint32 argv[])
{
bool ret = false;
if (!wasm_runtime_exec_env_check(exec_env)) {
LOG_ERROR("Invalid exec env stack info.");
return false;
@ -1030,19 +1125,28 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
/* set thread handle and stack boundary */
wasm_exec_env_set_thread_info(exec_env);
#if WASM_ENABLE_REF_TYPES != 0
wasm_runtime_prepare_call_function(exec_env, function);
#endif
#if WASM_ENABLE_INTERP != 0
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode)
return wasm_call_function(exec_env,
ret = wasm_call_function(exec_env,
(WASMFunctionInstance*)function,
argc, argv);
#endif
#if WASM_ENABLE_AOT != 0
if (exec_env->module_inst->module_type == Wasm_Module_AoT)
return aot_call_function(exec_env,
ret = aot_call_function(exec_env,
(AOTFunctionInstance*)function,
argc, argv);
#endif
return false;
#if WASM_ENABLE_REF_TYPES != 0
wasm_runtime_finalize_call_function(exec_env, function, ret, argv);
#endif
return ret;
}
static uint32
@ -1142,32 +1246,21 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env,
uint32 num_results, wasm_val_t results[],
uint32 num_args, wasm_val_t args[])
{
uint32 argc, *argv, ret_num, cell_num, total_size;
uint32 argc, *argv, ret_num, cell_num, total_size, module_type;
WASMType *type;
bool ret = false;
WASMType *type = NULL;
#if WASM_ENABLE_INTERP != 0
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) {
WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function;
type = wasm_func->u.func->func_type;
argc = wasm_func->param_cell_num;
cell_num = argc > wasm_func->ret_cell_num ?
argc : wasm_func->ret_cell_num;
}
#endif
#if WASM_ENABLE_AOT != 0
if (exec_env->module_inst->module_type == Wasm_Module_AoT) {
type = ((AOTFunctionInstance*)function)->u.func.func_type;
argc = type->param_cell_num;
cell_num = argc > type->ret_cell_num ?
argc : type->ret_cell_num;
}
#endif
module_type = exec_env->module_inst->module_type;
type = wasm_runtime_get_function_type(function, module_type);
if (!type) {
LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one.");
goto fail1;
}
argc = type->param_cell_num;
cell_num = (argc > type->ret_cell_num) ? argc : type->ret_cell_num;
if (num_results != type->result_count) {
LOG_ERROR("The result value number does not match the function declaration.");
goto fail1;
@ -1207,27 +1300,21 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env,
wasm_val_t *args = NULL;
WASMType *type = NULL;
bool ret = false;
uint32 i = 0;
uint32 i = 0, module_type;
va_list vargs;
#if WASM_ENABLE_INTERP != 0
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) {
WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)function;
type = wasm_func->u.func->func_type;
}
#endif
#if WASM_ENABLE_AOT != 0
if (exec_env->module_inst->module_type == Wasm_Module_AoT) {
type = ((AOTFunctionInstance*)function)->u.func.func_type;
}
#endif
module_type = exec_env->module_inst->module_type;
type = wasm_runtime_get_function_type(function, module_type);
if (!type) {
LOG_ERROR("Function type get failed, WAMR Interpreter and AOT must be enabled at least one.");
LOG_ERROR("Function type get failed, WAMR Interpreter and AOT "
"must be enabled at least one.");
goto fail1;
}
if (num_args != type->param_count) {
LOG_ERROR("The argument value number does not match the function declaration.");
LOG_ERROR("The argument value number does not match the "
"function declaration.");
goto fail1;
}
if (!(args = runtime_malloc(sizeof(wasm_val_t) * num_args, NULL, NULL, 0))) {
@ -1260,7 +1347,8 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env,
}
}
va_end(vargs);
ret = wasm_runtime_call_wasm_a(exec_env, function, num_results, results, num_args, args);
ret = wasm_runtime_call_wasm_a(exec_env, function, num_results, results,
num_args, args);
wasm_runtime_free(args);
fail1:
@ -1272,21 +1360,21 @@ wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst
WASMFunctionInstanceCommon *function,
uint32 argc, uint32 argv[])
{
bool ret = false;
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode)
return wasm_create_exec_env_and_call_function(
(WASMModuleInstance*)module_inst,
(WASMFunctionInstance*)function,
argc, argv);
ret = wasm_create_exec_env_and_call_function(
(WASMModuleInstance *)module_inst, (WASMFunctionInstance *)function,
argc, argv);
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT)
return aot_create_exec_env_and_call_function(
(AOTModuleInstance*)module_inst,
(AOTFunctionInstance*)function,
argc, argv);
ret = aot_create_exec_env_and_call_function(
(AOTModuleInstance *)module_inst, (AOTFunctionInstance *)function,
argc, argv);
#endif
return false;
return ret;
}
void
@ -2192,8 +2280,8 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
uint32 argv_buf_offset = 0;
int32 i;
char *argv_buf, *p, *p_end;
uint32 *argv_offsets;
bool ret;
uint32 *argv_offsets, module_type;
bool ret, is_import_func = true;
#if WASM_ENABLE_LIBC_WASI != 0
if (wasm_runtime_is_wasi_mode(module_inst)) {
@ -2219,19 +2307,24 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
if (((WASMFunctionInstance*)func)->is_import_func) {
wasm_runtime_set_exception(module_inst,
"lookup main function failed");
return false;
}
func_type = ((WASMFunctionInstance*)func)->u.func->func_type;
is_import_func = ((WASMFunctionInstance*)func)->is_import_func;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT)
func_type = ((AOTFunctionInstance*)func)->u.func.func_type;
if (module_inst->module_type == Wasm_Module_AoT) {
is_import_func = ((AOTFunctionInstance*)func)->is_import_func;
}
#endif
if (is_import_func) {
wasm_runtime_set_exception(module_inst,
"lookup main function failed");
return false;
}
module_type = module_inst->module_type;
func_type = wasm_runtime_get_function_type(func, module_type);
if (!func_type) {
LOG_ERROR("invalid module instance type");
return false;
@ -2462,7 +2555,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
WASMFunctionInstanceCommon *func;
WASMType *type = NULL;
uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0;
int32 i, p;
int32 i, p, module_type;
uint64 total_size;
const char *exception;
char buf[128];
@ -2489,22 +2582,12 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
wasm_runtime_set_exception(module_inst, buf);
goto fail;
}
type = wasm_func->is_import_func ? wasm_func->u.func_import->func_type
: wasm_func->u.func->func_type;
argc1 = wasm_func->param_cell_num;
cell_num = argc1 > wasm_func->ret_cell_num ?
argc1 : wasm_func->ret_cell_num;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
type = ((AOTFunctionInstance*)func)->u.func.func_type;
argc1 = type->param_cell_num;
cell_num = argc1 > type->ret_cell_num ?
argc1 : type->ret_cell_num;
}
#endif
module_type = module_inst->module_type;
type = wasm_runtime_get_function_type(func, module_type);
if (!type) {
LOG_ERROR("invalid module instance type");
return false;
@ -2516,6 +2599,9 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
goto fail;
}
argc1 = type->param_cell_num;
cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num;
total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2);
if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst,
NULL, 0)))) {
@ -2619,6 +2705,38 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
break;
}
#endif /* WASM_ENABLE_SIMD != 0 */
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
{
if (strncasecmp(argv[i], "null", 4) == 0) {
argv1[p++] = NULL_REF;
}
else {
argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0);
}
break;
}
case VALUE_TYPE_EXTERNREF:
{
if (strncasecmp(argv[i], "null", 4) == 0) {
argv1[p++] = NULL_REF;
}
else {
uint64 val = strtoull(argv[i], &endptr, 0);
void *extern_obj = (void *)(uintptr_t)val;
uint32 externref_idx;
if (!wasm_externref_obj2ref(module_inst, extern_obj,
&externref_idx)) {
wasm_runtime_set_exception(
module_inst, "map extern object to ref failed");
goto fail;
}
argv1[p++] = externref_idx;
}
break;
}
#endif /* WASM_ENABLE_REF_TYPES */
default:
bh_assert(0);
break;
@ -2666,9 +2784,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
break;
}
case VALUE_TYPE_F32:
{
os_printf("%.7g:f32", *(float32*)(argv1 + k));
k++;
break;
}
case VALUE_TYPE_F64:
{
union { float64 val; uint32 parts[2]; } u;
@ -2678,6 +2798,31 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
os_printf("%.7g:f64", u.val);
break;
}
#if WASM_ENABLE_REF_TYPES
case VALUE_TYPE_FUNCREF:
{
if (argv1[k] != NULL_REF)
os_printf("%u:ref.func", argv1[k]);
else
os_printf("func:ref.null");
k++;
break;
}
case VALUE_TYPE_EXTERNREF:
{
if (argv1[k] != NULL_REF) {
void *extern_obj = NULL;
bool ret = wasm_externref_ref2obj(argv1[k], &extern_obj);
bh_assert(ret);
(void)ret;
os_printf("%p:ref.extern", extern_obj);
}
else
os_printf("extern:ref.null");
k++;
break;
}
#endif
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
{
@ -2802,6 +2947,12 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
case VALUE_TYPE_F32:
*(float32*)argv_dst = *(float32*)argv_src++;
break;
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
*(uint32*)argv_dst = *argv_src++;
break;
#endif
default:
bh_assert(0);
break;
@ -2815,6 +2966,10 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
if (func_type->result_count > 0) {
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret[0] = *(uint32*)argv1;
break;
case VALUE_TYPE_F32:
@ -2899,6 +3054,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
for (i = 0; i < func_type->param_count; i++) {
switch (func_type->types[i]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
if (n_ints < MAX_REG_INTS)
n_ints++;
else
@ -3067,6 +3226,17 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
stacks[n_stacks++] = arg_i32;
break;
}
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
{
if (n_ints < MAX_REG_INTS)
ints[n_ints++] = *argv_src++;
else
stacks[n_stacks++] = *argv_src++;
break;
}
#endif
case VALUE_TYPE_I64:
{
if (n_ints < MAX_REG_INTS - 1) {
@ -3204,6 +3374,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
else {
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks);
break;
case VALUE_TYPE_I64:
@ -3341,6 +3515,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
argv1[j++] = *argv++;
break;
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv1[j++] = *argv++;
break;
default:
@ -3360,6 +3538,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
else {
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, argc1);
break;
case VALUE_TYPE_I64:
@ -3582,6 +3764,15 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
}
argv_src += 2;
break;
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
if (n_ints < MAX_REG_INTS)
ints[n_ints++] = *argv_src++;
else
stacks[n_stacks++] = *argv_src++;
break;
#endif
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
if (n_fps < MAX_REG_FLOATS) {
@ -3617,6 +3808,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
/* Invoke the native function and get the first result value */
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks);
break;
case VALUE_TYPE_I64:
@ -3670,11 +3865,11 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env,
#if WASM_ENABLE_INTERP != 0
if (exec_env->module_inst->module_type == Wasm_Module_Bytecode)
return wasm_call_indirect(exec_env, element_indices, argc, argv);
return wasm_call_indirect(exec_env, 0, element_indices, argc, argv);
#endif
#if WASM_ENABLE_AOT != 0
if (exec_env->module_inst->module_type == Wasm_Module_AoT)
return aot_call_indirect(exec_env, element_indices, argc, argv);
return aot_call_indirect(exec_env, 0, element_indices, argc, argv);
#endif
return false;
}
@ -3795,8 +3990,318 @@ wasm_runtime_join_thread(wasm_thread_t tid, void **retval)
return os_thread_join((korp_tid)tid, retval);
}
#endif /* end of WASM_ENABLE_THREAD_MGR */
#if WASM_ENABLE_REF_TYPES != 0
static korp_mutex externref_lock;
static uint32 externref_global_id = 1;
static HashMap *externref_map;
typedef struct ExternRefMapNode {
/* The extern object from runtime embedder */
void *extern_obj;
/* The module instance it belongs to */
WASMModuleInstanceCommon *module_inst;
/* Whether it is retained */
bool retained;
/* Whether it is marked by runtime */
bool marked;
} ExternRefMapNode;
static uint32
wasm_externref_hash(const void *key)
{
uint32 externref_idx = (uint32)(uintptr_t)key;
return externref_idx;
}
static bool
wasm_externref_equal(void *key1, void *key2)
{
uint32 externref_idx1 = (uint32)(uintptr_t)key1;
uint32 externref_idx2 = (uint32)(uintptr_t)key2;
return externref_idx1 == externref_idx2 ? true : false;
}
static bool
wasm_externref_map_init()
{
if (os_mutex_init(&externref_lock) != 0)
return false;
if (!(externref_map = bh_hash_map_create(32, false,
wasm_externref_hash,
wasm_externref_equal,
NULL,
wasm_runtime_free))) {
os_mutex_destroy(&externref_lock);
return false;
}
externref_global_id = 1;
return true;
}
static void
wasm_externref_map_destroy()
{
bh_hash_map_destroy(externref_map);
os_mutex_destroy(&externref_lock);
}
typedef struct LookupExtObj_UserData {
ExternRefMapNode node;
bool found;
uint32 externref_idx;
} LookupExtObj_UserData;
static void
lookup_extobj_callback(void *key, void *value, void *user_data)
{
uint32 externref_idx = (uint32)(uintptr_t)key;
ExternRefMapNode *node = (ExternRefMapNode *)value;
LookupExtObj_UserData *user_data_lookup = (LookupExtObj_UserData *)
user_data;
if (node->extern_obj == user_data_lookup->node.extern_obj
&& node->module_inst == user_data_lookup->node.module_inst) {
user_data_lookup->found = true;
user_data_lookup->externref_idx = externref_idx;
}
}
bool
wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst,
void *extern_obj, uint32 *p_externref_idx)
{
LookupExtObj_UserData lookup_user_data;
ExternRefMapNode *node;
uint32 externref_idx;
lookup_user_data.node.extern_obj = extern_obj;
lookup_user_data.node.module_inst = module_inst;
lookup_user_data.found = false;
os_mutex_lock(&externref_lock);
/* Lookup hashmap firstly */
bh_hash_map_traverse(externref_map, lookup_extobj_callback,
(void*)&lookup_user_data);
if (lookup_user_data.found) {
*p_externref_idx = lookup_user_data.externref_idx;
os_mutex_unlock(&externref_lock);
return true;
}
/* Not found in hashmap */
if (externref_global_id == NULL_REF
|| externref_global_id == 0) {
goto fail1;
}
if (!(node = wasm_runtime_malloc(sizeof(ExternRefMapNode)))) {
goto fail1;
}
memset(node, 0, sizeof(ExternRefMapNode));
node->extern_obj = extern_obj;
node->module_inst = module_inst;
externref_idx = externref_global_id;
if (!bh_hash_map_insert(externref_map,
(void*)(uintptr_t)externref_idx,
(void*)node)) {
goto fail2;
}
externref_global_id++;
*p_externref_idx = externref_idx;
os_mutex_unlock(&externref_lock);
return true;
fail2:
wasm_runtime_free(node);
fail1:
os_mutex_unlock(&externref_lock);
return false;
}
bool
wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj)
{
ExternRefMapNode *node;
if (externref_idx == NULL_REF) {
return false;
}
os_mutex_lock(&externref_lock);
node = bh_hash_map_find(externref_map,
(void*)(uintptr_t)externref_idx);
os_mutex_unlock(&externref_lock);
if (!node)
return false;
*p_extern_obj = node->extern_obj;
return true;
}
static void
reclaim_extobj_callback(void *key, void *value, void *user_data)
{
ExternRefMapNode *node = (ExternRefMapNode *)value;
WASMModuleInstanceCommon *module_inst = (WASMModuleInstanceCommon *)
user_data;
if (node->module_inst == module_inst) {
if (!node->marked && !node->retained) {
bh_hash_map_remove(externref_map, key, NULL, NULL);
wasm_runtime_free(value);
}
else {
node->marked = false;
}
}
}
static void
mark_externref(uint32 externref_idx)
{
ExternRefMapNode *node;
if (externref_idx != NULL_REF) {
node = bh_hash_map_find(externref_map,
(void*)(uintptr_t)externref_idx);
if (node) {
node->marked = true;
}
}
}
#if WASM_ENABLE_INTERP != 0
static void
interp_mark_all_externrefs(WASMModuleInstance *module_inst)
{
uint32 i, j, externref_idx, *table_data;
uint8 *global_data = module_inst->global_data;
WASMGlobalInstance *global;
WASMTableInstance *table;
global = module_inst->globals;
for (i = 0; i < module_inst->global_count; i++, global++) {
if (global->type == VALUE_TYPE_EXTERNREF) {
externref_idx = *(uint32*)(global_data + global->data_offset);
mark_externref(externref_idx);
}
}
for (i = 0; i < module_inst->table_count; i++) {
table = wasm_get_table_inst(module_inst, i);
if (table->elem_type == VALUE_TYPE_EXTERNREF) {
table_data = (uint32 *)table->base_addr;
for (j = 0; j < table->cur_size; j++) {
externref_idx = table_data[j];
mark_externref(externref_idx);
}
}
}
}
#endif
#if WASM_ENABLE_AOT != 0
static void
aot_mark_all_externrefs(AOTModuleInstance *module_inst)
{
uint32 i = 0, j = 0;
const AOTModule *module = (AOTModule *)(module_inst->aot_module.ptr);
const AOTTable *table = module->tables;
const AOTGlobal *global = module->globals;
const AOTTableInstance *table_inst =
(AOTTableInstance *)module_inst->tables.ptr;
for (i = 0; i < module->global_count; i++, global++) {
if (global->type == VALUE_TYPE_EXTERNREF) {
mark_externref(*(uint32 *)((uint8 *)module_inst->global_data.ptr
+ global->data_offset));
}
}
for (i = 0; i < module->table_count;
i++, table_inst = aot_next_tbl_inst(table_inst)) {
if ((table + i)->elem_type == VALUE_TYPE_EXTERNREF) {
while (j < table_inst->cur_size) {
mark_externref(table_inst->data[j++]);
}
}
}
}
#endif
void
wasm_externref_reclaim(WASMModuleInstanceCommon *module_inst)
{
os_mutex_lock(&externref_lock);
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode)
interp_mark_all_externrefs((WASMModuleInstance*)module_inst);
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT)
aot_mark_all_externrefs((AOTModuleInstance*)module_inst);
#endif
bh_hash_map_traverse(externref_map, reclaim_extobj_callback,
(void*)module_inst);
os_mutex_unlock(&externref_lock);
}
static void
cleanup_extobj_callback(void *key, void *value, void *user_data)
{
ExternRefMapNode *node = (ExternRefMapNode *)value;
WASMModuleInstanceCommon *module_inst = (WASMModuleInstanceCommon *)
user_data;
if (node->module_inst == module_inst) {
bh_hash_map_remove(externref_map, key, NULL, NULL);
wasm_runtime_free(value);
}
}
void
wasm_externref_cleanup(WASMModuleInstanceCommon *module_inst)
{
os_mutex_lock(&externref_lock);
bh_hash_map_traverse(externref_map, cleanup_extobj_callback,
(void*)module_inst);
os_mutex_unlock(&externref_lock);
}
bool
wasm_externref_retain(uint32 externref_idx)
{
ExternRefMapNode *node;
os_mutex_lock(&externref_lock);
if (externref_idx != NULL_REF) {
node = bh_hash_map_find(externref_map,
(void*)(uintptr_t)externref_idx);
if (node) {
node->retained = true;
os_mutex_unlock(&externref_lock);
return true;
}
}
os_mutex_unlock(&externref_lock);
return false;
}
#endif /* end of WASM_ENABLE_REF_TYPES */
#if WASM_ENABLE_DUMP_CALL_STACK != 0
void
wasm_runtime_dump_call_stack(WASMExecEnv *exec_env)
@ -3815,3 +4320,4 @@ wasm_runtime_dump_call_stack(WASMExecEnv *exec_env)
#endif
}
#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */

View File

@ -352,7 +352,6 @@ wasm_runtime_destroy(void);
WASM_RUNTIME_API_EXTERN PackageType
get_package_type(const uint8 *buf, uint32 size);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN WASMModuleCommon *
wasm_runtime_load(const uint8 *buf, uint32 size,
@ -393,6 +392,11 @@ WASM_RUNTIME_API_EXTERN WASMFunctionInstanceCommon *
wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst,
const char *name, const char *signature);
/* Internal API */
WASMType *
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
uint32 module_type);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN WASMExecEnv *
wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,
@ -651,6 +655,34 @@ wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst);
#endif /* end of WASM_ENABLE_LIBC_WASI */
#if WASM_ENABLE_REF_TYPES != 0
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN bool
wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst,
void *extern_obj, uint32 *p_externref_idx);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN bool
wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj);
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN bool
wasm_externref_retain(uint32 externref_idx);
/**
* Reclaim the externref objects/indexes which are not used by
* module instance
*/
void
wasm_externref_reclaim(WASMModuleInstanceCommon *module_inst);
/**
* Cleanup the externref objects/indexes of the module instance
*/
void
wasm_externref_cleanup(WASMModuleInstanceCommon *module_inst);
#endif /* end of WASM_ENABLE_REF_TYPES */
/* Get module of the current exec_env */
WASMModuleCommon*
wasm_exec_env_get_module(WASMExecEnv *exec_env);
@ -702,6 +734,16 @@ wasm_runtime_dump_module_inst_mem_consumption(const WASMModuleInstanceCommon
void
wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env);
#if WASM_ENABLE_REF_TYPES != 0
void
wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function);
void
wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
bool ret, uint32 *argv);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -125,8 +125,18 @@ aot_create_table_init_data_list(const WASMModule *module)
data_list[i]->offset = module->table_segments[i].base_offset;
data_list[i]->func_index_count = module->table_segments[i].function_count;
memcpy(data_list[i]->func_indexes, module->table_segments[i].func_indexes,
sizeof(uint32) * module->table_segments[i].function_count);
data_list[i]->mode = module->table_segments[i].mode;
data_list[i]->elem_type = module->table_segments[i].elem_type;
/* runtime control it */
data_list[i]->is_dropped = false;
data_list[i]->table_index = module->table_segments[i].table_index;
bh_memcpy_s(&data_list[i]->offset, sizeof(AOTInitExpr),
&module->table_segments[i].base_offset, sizeof(AOTInitExpr));
data_list[i]->func_index_count = module->table_segments[i].function_count;
bh_memcpy_s(data_list[i]->func_indexes,
sizeof(uint32) * module->table_segments[i].function_count,
module->table_segments[i].func_indexes,
sizeof(uint32) * module->table_segments[i].function_count);
}
return data_list;
@ -424,8 +434,6 @@ aot_create_comp_data(WASMModule *module)
aot_create_mem_init_data_list(module)))
goto fail;
/* TODO: create import tables */
/* Create tables */
comp_data->table_count = module->import_table_count + module->table_count;
@ -447,6 +455,8 @@ aot_create_comp_data(WASMModule *module)
module->import_tables[i].u.table.init_size;
comp_data->tables[i].table_max_size =
module->import_tables[i].u.table.max_size;
comp_data->tables[i].possible_grow =
module->import_tables[i].u.table.possible_grow;
}
else {
j = i - module->import_table_count;
@ -454,6 +464,7 @@ aot_create_comp_data(WASMModule *module)
comp_data->tables[i].table_flags = module->tables[i].flags;
comp_data->tables[i].table_init_size = module->tables[i].init_size;
comp_data->tables[i].table_max_size = module->tables[i].max_size;
comp_data->tables[i].possible_grow = module->tables[i].possible_grow;
}
}
}

View File

@ -71,6 +71,7 @@ typedef struct AOTImportTable {
uint32 table_flags;
uint32 table_init_size;
uint32 table_max_size;
bool possible_grow;
} AOTImportTable;
/**
@ -81,12 +82,19 @@ typedef struct AOTTable {
uint32 table_flags;
uint32 table_init_size;
uint32 table_max_size;
bool possible_grow;
} AOTTable;
/**
* A segment of table init data
*/
typedef struct AOTTableInitData {
/* 0 to 7 */
uint32 mode;
/* funcref or externref, elemkind will be considered as funcref */
uint32 elem_type;
bool is_dropped;
/* optional, only for active */
uint32 table_index;
/* Start address of init data */
AOTInitExpr offset;
@ -245,6 +253,18 @@ aot_set_last_error_v(const char *format, ...);
} while (0)
#endif
static inline uint32
aot_get_tbl_data_slots(const AOTTable *tbl)
{
return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size;
}
static inline uint32
aot_get_imp_tbl_data_slots(const AOTImportTable *tbl)
{
return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size;
}
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -14,6 +14,7 @@
#include "aot_emit_control.h"
#include "aot_emit_function.h"
#include "aot_emit_parametric.h"
#include "aot_emit_table.h"
#include "simd/simd_access_lanes.h"
#include "simd/simd_bitmask_extracts.h"
#include "simd/simd_bit_shifts.h"
@ -176,7 +177,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|| value_type == VALUE_TYPE_F32
|| value_type == VALUE_TYPE_F64
|| value_type == VALUE_TYPE_V128
|| value_type == VALUE_TYPE_VOID) {
|| value_type == VALUE_TYPE_VOID
|| value_type == VALUE_TYPE_FUNCREF
|| value_type == VALUE_TYPE_EXTERNREF) {
param_count = 0;
param_types = NULL;
if (value_type == VALUE_TYPE_VOID) {
@ -258,11 +261,27 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
break;
case WASM_OP_CALL_INDIRECT:
{
uint32 tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, type_idx);
frame_ip++; /* skip 0x00 */
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx))
#if WASM_ENABLE_REF_TYPES != 0
if (comp_ctx->enable_ref_types) {
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
}
else
#endif
{
frame_ip++;
tbl_idx = 0;
}
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
tbl_idx))
return false;
break;
}
#if WASM_ENABLE_TAIL_CALL != 0
case WASM_OP_RETURN_CALL:
@ -278,17 +297,33 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
break;
case WASM_OP_RETURN_CALL_INDIRECT:
{
uint32 tbl_idx;
if (!comp_ctx->enable_tail_call) {
aot_set_last_error("unsupported opcode");
return false;
}
read_leb_uint32(frame_ip, frame_ip_end, type_idx);
frame_ip++; /* skip 0x00 */
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx))
#if WASM_ENABLE_REF_TYPES != 0
if (comp_ctx->enable_ref_types) {
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
}
else
#endif
{
frame_ip++;
tbl_idx = 0;
}
if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
tbl_idx))
return false;
if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip))
return false;
break;
}
#endif /* end of WASM_ENABLE_TAIL_CALL */
case WASM_OP_DROP:
@ -311,6 +346,93 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
return false;
break;
#if WASM_ENABLE_REF_TYPES != 0
case WASM_OP_SELECT_T:
{
uint32 vec_len;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, vec_len);
bh_assert(vec_len == 1);
vec_len = vec_len;
type_idx = *frame_ip++;
if (!aot_compile_op_select(comp_ctx, func_ctx,
(type_idx != VALUE_TYPE_I64)
&& (type_idx != VALUE_TYPE_F64)))
return false;
break;
}
case WASM_OP_TABLE_GET:
{
uint32 tbl_idx;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_get(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
case WASM_OP_TABLE_SET:
{
uint32 tbl_idx;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_set(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
case WASM_OP_REF_NULL:
{
uint32 type;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, type);
if (!aot_compile_op_ref_null(comp_ctx, func_ctx))
return false;
(void)type;
break;
}
case WASM_OP_REF_IS_NULL:
{
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
if (!aot_compile_op_ref_is_null(comp_ctx, func_ctx))
return false;
break;
}
case WASM_OP_REF_FUNC:
{
uint32 func_idx;
if (!comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
read_leb_uint32(frame_ip, frame_ip_end, func_idx);
if (!aot_compile_op_ref_func(comp_ctx, func_ctx, func_idx))
return false;
break;
}
#endif
case WASM_OP_GET_LOCAL:
read_leb_uint32(frame_ip, frame_ip_end, local_idx);
if (!aot_compile_op_get_local(comp_ctx, func_ctx, local_idx))
@ -828,6 +950,15 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
read_leb_uint32(frame_ip, frame_ip_end, opcode1);
opcode = (uint32)opcode1;
//TODO: --enable-bulk-memory ?
#if WASM_ENABLE_REF_TYPES != 0
if (WASM_OP_TABLE_INIT <= opcode && opcode <= WASM_OP_TABLE_FILL
&& !comp_ctx->enable_ref_types) {
goto unsupport_ref_types;
}
#endif
switch (opcode) {
case WASM_OP_I32_TRUNC_SAT_S_F32:
case WASM_OP_I32_TRUNC_SAT_U_F32:
@ -886,11 +1017,74 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
break;
}
#endif /* WASM_ENABLE_BULK_MEMORY */
default:
#if WASM_ENABLE_REF_TYPES != 0
case WASM_OP_TABLE_INIT:
{
uint32 tbl_idx, tbl_seg_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_seg_idx);
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_init(comp_ctx, func_ctx, tbl_idx,
tbl_seg_idx))
return false;
break;
}
case WASM_OP_ELEM_DROP:
{
uint32 tbl_seg_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_seg_idx);
if (!aot_compile_op_elem_drop(comp_ctx, func_ctx, tbl_seg_idx))
return false;
break;
}
case WASM_OP_TABLE_COPY:
{
uint32 src_tbl_idx, dst_tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx);
read_leb_uint32(frame_ip, frame_ip_end, src_tbl_idx);
if (!aot_compile_op_table_copy(comp_ctx, func_ctx, src_tbl_idx,
dst_tbl_idx))
return false;
break;
}
case WASM_OP_TABLE_GROW:
{
uint32 tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_grow(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
case WASM_OP_TABLE_SIZE:
{
uint32 tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_size(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
case WASM_OP_TABLE_FILL:
{
uint32 tbl_idx;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
if (!aot_compile_op_table_fill(comp_ctx, func_ctx, tbl_idx))
return false;
break;
}
#endif /* WASM_ENABLE_REF_TYPES */
default:
aot_set_last_error("unsupported opcode");
return false;
}
break;
}
#if WASM_ENABLE_SHARED_MEMORY != 0
case WASM_OP_ATOMIC_PREFIX:
{
@ -1030,7 +1224,8 @@ build_atomic_rmw:
break;
default:
break;
aot_set_last_error("unsupported opcode");
return false;
}
break;
}
@ -1040,9 +1235,7 @@ build_atomic_rmw:
case WASM_OP_SIMD_PREFIX:
{
if (!comp_ctx->enable_simd) {
aot_set_last_error("SIMD instruction was found, "
"try adding --enable-simd option?");
return false;
goto unsupport_simd;
}
opcode = *frame_ip++;
@ -1795,7 +1988,8 @@ build_atomic_rmw:
}
default:
break;
aot_set_last_error("unsupported opcode");
return false;
}
break;
}
@ -1803,29 +1997,43 @@ build_atomic_rmw:
default:
aot_set_last_error("unsupported opcode");
break;
return false;
}
}
/* Move func_return block to the bottom */
if (func_ctx->func_return_block) {
LLVMBasicBlockRef last_block =
LLVMGetLastBasicBlock(func_ctx->func);
if (last_block != func_ctx->func_return_block)
LLVMMoveBasicBlockAfter(func_ctx->func_return_block,
last_block);
LLVMBasicBlockRef last_block =
LLVMGetLastBasicBlock(func_ctx->func);
if (last_block != func_ctx->func_return_block)
LLVMMoveBasicBlockAfter(func_ctx->func_return_block,
last_block);
}
/* Move got_exception block to the bottom */
if (func_ctx->got_exception_block) {
LLVMBasicBlockRef last_block =
LLVMGetLastBasicBlock(func_ctx->func);
if (last_block != func_ctx->got_exception_block)
LLVMMoveBasicBlockAfter(func_ctx->got_exception_block,
last_block);
LLVMBasicBlockRef last_block =
LLVMGetLastBasicBlock(func_ctx->func);
if (last_block != func_ctx->got_exception_block)
LLVMMoveBasicBlockAfter(func_ctx->got_exception_block,
last_block);
}
return true;
#if WASM_ENABLE_SIMD != 0
unsupport_simd:
aot_set_last_error("SIMD instruction was found, "
"try adding --enable-simd option?");
return false;
#endif
#if WASM_ENABLE_REF_TYPES != 0
unsupport_ref_types:
aot_set_last_error("reference type instruction was found, "
"try adding --enable-ref-types option?");
return false;
#endif
fail:
return false;
}

View File

@ -102,6 +102,34 @@ typedef enum FloatArithmetic {
FLOAT_MAX
} FloatArithmetic;
static inline bool
check_type_compatible(uint8 src_type, uint8 dst_type)
{
if (src_type == dst_type) {
return true;
}
/* ext i1 to i32 */
if (src_type == VALUE_TYPE_I1 && dst_type == VALUE_TYPE_I32) {
return true;
}
/* i32 <==> func.ref, i32 <==> extern.ref */
if (src_type == VALUE_TYPE_I32
&& (dst_type == VALUE_TYPE_EXTERNREF
|| dst_type == VALUE_TYPE_FUNCREF)) {
return true;
}
if (dst_type == VALUE_TYPE_I32
&& (src_type == VALUE_TYPE_FUNCREF
|| src_type == VALUE_TYPE_EXTERNREF)) {
return true;
}
return false;
}
#define CHECK_STACK() do { \
if (!func_ctx->block_stack.block_list_end) { \
aot_set_last_error("WASM block stack underflow."); \
@ -119,11 +147,8 @@ typedef enum FloatArithmetic {
CHECK_STACK(); \
aot_value = aot_value_stack_pop \
(&func_ctx->block_stack.block_list_end->value_stack); \
if ((value_type != VALUE_TYPE_I32 \
&& aot_value->type != value_type) \
|| (value_type == VALUE_TYPE_I32 \
&& (aot_value->type != VALUE_TYPE_I32 \
&& aot_value->type != VALUE_TYPE_I1))) { \
if (!check_type_compatible(aot_value->type, \
value_type)) { \
aot_set_last_error("invalid WASM stack data type."); \
wasm_runtime_free(aot_value); \
goto fail; \
@ -131,12 +156,23 @@ typedef enum FloatArithmetic {
if (aot_value->type == value_type) \
llvm_value = aot_value->value; \
else { \
bh_assert(aot_value->type == VALUE_TYPE_I1); \
if (!(llvm_value = LLVMBuildZExt(comp_ctx->builder, \
aot_value->value, I32_TYPE, "i1toi32"))) { \
aot_set_last_error("invalid WASM stack data type.");\
wasm_runtime_free(aot_value); \
goto fail; \
if (aot_value->type == VALUE_TYPE_I1) { \
if (!(llvm_value = LLVMBuildZExt(comp_ctx->builder, \
aot_value->value, I32_TYPE, "i1toi32"))) { \
aot_set_last_error("invalid WASM stack " \
"data type."); \
wasm_runtime_free(aot_value); \
goto fail; \
} \
} \
else { \
bh_assert(aot_value->type == VALUE_TYPE_I32 \
|| aot_value->type == VALUE_TYPE_FUNCREF \
|| aot_value->type == VALUE_TYPE_EXTERNREF); \
bh_assert(value_type == VALUE_TYPE_I32 \
|| value_type == VALUE_TYPE_FUNCREF \
|| value_type == VALUE_TYPE_EXTERNREF); \
llvm_value = aot_value->value; \
} \
} \
wasm_runtime_free(aot_value); \
@ -147,6 +183,8 @@ typedef enum FloatArithmetic {
#define POP_F32(v) POP(v, VALUE_TYPE_F32)
#define POP_F64(v) POP(v, VALUE_TYPE_F64)
#define POP_V128(v) POP(v, VALUE_TYPE_V128)
#define POP_FUNCREF(v) POP(v, VALUE_TYPE_FUNCREF)
#define POP_EXTERNREF(v) POP(v, VALUE_TYPE_EXTERNREF)
#define POP_COND(llvm_value) do { \
AOTValue *aot_value; \
@ -198,6 +236,8 @@ typedef enum FloatArithmetic {
#define PUSH_F64(v) PUSH(v, VALUE_TYPE_F64)
#define PUSH_V128(v) PUSH(v, VALUE_TYPE_V128)
#define PUSH_COND(v) PUSH(v, VALUE_TYPE_I1)
#define PUSH_FUNCREF(v) PUSH(v, VALUE_TYPE_FUNCREF)
#define PUSH_EXTERNREF(v) PUSH(v, VALUE_TYPE_EXTERNREF)
#define TO_LLVM_TYPE(wasm_type) \
wasm_type_to_llvm_type(&comp_ctx->basic_types, wasm_type)
@ -217,6 +257,8 @@ typedef enum FloatArithmetic {
#define INT64_PTR_TYPE comp_ctx->basic_types.int64_ptr_type
#define F32_PTR_TYPE comp_ctx->basic_types.float32_ptr_type
#define F64_PTR_TYPE comp_ctx->basic_types.float64_ptr_type
#define FUNC_REF_TYPE comp_ctx->basic_types.funcref_type
#define EXTERN_REF_TYPE comp_ctx->basic_types.externref_type
#define I32_CONST(v) LLVMConstInt(I32_TYPE, v, true)
#define I64_CONST(v) LLVMConstInt(I64_TYPE, v, true)
@ -263,6 +305,8 @@ typedef enum FloatArithmetic {
#define V128_f32x4_ZERO (comp_ctx->llvm_consts.f32x4_vec_zero)
#define V128_f64x2_ZERO (comp_ctx->llvm_consts.f64x2_vec_zero)
#define REF_NULL (comp_ctx->llvm_consts.i32_neg_one)
#define TO_V128_i8x16(v) LLVMBuildBitCast(comp_ctx->builder, v, \
V128_i8x16_TYPE, "i8x16_val")
#define TO_V128_i16x8(v) LLVMBuildBitCast(comp_ctx->builder, v, \
@ -283,6 +327,36 @@ typedef enum FloatArithmetic {
} \
} while (0)
#define GET_AOT_FUNCTION(name, argc) do { \
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
argc, false))) { \
aot_set_last_error("llvm add function type failed."); \
return false; \
} \
if (comp_ctx->is_jit_mode) { \
/* JIT mode, call the function directly */ \
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
aot_set_last_error("llvm add pointer type failed."); \
return false; \
} \
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
aot_set_last_error("create LLVM value failed."); \
return false; \
} \
} \
else { \
char *func_name = #name; \
/* AOT mode, delcare the function */ \
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
&& !(func = LLVMAddFunction(comp_ctx->module, \
func_name, func_type))) { \
aot_set_last_error("llvm add function failed."); \
return false; \
} \
} \
} while (0)
bool
aot_compile_wasm(AOTCompContext *comp_ctx);

View File

@ -183,9 +183,13 @@ get_mem_info_size(AOTCompData *comp_data)
static uint32
get_table_init_data_size(AOTTableInitData *table_init_data)
{
/* table_index + init expr type (4 bytes) + init expr value (8 bytes)
+ func index count (4 bytes) + func indexes */
return (uint32)(sizeof(uint32) + sizeof(uint32)
/*
* mode (4 bytes), elem_type (4 bytes), do not need is_dropped field
*
* table_index(4 bytes) + init expr type (4 bytes) + init expr value (8 bytes)
* + func index count (4 bytes) + func indexes
*/
return (uint32)(sizeof(uint32) * 2 + sizeof(uint32) + sizeof(uint32)
+ sizeof(uint64) + sizeof(uint32)
+ sizeof(uint32) * table_init_data->func_index_count);
}
@ -194,9 +198,24 @@ static uint32
get_table_init_data_list_size(AOTTableInitData **table_init_data_list,
uint32 table_init_data_count)
{
/*
* ------------------------------
* | table_init_data_count
* ------------------------------
* | | U32 mode
* | AOTTableInitData[N] | U32 elem_type
* | | U32 table_index
* | | U32 offset.init_expr_type
* | | U64 offset.u.i64
* | | U32 func_index_count
* | | U32[func_index_count]
* ------------------------------
*/
AOTTableInitData **table_init_data = table_init_data_list;
uint32 size = 0, i;
size = (uint32)sizeof(uint32);
for (i = 0; i < table_init_data_count; i++, table_init_data++) {
size = align_uint(size, 4);
size += get_table_init_data_size(*table_init_data);
@ -207,27 +226,66 @@ get_table_init_data_list_size(AOTTableInitData **table_init_data_list,
static uint32
get_import_table_size(AOTCompData *comp_data)
{
/* currently we only emit import_table_count = 0 */
return sizeof(uint32);
/*
* ------------------------------
* | import_table_count
* ------------------------------
* | | U32 table_init_size
* | | ----------------------
* | AOTImpotTable[N] | U32 table_init_size
* | | ----------------------
* | | U32 possible_grow (convenient than U8)
* ------------------------------
*/
return (uint32)(sizeof(uint32)
+ comp_data->import_table_count
* (sizeof(uint32) * 3));
}
static uint32
get_table_size(AOTCompData *comp_data)
{
/* table_count + table_count * (elem_type + table_flags
* + init_size + max_size) */
/*
* ------------------------------
* | table_count
* ------------------------------
* | | U32 elem_type
* | AOTTable[N] | U32 table_flags
* | | U32 table_init_size
* | | U32 table_max_size
* | | U32 possible_grow (convenient than U8)
* ------------------------------
*/
return (uint32)(sizeof(uint32)
+ comp_data->table_count * sizeof(uint32) * 4);
+ comp_data->table_count
* (sizeof(uint32) * 5));
}
static uint32
get_table_info_size(AOTCompData *comp_data)
{
/* import_table size + table_size
+ init data count + init data list */
return get_import_table_size(comp_data)
+ get_table_size(comp_data)
+ (uint32)sizeof(uint32)
/*
* ------------------------------
* | import_table_count
* ------------------------------
* |
* | AOTImportTable[import_table_count]
* |
* ------------------------------
* | table_count
* ------------------------------
* |
* | AOTTable[table_count]
* |
* ------------------------------
* | table_init_data_count
* ------------------------------
* |
* | AOTTableInitData*[table_init_data_count]
* |
* ------------------------------
*/
return get_import_table_size(comp_data) + get_table_size(comp_data)
+ get_table_init_data_list_size(comp_data->table_init_data_list,
comp_data->table_init_data_count);
}
@ -1014,10 +1072,18 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
*p_offset = offset = align_uint(offset, 4);
/* Emit import table count, only emit 0 currently.
TODO: emit the actual import table count and
the full import table info. */
EMIT_U32(0);
/* Emit import table count */
EMIT_U32(comp_data->import_table_count);
/* Emit table items */
for (i = 0; i < comp_data->import_table_count; i++) {
/* TODO:
* EMIT_STR(comp_data->import_tables[i].module_name );
* EMIT_STR(comp_data->import_tables[i].table_name);
*/
EMIT_U32(comp_data->import_tables[i].table_init_size);
EMIT_U32(comp_data->import_tables[i].table_max_size);
EMIT_U32(comp_data->import_tables[i].possible_grow & 0x000000FF);
}
/* Emit table count */
EMIT_U32(comp_data->table_count);
@ -1027,6 +1093,7 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
EMIT_U32(comp_data->tables[i].table_flags);
EMIT_U32(comp_data->tables[i].table_init_size);
EMIT_U32(comp_data->tables[i].table_max_size);
EMIT_U32(comp_data->tables[i].possible_grow & 0x000000FF);
}
/* Emit table init data count */
@ -1034,6 +1101,8 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
/* Emit table init data items */
for (i = 0; i < comp_data->table_init_data_count; i++) {
offset = align_uint(offset, 4);
EMIT_U32(init_datas[i]->mode);
EMIT_U32(init_datas[i]->elem_type);
EMIT_U32(init_datas[i]->table_index);
EMIT_U32(init_datas[i]->offset.init_expr_type);
EMIT_U64(init_datas[i]->offset.u.i64);

View File

@ -616,8 +616,10 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Handle block result values */
CREATE_RESULT_VALUE_PHIS(block);
for (i = 0; i < block->result_count; i++) {
value = NULL;
result_index = block->result_count - 1 - i;
POP(value, block->result_types[result_index]);
bh_assert(value);
ADD_TO_RESULT_PHIS(block, value, result_index);
}

View File

@ -6,38 +6,9 @@
#include "aot_emit_function.h"
#include "aot_emit_exception.h"
#include "aot_emit_control.h"
#include "aot_emit_table.h"
#include "../aot/aot_runtime.h"
#define GET_AOT_FUNCTION(name, argc) do { \
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
argc, false))) { \
aot_set_last_error("llvm add function type failed."); \
return false; \
} \
if (comp_ctx->is_jit_mode) { \
/* JIT mode, call the function directly */ \
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
aot_set_last_error("llvm add pointer type failed."); \
return false; \
} \
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
aot_set_last_error("create LLVM value failed."); \
return false; \
} \
} \
else { \
char *func_name = #name; \
/* AOT mode, delcare the function */ \
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
&& !(func = LLVMAddFunction(comp_ctx->module, \
func_name, func_type))) { \
aot_set_last_error("llvm add function failed."); \
return false; \
} \
} \
} while (0)
#define ADD_BASIC_BLOCK(block, name) do { \
if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \
func_ctx->func, \
@ -640,8 +611,8 @@ fail:
static bool
call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
AOTFuncType *aot_func_type,
LLVMValueRef func_type_idx, LLVMValueRef table_elem_idx,
AOTFuncType *aot_func_type, LLVMValueRef func_type_idx,
LLVMValueRef table_idx, LLVMValueRef table_elem_idx,
LLVMTypeRef *param_types, LLVMValueRef *param_values,
uint32 param_count, uint32 param_cell_num,
uint32 result_count, uint8 *wasm_ret_types,
@ -656,10 +627,11 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* prepare function type of aot_call_indirect */
func_param_types[0] = comp_ctx->exec_env_type; /* exec_env */
func_param_types[1] = I32_TYPE; /* table_elem_idx */
func_param_types[2] = I32_TYPE; /* argc */
func_param_types[3] = INT32_PTR_TYPE; /* argv */
if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 4, false))) {
func_param_types[1] = I32_TYPE; /* table_idx */
func_param_types[2] = I32_TYPE; /* table_elem_idx */
func_param_types[3] = I32_TYPE; /* argc */
func_param_types[4] = INT32_PTR_TYPE; /* argv */
if (!(func_type = LLVMFunctionType(INT8_TYPE, func_param_types, 5, false))) {
aot_set_last_error("llvm add function type failed.");
return false;
}
@ -722,18 +694,19 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
func_param_values[0] = func_ctx->exec_env;
func_param_values[1] = table_elem_idx;
func_param_values[2] = I32_CONST(param_cell_num);
func_param_values[3] = func_ctx->argv_buf;
func_param_values[1] = table_idx;
func_param_values[2] = table_elem_idx;
func_param_values[3] = I32_CONST(param_cell_num);
func_param_values[4] = func_ctx->argv_buf;
if (!func_param_values[2]) {
if (!func_param_values[3]) {
aot_set_last_error("llvm create const failed.");
return false;
}
/* call aot_call_indirect() function */
if (!(res = LLVMBuildCall(comp_ctx->builder, func,
func_param_values, 4, "res"))) {
func_param_values, 5, "res"))) {
aot_set_last_error("llvm build call failed.");
return false;
}
@ -771,10 +744,10 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
bool
aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_idx)
uint32 type_idx, uint32 tbl_idx)
{
AOTFuncType *func_type;
LLVMValueRef elem_idx, table_elem, func_idx;
LLVMValueRef tbl_idx_value, elem_idx, table_elem, func_idx;
LLVMValueRef ftype_idx_ptr, ftype_idx, ftype_idx_const;
LLVMValueRef cmp_elem_idx, cmp_func_idx, cmp_ftype_idx;
LLVMValueRef func, func_ptr, table_size_const;
@ -787,8 +760,9 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMBasicBlockRef check_elem_idx_succ, check_ftype_idx_succ;
LLVMBasicBlockRef check_func_idx_succ, block_return, block_curr;
LLVMBasicBlockRef block_call_import, block_call_non_import;
LLVMValueRef offset;
uint32 total_param_count, func_param_count, func_result_count;
uint32 table_init_size = 0, ext_cell_num, param_cell_num, i, j;
uint32 ext_cell_num, param_cell_num, i, j;
uint8 wasm_ret_type, *wasm_ret_types;
uint64 total_size;
char buf[32];
@ -818,20 +792,31 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
POP_I32(elem_idx);
if (comp_ctx->comp_data->import_table_count > 0) {
table_init_size = comp_ctx->comp_data->import_tables[0]
.table_init_size;
}
else if (comp_ctx->comp_data->table_count > 0) {
table_init_size = comp_ctx->comp_data->tables[0]
.table_init_size;
}
else {
aot_set_last_error("table index out of range");
/* get the cur size of the table instance */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, cur_size)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_size_const =
LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset, 1,
"cur_size_i8p"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(table_size_const =
LLVMBuildBitCast(comp_ctx->builder, table_size_const,
INT32_PTR_TYPE, "cur_siuze_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(table_size_const = LLVMBuildLoad(comp_ctx->builder, table_size_const, "cur_size"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
table_size_const = I32_CONST(table_init_size);
CHECK_LLVM_CONST(table_size_const);
/* Check if (uint32)elem index >= table size */
if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE,
@ -857,14 +842,32 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
true, cmp_elem_idx, check_elem_idx_succ)))
goto fail;
/* Load function index */
if (!(table_elem = LLVMBuildInBoundsGEP(comp_ctx->builder,
func_ctx->table_base,
&elem_idx, 1, "table_elem"))) {
/* load data as i32* */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, data)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
&offset, 1, "table_elem_i8p"))) {
aot_set_last_error("llvm build add failed.");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function index */
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx,
1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildNUWAdd");
goto fail;
}
if (!(func_idx = LLVMBuildLoad(comp_ctx->builder,
table_elem, "func_idx"))) {
aot_set_last_error("llvm build load failed.");
@ -1118,8 +1121,15 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
param_cell_num = func_type->param_cell_num;
wasm_ret_types = func_type->types + func_type->param_count;
tbl_idx_value = I32_CONST(tbl_idx);
if (!tbl_idx_value) {
aot_set_last_error("llvm create const failed.");
goto fail;
}
if (!call_aot_call_indirect_func(comp_ctx, func_ctx,
func_type, ftype_idx, elem_idx,
func_type, ftype_idx,
tbl_idx_value, elem_idx,
param_types + 1, param_values + 1,
func_param_count, param_cell_num,
func_result_count, wasm_ret_types,
@ -1240,3 +1250,56 @@ fail:
return ret;
}
bool
aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
PUSH_I32(REF_NULL);
return true;
fail:
return false;
}
bool
aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef lhs, res;
POP_I32(lhs);
if (!(res = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, lhs, REF_NULL,
"cmp_w_null"))) {
HANDLE_FAILURE("LLVMBuildICmp");
goto fail;
}
if (!(res = LLVMBuildZExt(comp_ctx->builder, res, I32_TYPE, "r_i"))) {
HANDLE_FAILURE("LLVMBuildZExt");
goto fail;
}
PUSH_I32(res);
return true;
fail:
return false;
}
bool
aot_compile_op_ref_func(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 func_idx)
{
LLVMValueRef ref_idx;
if (!(ref_idx = I32_CONST(func_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
PUSH_I32(ref_idx);
return true;
fail:
return false;
}

View File

@ -17,9 +17,21 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 func_idx, bool tail_call);
bool
aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 type_idx);
aot_compile_op_call_indirect(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 type_idx,
uint32 tbl_idx);
bool
aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_ref_func(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 func_idx);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -657,7 +657,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
POP_I32(delta);
/* Function type of wasm_runtime_enlarge_memory() */
/* Function type of aot_enlarge_memory() */
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
ret_type = INT8_TYPE;
@ -673,14 +673,14 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
aot_set_last_error("llvm add pointer type failed.");
return false;
}
if (!(value = I64_CONST((uint64)(uintptr_t)wasm_runtime_enlarge_memory))
if (!(value = I64_CONST((uint64)(uintptr_t)aot_enlarge_memory))
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) {
aot_set_last_error("create LLVM value failed.");
return false;
}
}
else {
char *func_name = "wasm_runtime_enlarge_memory";
char *func_name = "aot_enlarge_memory";
/* AOT mode, delcare the function */
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name))
&& !(func = LLVMAddFunction(comp_ctx->module,
@ -690,7 +690,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
}
}
/* Call function wasm_runtime_enlarge_memory() */
/* Call function aot_enlarge_memory() */
param_values[0] = func_ctx->aot_inst;
param_values[1] = delta;
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
@ -715,35 +715,6 @@ fail:
return false;
}
#define GET_AOT_FUNCTION(name, argc) do { \
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
argc, false))) { \
aot_set_last_error("llvm add function type failed."); \
return false; \
} \
if (comp_ctx->is_jit_mode) { \
/* JIT mode, call the function directly */ \
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
aot_set_last_error("llvm add pointer type failed."); \
return false; \
} \
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
aot_set_last_error("create LLVM value failed."); \
return false; \
} \
} \
else { \
char *func_name = #name; \
/* AOT mode, delcare the function */ \
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
&& !(func = LLVMAddFunction(comp_ctx->module, \
func_name, func_type))) { \
aot_set_last_error("llvm add function failed."); \
return false; \
} \
} \
} while (0)
#if WASM_ENABLE_BULK_MEMORY != 0

View File

@ -45,11 +45,18 @@ pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
wasm_runtime_free(aot_value);
if ((is_32
&& (type != VALUE_TYPE_I32 && type != VALUE_TYPE_F32
&& type != VALUE_TYPE_V128))
|| (!is_32
&& (type != VALUE_TYPE_I64 && type != VALUE_TYPE_F64))) {
/* is_32: i32, f32, ref.func, ref.extern, v128 */
if (is_32
&& !(type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
|| type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
|| type == VALUE_TYPE_V128)) {
aot_set_last_error("invalid WASM stack data type.");
return false;
}
/* !is_32: i64, f64 */
if (!is_32
&& !(type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)) {
aot_set_last_error("invalid WASM stack data type.");
return false;
}

View File

@ -0,0 +1,487 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "aot_emit_table.h"
#include "aot_emit_exception.h"
#include "../aot/aot_runtime.h"
uint64
get_tbl_inst_offset(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
uint64 offset = 0, i = 0;
AOTImportTable *imp_tbls = comp_ctx->comp_data->import_tables;
AOTTable *tbls = comp_ctx->comp_data->tables;
/* from the head of AOTModuleInstance */
offset =
offsetof(AOTModuleInstance, global_table_data.bytes)
+ (uint64)comp_ctx->comp_data->memory_count * sizeof(AOTMemoryInstance)
+ comp_ctx->comp_data->global_data_size;
while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) {
offset += offsetof(AOTTableInstance, data);
offset += sizeof(uint32) * aot_get_imp_tbl_data_slots(imp_tbls + i);
++i;
}
if (i == tbl_idx) {
return offset;
}
tbl_idx -= comp_ctx->comp_data->import_table_count;
i -= comp_ctx->comp_data->import_table_count;
while (i < tbl_idx && i < comp_ctx->comp_data->table_count) {
offset += offsetof(AOTTableInstance, data);
offset += sizeof(uint32) * aot_get_tbl_data_slots(tbls + i);
++i;
}
return offset;
}
#if WASM_ENABLE_REF_TYPES != 0
LLVMValueRef
aot_compile_get_tbl_inst(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef offset, tbl_inst;
if (!(offset =
I64_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(tbl_inst = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
&offset, 1, "tbl_inst"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
return tbl_inst;
fail:
return NULL;
}
bool
aot_compile_op_elem_drop(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_seg_idx)
{
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
LLVMValueRef param_values[2], ret_value, func, value;
/* void aot_drop_table_seg(AOTModuleInstance *, uint32 ) */
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
ret_type = VOID_TYPE;
GET_AOT_FUNCTION(aot_drop_table_seg, 2);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_seg_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* "" means return void */
if (!(ret_value =
LLVMBuildCall(comp_ctx->builder, func, param_values, 2, ""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
static bool
aot_check_table_access(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx,
LLVMValueRef elem_idx)
{
LLVMValueRef offset, tbl_sz, cmp_elem_idx;
LLVMBasicBlockRef check_elem_idx_succ;
/* get the cur size of the table instance */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, cur_size)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(tbl_sz = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset,
1, "cur_size_i8p"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
"cur_siuze_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(tbl_sz = LLVMBuildLoad(comp_ctx->builder, tbl_sz, "cur_size"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
/* Check if (uint32)elem index >= table size */
if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx,
tbl_sz, "cmp_elem_idx"))) {
aot_set_last_error("llvm build icmp failed.");
goto fail;
}
/* Throw exception if elem index >= table size */
if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext(
comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) {
aot_set_last_error("llvm add basic block failed.");
goto fail;
}
LLVMMoveBasicBlockAfter(check_elem_idx_succ,
LLVMGetInsertBlock(comp_ctx->builder));
if (!(aot_emit_exception(comp_ctx, func_ctx,
EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, true,
cmp_elem_idx, check_elem_idx_succ)))
goto fail;
return true;
fail:
return false;
}
bool
aot_compile_op_table_get(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef elem_idx, offset, table_elem, func_idx;
POP_I32(elem_idx);
if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
goto fail;
}
/* load data as i32* */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, data)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
&offset, 1, "table_elem_i8p"))) {
aot_set_last_error("llvm build add failed.");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function index */
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx,
1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildNUWAdd");
goto fail;
}
if (!(func_idx =
LLVMBuildLoad(comp_ctx->builder, table_elem, "func_idx"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
PUSH_I32(func_idx);
return true;
fail:
return false;
}
bool
aot_compile_op_table_set(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef val, elem_idx, offset, table_elem;
POP_I32(val);
POP_I32(elem_idx);
if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
goto fail;
}
/* load data as i32* */
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, data)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst,
&offset, 1, "table_elem_i8p"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
INT32_PTR_TYPE, "table_elem_i32p"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
/* Load function index */
if (!(table_elem = LLVMBuildGEP(comp_ctx->builder, table_elem, &elem_idx,
1, "table_elem"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(LLVMBuildStore(comp_ctx->builder, val, table_elem))) {
HANDLE_FAILURE("LLVMBuildStore");
goto fail;
}
return true;
fail:
return false;
}
bool
aot_compile_op_table_init(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx,
uint32 tbl_seg_idx)
{
LLVMValueRef func, param_values[6], value;
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[4] = I32_TYPE;
param_types[5] = I32_TYPE;
ret_type = VOID_TYPE;
GET_AOT_FUNCTION(aot_table_init, 6);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(param_values[2] = I32_CONST(tbl_seg_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[3]);
/* s */
POP_I32(param_values[4]);
/* d */
POP_I32(param_values[5]);
/* "" means return void */
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 6, ""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
bool
aot_compile_op_table_copy(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 src_tbl_idx,
uint32 dst_tbl_idx)
{
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
LLVMValueRef func, param_values[6], value;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[4] = I32_TYPE;
param_types[5] = I32_TYPE;
ret_type = VOID_TYPE;
GET_AOT_FUNCTION(aot_table_copy, 6);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(src_tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(param_values[2] = I32_CONST(dst_tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[3]);
/* s */
POP_I32(param_values[4]);
/* d */
POP_I32(param_values[5]);
/* "" means return void */
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 6, ""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
bool
aot_compile_op_table_size(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMValueRef offset, tbl_sz;
if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
+ offsetof(AOTTableInstance, cur_size)))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
if (!(tbl_sz = LLVMBuildGEP(comp_ctx->builder, func_ctx->aot_inst, &offset,
1, "tbl_sz_ptr_i8"))) {
HANDLE_FAILURE("LLVMBuildGEP");
goto fail;
}
if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
"tbl_sz_ptr"))) {
HANDLE_FAILURE("LLVMBuildBitCast");
goto fail;
}
if (!(tbl_sz = LLVMBuildLoad(comp_ctx->builder, tbl_sz, "tbl_sz"))) {
HANDLE_FAILURE("LLVMBuildLoad");
goto fail;
}
PUSH_I32(tbl_sz);
return true;
fail:
return false;
}
bool
aot_compile_op_table_grow(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMTypeRef param_types[4], ret_type, func_type, func_ptr_type;
LLVMValueRef func, param_values[4], ret, value;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
ret_type = I32_TYPE;
GET_AOT_FUNCTION(aot_table_grow, 4);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[2]);
/* v */
POP_I32(param_values[3]);
if (!(ret = LLVMBuildCall(comp_ctx->builder, func, param_values, 4,
"table_grow"))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
PUSH_I32(ret);
return true;
fail:
return false;
}
bool
aot_compile_op_table_fill(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx)
{
LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
LLVMValueRef func, param_values[5], value;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
param_types[3] = I32_TYPE;
param_types[4] = I32_TYPE;
ret_type = VOID_TYPE;
GET_AOT_FUNCTION(aot_table_fill, 5);
param_values[0] = func_ctx->aot_inst;
if (!(param_values[1] = I32_CONST(tbl_idx))) {
HANDLE_FAILURE("LLVMConstInt");
goto fail;
}
/* n */
POP_I32(param_values[2]);
/* v */
POP_I32(param_values[3]);
/* i */
POP_I32(param_values[4]);
/* "" means return void */
if (!(LLVMBuildCall(comp_ctx->builder, func, param_values, 5, ""))) {
HANDLE_FAILURE("LLVMBuildCall");
goto fail;
}
return true;
fail:
return false;
}
#endif /* WASM_ENABLE_REF_TYPES != 0 */

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _AOT_EMIT_TABLE_H_
#define _AOT_EMIT_TABLE_H_
#include "aot_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
bool
aot_compile_op_elem_drop(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_seg_idx);
bool
aot_compile_op_table_get(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
bool
aot_compile_op_table_set(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
bool
aot_compile_op_table_init(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx,
uint32 tbl_seg_idx);
bool
aot_compile_op_table_copy(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 src_tbl_idx,
uint32 dst_tbl_idx);
bool
aot_compile_op_table_size(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
bool
aot_compile_op_table_grow(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
bool
aot_compile_op_table_fill(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
uint64
get_tbl_inst_offset(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx,
uint32 tbl_idx);
LLVMValueRef
aot_compile_get_tbl_inst(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint32 tbl_idx);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif

View File

@ -143,6 +143,8 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
switch (global_type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_EXTERNREF:
case VALUE_TYPE_FUNCREF:
ptr_type = comp_ctx->basic_types.int32_ptr_type;
break;
case VALUE_TYPE_I64:
@ -158,7 +160,7 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
ptr_type = comp_ctx->basic_types.v128_ptr_type;
break;
default:
bh_assert(0);
bh_assert("unknown type");
break;
}

View File

@ -14,6 +14,8 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
{
switch (wasm_type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
return llvm_types->int32_type;
case VALUE_TYPE_I64:
return llvm_types->int64_type;
@ -21,12 +23,12 @@ wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
return llvm_types->float32_type;
case VALUE_TYPE_F64:
return llvm_types->float64_type;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
return llvm_types->i64x2_vec_type;
#endif
case VALUE_TYPE_VOID:
return llvm_types->void_type;
default:
break;
}
return NULL;
}
@ -491,34 +493,6 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return true;
}
static bool
create_table_base(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
AOTCompData *comp_data = comp_ctx->comp_data;
uint64 module_inst_mem_inst_size =
(uint64)comp_data->memory_count * sizeof(AOTMemoryInstance);
LLVMValueRef offset;
offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data.bytes)
+ module_inst_mem_inst_size
+ comp_ctx->comp_data->global_data_size);
func_ctx->table_base = LLVMBuildInBoundsGEP(comp_ctx->builder,
func_ctx->aot_inst,
&offset, 1,
"table_base_tmp");
if (!func_ctx->table_base) {
aot_set_last_error("llvm build in bounds gep failed.");
return false;
}
func_ctx->table_base = LLVMBuildBitCast(comp_ctx->builder, func_ctx->table_base,
INT32_PTR_TYPE, "table_base");
if (!func_ctx->table_base) {
aot_set_last_error("llvm build bit cast failed.");
return false;
}
return true;
}
static bool
create_cur_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
@ -810,11 +784,13 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
case VALUE_TYPE_F64:
local_value = F64_ZERO;
break;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
local_value = V128_ZERO;
break;
#endif
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
local_value = REF_NULL;
break;
default:
bh_assert(0);
break;
@ -853,10 +829,6 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
if (!create_memory_info(comp_ctx, func_ctx, int8_ptr_type, func_index))
goto fail;
/* Load table base */
if (!create_table_base(comp_ctx, func_ctx))
goto fail;
/* Load current exception */
if (!create_cur_exception(comp_ctx, func_ctx))
goto fail;
@ -943,6 +915,12 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
basic_types->meta_data_type = LLVMMetadataTypeInContext(context);
basic_types->int8_ptr_type = LLVMPointerType(basic_types->int8_type, 0);
if (basic_types->int8_ptr_type) {
basic_types->int8_pptr_type =
LLVMPointerType(basic_types->int8_ptr_type, 0);
}
basic_types->int16_ptr_type = LLVMPointerType(basic_types->int16_type, 0);
basic_types->int32_ptr_type = LLVMPointerType(basic_types->int32_type, 0);
basic_types->int64_ptr_type = LLVMPointerType(basic_types->int64_type, 0);
@ -959,7 +937,11 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
basic_types->v128_type = basic_types->i64x2_vec_type;
basic_types->v128_ptr_type = LLVMPointerType(basic_types->v128_type, 0);
basic_types->funcref_type = LLVMInt32TypeInContext(context);
basic_types->externref_type = LLVMInt32TypeInContext(context);
return (basic_types->int8_ptr_type
&& basic_types->int8_pptr_type
&& basic_types->int16_ptr_type
&& basic_types->int32_ptr_type
&& basic_types->int64_ptr_type
@ -971,7 +953,9 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context)
&& basic_types->i64x2_vec_type
&& basic_types->f32x4_vec_type
&& basic_types->f64x2_vec_type
&& basic_types->meta_data_type) ? true : false;
&& basic_types->meta_data_type
&& basic_types->funcref_type
&& basic_types->externref_type) ? true : false;
}
static bool
@ -1014,6 +998,7 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
consts->i32_32 = I32_CONST(32);
consts->i64_63 = I64_CONST(63);
consts->i64_64 = I64_CONST(64);
consts->ref_null = I32_CONST(NULL_REF);
return (consts->i8_zero
&& consts->i32_zero
@ -1041,7 +1026,8 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
&& consts->i32_31
&& consts->i32_32
&& consts->i64_63
&& consts->i64_64) ? true : false;
&& consts->i64_64
&& consts->ref_null) ? true : false;
}
typedef struct ArchItem {
@ -1245,6 +1231,9 @@ aot_create_comp_context(AOTCompData *comp_data,
if (option->enable_tail_call)
comp_ctx->enable_tail_call = true;
if (option->enable_ref_types)
comp_ctx->enable_ref_types = true;
if (option->enable_aux_stack_frame)
comp_ctx->enable_aux_stack_frame = true;
@ -1585,10 +1574,7 @@ aot_create_comp_context(AOTCompData *comp_data,
}
/* set exec_env data type to int8** */
if (!(comp_ctx->exec_env_type = LLVMPointerType(INT8_PTR_TYPE, 0))) {
aot_set_last_error("llvm get pointer type failed.");
goto fail;
}
comp_ctx->exec_env_type = comp_ctx->basic_types.int8_pptr_type;
/* set aot_inst data type to int8* */
comp_ctx->aot_inst_type = INT8_PTR_TYPE;
@ -1846,11 +1832,13 @@ aot_build_zero_function_ret(AOTCompContext *comp_ctx,
case VALUE_TYPE_F64:
ret = LLVMBuildRet(comp_ctx->builder, F64_ZERO);
break;
#if WASM_ENABLE_SIMD != 0
case VALUE_TYPE_V128:
ret = LLVMBuildRet(comp_ctx->builder, V128_ZERO);
break;
#endif
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
ret = LLVMBuildRet(comp_ctx->builder, REF_NULL);
break;
default:
bh_assert(0);
}

View File

@ -119,7 +119,6 @@ typedef struct AOTFuncContext {
LLVMValueRef exec_env;
LLVMValueRef aot_inst;
LLVMValueRef table_base;
LLVMValueRef argv_buf;
LLVMValueRef native_stack_bound;
LLVMValueRef aux_stack_bound;
@ -152,6 +151,7 @@ typedef struct AOTLLVMTypes {
LLVMTypeRef void_type;
LLVMTypeRef int8_ptr_type;
LLVMTypeRef int8_pptr_type;
LLVMTypeRef int16_ptr_type;
LLVMTypeRef int32_ptr_type;
LLVMTypeRef int64_ptr_type;
@ -168,6 +168,9 @@ typedef struct AOTLLVMTypes {
LLVMTypeRef f64x2_vec_type;
LLVMTypeRef meta_data_type;
LLVMTypeRef funcref_type;
LLVMTypeRef externref_type;
} AOTLLVMTypes;
typedef struct AOTLLVMConsts {
@ -199,6 +202,7 @@ typedef struct AOTLLVMConsts {
LLVMValueRef i32_32;
LLVMValueRef i64_63;
LLVMValueRef i64_64;
LLVMValueRef ref_null;
} AOTLLVMConsts;
/**
@ -241,6 +245,9 @@ typedef struct AOTCompContext {
/* Tail Call */
bool enable_tail_call;
/* Reference Types */
bool enable_ref_types;
/* Whether optimize the JITed code */
bool optimize;
@ -283,6 +290,7 @@ typedef struct AOTCompOption{
bool enable_thread_mgr;
bool enable_tail_call;
bool enable_simd;
bool enable_ref_types;
bool enable_aux_stack_check;
bool enable_aux_stack_frame;
bool is_sgx_platform;

View File

@ -43,6 +43,7 @@ typedef struct AOTCompOption{
bool enable_thread_mgr;
bool enable_tail_call;
bool enable_simd;
bool enable_ref_types;
bool enable_aux_stack_check;
bool enable_aux_stack_frame;
bool is_sgx_platform;

View File

@ -849,6 +849,45 @@ wasm_runtime_spawn_thread(wasm_exec_env_t exec_env, wasm_thread_t *tid,
WASM_RUNTIME_API_EXTERN int32_t
wasm_runtime_join_thread(wasm_thread_t tid, void **retval);
/**
* Map external object to an internal externref index: if the index
* has been created, return it, otherwise create the index.
*
* @param module_inst the WASM module instance that the extern object
* belongs to
* @param extern_obj the external object to be mapped
* @param p_externref_idx return externref index of the external object
*
* @return true if success, false otherwise
*/
WASM_RUNTIME_API_EXTERN bool
wasm_externref_obj2ref(wasm_module_inst_t module_inst,
void *extern_obj, uint32_t *p_externref_idx);
/**
* Retrieve the external object from an internal externref index
*
* @param externref_idx the externref index to retrieve
* @param p_extern_obj return the mapped external object of
* the externref index
*
* @return true if success, false otherwise
*/
WASM_RUNTIME_API_EXTERN bool
wasm_externref_ref2obj(uint32_t externref_idx, void **p_extern_obj);
/**
* Retain an extern object which is mapped to the internal externref
* so that the object won't be cleaned during extern object reclaim
* if it isn't used.
*
* @param externref_idx the externref index of an external object
* to retain
* @return true if success, false otherwise
*/
WASM_RUNTIME_API_EXTERN bool
wasm_externref_retain(uint32_t externref_idx);
/**
* dump the call stack
*

View File

@ -20,22 +20,29 @@ extern "C" {
#define VALUE_TYPE_F32 0x7D
#define VALUE_TYPE_F64 0x7C
#define VALUE_TYPE_V128 0x7B
#define VALUE_TYPE_FUNCREF 0x70
#define VALUE_TYPE_EXTERNREF 0x6F
#define VALUE_TYPE_VOID 0x40
/* Used by AOT */
#define VALUE_TYPE_I1 0x41
/* Used by loader to represent any type of i32/i64/f32/f64 */
#define VALUE_TYPE_ANY 0x42
/* Table Element Type */
#define TABLE_ELEM_TYPE_ANY_FUNC 0x70
#define DEFAULT_NUM_BYTES_PER_PAGE 65536
#define NULL_REF (0xFFFFFFFF)
#define TABLE_MAX_SIZE (1024)
#define INIT_EXPR_TYPE_I32_CONST 0x41
#define INIT_EXPR_TYPE_I64_CONST 0x42
#define INIT_EXPR_TYPE_F32_CONST 0x43
#define INIT_EXPR_TYPE_F64_CONST 0x44
#define INIT_EXPR_TYPE_V128_CONST 0xFD
/* = WASM_OP_REF_FUNC */
#define INIT_EXPR_TYPE_FUNCREF_CONST 0xD2
/* = WASM_OP_REF_NULL */
#define INIT_EXPR_TYPE_REFNULL_CONST 0xD0
#define INIT_EXPR_TYPE_GET_GLOBAL 0x23
#define INIT_EXPR_TYPE_ERROR 0xff
@ -105,6 +112,7 @@ typedef union WASMValue {
typedef struct InitializerExpression {
/* type of INIT_EXPR_TYPE_XXX */
/* it actually is instr, in some places, requires constant only */
uint8 init_expr_type;
WASMValue u;
} InitializerExpression;
@ -124,6 +132,7 @@ typedef struct WASMTable {
uint32 init_size;
/* specified if (flags & 1), else it is 0x10000 */
uint32 max_size;
bool possible_grow;
} WASMTable;
typedef struct WASMMemory {
@ -141,6 +150,7 @@ typedef struct WASMTableImport {
uint32 init_size;
/* specified if (flags & 1), else it is 0x10000 */
uint32 max_size;
bool possible_grow;
#if WASM_ENABLE_MULTI_MODULE != 0
WASMModule *import_module;
WASMTable *import_table_linked;
@ -257,6 +267,12 @@ typedef struct WASMExport {
} WASMExport;
typedef struct WASMTableSeg {
/* 0 to 7 */
uint32 mode;
/* funcref or externref, elemkind will be considered as funcref */
uint32 elem_type;
bool is_dropped;
/* optional, only for active */
uint32 table_index;
InitializerExpression base_offset;
uint32 function_count;
@ -456,6 +472,10 @@ wasm_value_type_size(uint8 value_type)
switch (value_type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
return sizeof(int32);
case VALUE_TYPE_I64:
case VALUE_TYPE_F64:
@ -475,11 +495,14 @@ wasm_value_type_cell_num(uint8 value_type)
{
if (value_type == VALUE_TYPE_VOID)
return 0;
else if (value_type == VALUE_TYPE_I32
|| value_type == VALUE_TYPE_F32)
else if (value_type == VALUE_TYPE_I32 || value_type == VALUE_TYPE_F32
#if WASM_ENABLE_REF_TYPES != 0
|| value_type == VALUE_TYPE_FUNCREF
|| value_type == VALUE_TYPE_EXTERNREF
#endif
)
return 1;
else if (value_type == VALUE_TYPE_I64
|| value_type == VALUE_TYPE_F64)
else if (value_type == VALUE_TYPE_I64 || value_type == VALUE_TYPE_F64)
return 2;
#if WASM_ENABLE_SIMD != 0
else if (value_type == VALUE_TYPE_V128)

View File

@ -871,7 +871,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
uint8 *global_data = module->global_data;
uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0;
WASMTableInstance *table = module->default_table;
WASMType **wasm_types = module->module->types;
WASMGlobalInstance *globals = module->globals, *global;
uint8 opcode_IMPDEP = WASM_OP_IMPDEP;
@ -1099,7 +1098,8 @@ label_pop_csp_n:
#endif
{
WASMType *cur_type, *cur_func_type;
WASMTableInstance *cur_table_inst;
WASMTableInstance *tbl_inst;
uint32 tbl_idx;
#if WASM_ENABLE_TAIL_CALL != 0
opcode = *(frame_ip - 1);
#endif
@ -1114,41 +1114,35 @@ label_pop_csp_n:
* no matter it is used or not
*/
read_leb_uint32(frame_ip, frame_ip_end, tidx);
if (tidx >= module->module->type_count) {
wasm_set_exception(module, "unknown type");
goto got_exception;
}
bh_assert(tidx < module->module->type_count);
cur_type = wasm_types[tidx];
/* to skip 0x00 here */
frame_ip++;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
val = POP_I32();
/* careful, it might be a table in another module */
cur_table_inst = table;
#if WASM_ENABLE_MULTI_MODULE != 0
if (table->table_inst_linked) {
cur_table_inst = table->table_inst_linked;
}
#endif
if (val < 0 || val >= (int32)cur_table_inst->cur_size) {
if (val < 0 || val >= (int32)tbl_inst->cur_size) {
wasm_set_exception(module, "undefined element");
goto got_exception;
}
fidx = ((uint32*)cur_table_inst->base_addr)[val];
fidx = ((uint32*)tbl_inst->base_addr)[val];
if (fidx == (uint32)-1) {
wasm_set_exception(module, "uninitialized element");
goto got_exception;
}
#if WASM_ENABLE_MULTI_MODULE != 0
if (fidx >= module->function_count) {
/*
* we might be using a table injected by host or
* another module. In that case, we don't validate
* the elem value while loading
*/
if (fidx >= module->function_count) {
wasm_set_exception(module, "unknown function");
goto got_exception;
}
#endif
/* always call module own functions */
cur_func = module->functions + fidx;
@ -1201,6 +1195,99 @@ label_pop_csp_n:
HANDLE_OP_END ();
}
#if WASM_ENABLE_REF_TYPES != 0
HANDLE_OP (WASM_OP_SELECT_T):
{
uint32 vec_len;
uint8 type;
read_leb_uint32(frame_ip, frame_ip_end, vec_len);
type = *frame_ip++;
cond = (uint32)POP_I32();
if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) {
frame_sp -= 2;
if (!cond) {
*(frame_sp - 2) = *frame_sp;
*(frame_sp - 1) = *(frame_sp + 1);
}
}
else {
frame_sp--;
if (!cond)
*(frame_sp - 1) = *frame_sp;
}
(void)vec_len;
HANDLE_OP_END ();
}
HANDLE_OP (WASM_OP_TABLE_GET):
{
uint32 tbl_idx, elem_idx;
WASMTableInstance *tbl_inst;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
elem_idx = POP_I32();
if (elem_idx >= tbl_inst->cur_size) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
PUSH_I32(((uint32 *)tbl_inst->base_addr)[elem_idx]);
HANDLE_OP_END ();
}
HANDLE_OP (WASM_OP_TABLE_SET):
{
uint32 tbl_idx, elem_idx, val;
WASMTableInstance *tbl_inst;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
val = POP_I32();
elem_idx = POP_I32();
if (elem_idx >= tbl_inst->cur_size) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
((uint32 *)(tbl_inst->base_addr))[elem_idx] = val;
HANDLE_OP_END();
}
HANDLE_OP (WASM_OP_REF_NULL):
{
uint32 ref_type;
read_leb_uint32(frame_ip, frame_ip_end, ref_type);
PUSH_I32(NULL_REF);
(void)ref_type;
HANDLE_OP_END();
}
HANDLE_OP (WASM_OP_REF_IS_NULL):
{
uint32 val;
val = POP_I32();
PUSH_I32(val == NULL_REF ? 1 : 0);
HANDLE_OP_END();
}
HANDLE_OP (WASM_OP_REF_FUNC):
{
uint32 func_idx;
read_leb_uint32(frame_ip, frame_ip_end, func_idx);
PUSH_I32(func_idx);
HANDLE_OP_END();
}
#endif /* WASM_ENABLE_REF_TYPES */
/* variable instructions */
HANDLE_OP (WASM_OP_GET_LOCAL):
{
@ -1209,6 +1296,10 @@ label_pop_csp_n:
switch (local_type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
PUSH_I32(*(int32*)(frame_lp + local_offset));
break;
case VALUE_TYPE_I64:
@ -1240,6 +1331,10 @@ label_pop_csp_n:
switch (local_type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
*(int32*)(frame_lp + local_offset) = POP_I32();
break;
case VALUE_TYPE_I64:
@ -1271,6 +1366,10 @@ label_pop_csp_n:
switch (local_type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
*(int32*)(frame_lp + local_offset) = *(int32*)(frame_sp - 1);
break;
case VALUE_TYPE_I64:
@ -2586,10 +2685,173 @@ label_pop_csp_n:
break;
}
#endif /* WASM_ENABLE_BULK_MEMORY */
#if WASM_ENABLE_REF_TYPES != 0
case WASM_OP_TABLE_INIT:
{
uint32 tbl_idx, elem_idx;
uint64 n, s, d;
WASMTableInstance *tbl_inst;
read_leb_uint32(frame_ip, frame_ip_end, elem_idx);
bh_assert(elem_idx < module->module->table_seg_count);
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
bh_assert(tbl_idx < module->module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
n = (uint32)POP_I32();
s = (uint32)POP_I32();
d = (uint32)POP_I32();
/* TODO: what if the element is not passive? */
if (!n) {
break;
}
if (n + s > module->module->table_segments[elem_idx].function_count
|| d + n > tbl_inst->cur_size) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
if (module->module->table_segments[elem_idx].is_dropped) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
if (!wasm_elem_is_passive(
module->module->table_segments[elem_idx].mode)) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
bh_memcpy_s(
(uint8 *)(tbl_inst)
+ offsetof(WASMTableInstance, base_addr) + d * sizeof(uint32),
(tbl_inst->cur_size - d) * sizeof(uint32),
module->module->table_segments[elem_idx].func_indexes + s,
n * sizeof(uint32));
break;
}
case WASM_OP_ELEM_DROP:
{
uint32 elem_idx;
read_leb_uint32(frame_ip, frame_ip_end, elem_idx);
bh_assert(elem_idx < module->module->table_seg_count);
module->module->table_segments[elem_idx].is_dropped = true;
break;
}
case WASM_OP_TABLE_COPY:
{
uint32 src_tbl_idx, dst_tbl_idx;
uint64 n, s, d;
WASMTableInstance *src_tbl_inst, *dst_tbl_inst;
read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx);
bh_assert(dst_tbl_idx < module->table_count);
dst_tbl_inst = wasm_get_table_inst(module, dst_tbl_idx);
read_leb_uint32(frame_ip, frame_ip_end, src_tbl_idx);
bh_assert(src_tbl_idx < module->table_count);
src_tbl_inst = wasm_get_table_inst(module, src_tbl_idx);
n = (uint32)POP_I32();
s = (uint32)POP_I32();
d = (uint32)POP_I32();
if (s + n > dst_tbl_inst->cur_size
|| d + n > src_tbl_inst->cur_size) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
/* if s >= d, copy from front to back */
/* if s < d, copy from back to front */
/* merge all together */
bh_memcpy_s(
(uint8 *)(dst_tbl_inst) + offsetof(WASMTableInstance, base_addr)
+ d * sizeof(uint32),
(dst_tbl_inst->cur_size - d) * sizeof(uint32),
(uint8 *)(src_tbl_inst) + offsetof(WASMTableInstance, base_addr)
+ s * sizeof(uint32),
n * sizeof(uint32));
break;
}
case WASM_OP_TABLE_GROW:
{
uint32 tbl_idx, n, init_val, orig_tbl_sz;
WASMTableInstance *tbl_inst;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
orig_tbl_sz = tbl_inst->cur_size;
n = POP_I32();
init_val = POP_I32();
if (!wasm_enlarge_table(module, tbl_idx, n, init_val)) {
PUSH_I32(-1);
}
else {
PUSH_I32(orig_tbl_sz);
}
break;
}
case WASM_OP_TABLE_SIZE:
{
uint32 tbl_idx;
WASMTableInstance *tbl_inst;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
PUSH_I32(tbl_inst->cur_size);
break;
}
case WASM_OP_TABLE_FILL:
{
uint32 tbl_idx, n, val, i;
WASMTableInstance *tbl_inst;
read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
n = POP_I32();
val = POP_I32();
i = POP_I32();
/* TODO: what if the element is not passive? */
/* TODO: what if the element is dropped? */
if (i + n > tbl_inst->cur_size) {
/* TODO: verify warning content */
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
for (; n != 0; i++, n--) {
((uint32 *)(tbl_inst->base_addr))[i] = val;
}
break;
}
#endif /* WASM_ENABLE_REF_TYPES */
default:
wasm_set_exception(module, "unsupported opcode");
goto got_exception;
break;
goto got_exception;
}
HANDLE_OP_END ();
}
@ -2946,6 +3208,17 @@ label_pop_csp_n:
#if WASM_ENABLE_TAIL_CALL == 0
HANDLE_OP (WASM_OP_RETURN_CALL):
HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
#endif
#if WASM_ENABLE_SHARED_MEMORY == 0
HANDLE_OP (WASM_OP_ATOMIC_PREFIX):
#endif
#if WASM_ENABLE_REF_TYPES == 0
HANDLE_OP (WASM_OP_SELECT_T):
HANDLE_OP (WASM_OP_TABLE_GET):
HANDLE_OP (WASM_OP_TABLE_SET):
HANDLE_OP (WASM_OP_REF_NULL):
HANDLE_OP (WASM_OP_REF_IS_NULL):
HANDLE_OP (WASM_OP_REF_FUNC):
#endif
HANDLE_OP (WASM_OP_UNUSED_0x14):
HANDLE_OP (WASM_OP_UNUSED_0x15):
@ -2953,10 +3226,7 @@ label_pop_csp_n:
HANDLE_OP (WASM_OP_UNUSED_0x17):
HANDLE_OP (WASM_OP_UNUSED_0x18):
HANDLE_OP (WASM_OP_UNUSED_0x19):
HANDLE_OP (WASM_OP_UNUSED_0x1c):
HANDLE_OP (WASM_OP_UNUSED_0x1d):
HANDLE_OP (WASM_OP_UNUSED_0x1e):
HANDLE_OP (WASM_OP_UNUSED_0x1f):
HANDLE_OP (WASM_OP_UNUSED_0x27):
/* Used by fast interpreter */
HANDLE_OP (EXT_OP_SET_LOCAL_FAST_I64):
HANDLE_OP (EXT_OP_TEE_LOCAL_FAST_I64):

View File

@ -991,7 +991,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
uint8 *global_data = module->global_data;
uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0;
WASMTableInstance *table = module->default_table;
WASMGlobalInstance *globals = module->globals, *global;
uint8 opcode_IMPDEP = WASM_OP_IMPDEP;
WASMInterpFrame *frame = NULL;
@ -1150,7 +1149,8 @@ recover_br_info:
#endif
{
WASMType *cur_type, *cur_func_type;
WASMTableInstance *cur_table_inst;
WASMTableInstance *tbl_inst;
uint32 tbl_idx;
#if WASM_ENABLE_TAIL_CALL != 0
GET_OPCODE();
@ -1160,40 +1160,36 @@ recover_br_info:
#endif
tidx = read_uint32(frame_ip);
cur_type = module->module->types[tidx];
tbl_idx = read_uint32(frame_ip);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
val = GET_OPERAND(uint32, I32, 0);
frame_ip += 2;
if (tidx >= module->module->type_count) {
wasm_set_exception(module, "type index is overflow");
goto got_exception;
}
cur_type = module->module->types[tidx];
/* careful, it might be a table in another module */
cur_table_inst = table;
#if WASM_ENABLE_MULTI_MODULE != 0
if (table->table_inst_linked) {
cur_table_inst = table->table_inst_linked;
}
#endif
if (val < 0 || val >= (int32)cur_table_inst->cur_size) {
if (val < 0 || val >= (int32)tbl_inst->cur_size) {
wasm_set_exception(module, "undefined element");
goto got_exception;
}
fidx = ((uint32*)cur_table_inst->base_addr)[val];
fidx = ((uint32*)tbl_inst->base_addr)[val];
if (fidx == (uint32)-1) {
wasm_set_exception(module, "uninitialized element");
goto got_exception;
}
#if WASM_ENABLE_MULTI_MODULE != 0
/*
* we might be using a table injected by host or
* another module. in that case, we don't validate
* the elem value while loading
*/
if (fidx >= module->function_count) {
wasm_set_exception(module, "unknown function");
goto got_exception;
}
#endif
/* always call module own functions */
cur_func = module->functions + fidx;
@ -1252,6 +1248,70 @@ recover_br_info:
HANDLE_OP_END ();
}
#if WASM_ENABLE_REF_TYPES != 0
HANDLE_OP (WASM_OP_TABLE_GET):
{
uint32 tbl_idx, elem_idx;
WASMTableInstance *tbl_inst;
tbl_idx = read_uint32(frame_ip);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
elem_idx = POP_I32();
if (elem_idx >= tbl_inst->cur_size) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
PUSH_I32(((uint32 *)tbl_inst->base_addr)[elem_idx]);
HANDLE_OP_END();
}
HANDLE_OP (WASM_OP_TABLE_SET):
{
uint32 tbl_idx, elem_idx, val;
WASMTableInstance *tbl_inst;
tbl_idx = read_uint32(frame_ip);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
val = POP_I32();
elem_idx = POP_I32();
if (elem_idx >= tbl_inst->cur_size) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
((uint32 *)tbl_inst->base_addr)[elem_idx] = val;
HANDLE_OP_END ();
}
HANDLE_OP (WASM_OP_REF_NULL):
{
PUSH_I32(NULL_REF);
HANDLE_OP_END();
}
HANDLE_OP (WASM_OP_REF_IS_NULL):
{
uint32 val;
val = POP_I32();
PUSH_I32(val == NULL_REF ? 1 : 0);
HANDLE_OP_END();
}
HANDLE_OP (WASM_OP_REF_FUNC):
{
uint32 func_idx = read_uint32(frame_ip);
PUSH_I32(func_idx);
HANDLE_OP_END();
}
#endif /* WASM_ENABLE_REF_TYPES */
/* variable instructions */
HANDLE_OP (EXT_OP_SET_LOCAL_FAST):
HANDLE_OP (EXT_OP_TEE_LOCAL_FAST):
@ -2605,10 +2665,165 @@ recover_br_info:
break;
}
#endif /* WASM_ENABLE_BULK_MEMORY */
#if WASM_ENABLE_REF_TYPES != 0
case WASM_OP_TABLE_INIT:
{
uint32 tbl_idx, elem_idx;
uint64 n, s, d;
WASMTableInstance *tbl_inst;
elem_idx = read_uint32(frame_ip);
bh_assert(elem_idx < module->module->table_seg_count);
tbl_idx = read_uint32(frame_ip);
bh_assert(tbl_idx < module->module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
n = (uint32)POP_I32();
s = (uint32)POP_I32();
d = (uint32)POP_I32();
if (!n) {
break;
}
if (n + s > module->module->table_segments[elem_idx].function_count
|| d + n > tbl_inst->cur_size) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
if (module->module->table_segments[elem_idx].is_dropped) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
if (!wasm_elem_is_passive(
module->module->table_segments[elem_idx].mode)) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
bh_memcpy_s(
(uint8 *)tbl_inst + offsetof(WASMTableInstance, base_addr)
+ d * sizeof(uint32),
(tbl_inst->cur_size - d) * sizeof(uint32),
module->module->table_segments[elem_idx].func_indexes + s,
n * sizeof(uint32));
break;
}
case WASM_OP_ELEM_DROP:
{
uint32 elem_idx = read_uint32(frame_ip);
bh_assert(elem_idx < module->module->table_seg_count);
module->module->table_segments[elem_idx].is_dropped = true;
break;
}
case WASM_OP_TABLE_COPY:
{
uint32 src_tbl_idx, dst_tbl_idx;
uint64 n, s, d;
WASMTableInstance *src_tbl_inst, *dst_tbl_inst;
dst_tbl_idx = read_uint32(frame_ip);
bh_assert(dst_tbl_idx < module->table_count);
dst_tbl_inst = wasm_get_table_inst(module, dst_tbl_idx);
src_tbl_idx = read_uint32(frame_ip);
bh_assert(src_tbl_idx < module->table_count);
src_tbl_inst = wasm_get_table_inst(module, src_tbl_idx);
n = (uint32)POP_I32();
s = (uint32)POP_I32();
d = (uint32)POP_I32();
if (s + n > dst_tbl_inst->cur_size
|| d + n > src_tbl_inst->cur_size) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
/* if s >= d, copy from front to back */
/* if s < d, copy from back to front */
/* merge all together */
bh_memcpy_s(
(uint8 *)dst_tbl_inst + offsetof(WASMTableInstance, base_addr)
+ d * sizeof(uint32),
(dst_tbl_inst->cur_size - d) * sizeof(uint32),
(uint8 *)src_tbl_inst
+ offsetof(WASMTableInstance, base_addr) + s * sizeof(uint32),
n * sizeof(uint32));
break;
}
case WASM_OP_TABLE_GROW:
{
uint32 tbl_idx, n, init_val, orig_tbl_sz;
WASMTableInstance *tbl_inst;
tbl_idx = read_uint32(frame_ip);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
orig_tbl_sz = tbl_inst->cur_size;
n = POP_I32();
init_val = POP_I32();
if (!wasm_enlarge_table(module, tbl_idx, n, init_val)) {
PUSH_I32(-1);
} else {
PUSH_I32(orig_tbl_sz);
}
break;
}
case WASM_OP_TABLE_SIZE:
{
uint32 tbl_idx;
WASMTableInstance *tbl_inst;
tbl_idx = read_uint32(frame_ip);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
PUSH_I32(tbl_inst->cur_size);
break;
}
case WASM_OP_TABLE_FILL:
{
uint32 tbl_idx, n, val, i;
WASMTableInstance *tbl_inst;
tbl_idx = read_uint32(frame_ip);
bh_assert(tbl_idx < module->table_count);
tbl_inst = wasm_get_table_inst(module, tbl_idx);
n = POP_I32();
val = POP_I32();
i = POP_I32();
if (i + n > tbl_inst->cur_size) {
wasm_set_exception(module, "out of bounds table access");
goto got_exception;
}
for (; n != 0; i++, n--) {
((uint32 *)(tbl_inst->base_addr))[i] = val;
}
break;
}
#endif /* WASM_ENABLE_REF_TYPES */
default:
wasm_set_exception(module, "unsupported opcode");
goto got_exception;
break;
goto got_exception;
}
HANDLE_OP_END ();
}
@ -2992,16 +3207,25 @@ recover_br_info:
HANDLE_OP (WASM_OP_RETURN_CALL):
HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
#endif
#if WASM_ENABLE_SHARED_MEMORY == 0
HANDLE_OP (WASM_OP_ATOMIC_PREFIX):
#endif
#if WASM_ENABLE_REF_TYPES == 0
HANDLE_OP (WASM_OP_TABLE_GET):
HANDLE_OP (WASM_OP_TABLE_SET):
HANDLE_OP (WASM_OP_REF_NULL):
HANDLE_OP (WASM_OP_REF_IS_NULL):
HANDLE_OP (WASM_OP_REF_FUNC):
#endif
/* SELECT_T is converted to SELECT or SELECT_64 */
HANDLE_OP (WASM_OP_SELECT_T):
HANDLE_OP (WASM_OP_UNUSED_0x14):
HANDLE_OP (WASM_OP_UNUSED_0x15):
HANDLE_OP (WASM_OP_UNUSED_0x16):
HANDLE_OP (WASM_OP_UNUSED_0x17):
HANDLE_OP (WASM_OP_UNUSED_0x18):
HANDLE_OP (WASM_OP_UNUSED_0x19):
HANDLE_OP (WASM_OP_UNUSED_0x1c):
HANDLE_OP (WASM_OP_UNUSED_0x1d):
HANDLE_OP (WASM_OP_UNUSED_0x1e):
HANDLE_OP (WASM_OP_UNUSED_0x1f):
HANDLE_OP (WASM_OP_UNUSED_0x27):
/* optimized op code */
HANDLE_OP (WASM_OP_F32_STORE):
HANDLE_OP (WASM_OP_F64_STORE):

File diff suppressed because it is too large Load Diff

View File

@ -70,6 +70,14 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
uint8 **p_else_addr,
uint8 **p_end_addr);
#if WASM_ENABLE_REF_TYPES != 0
void
wasm_set_ref_types_flag(bool enable);
bool
wasm_get_ref_types_flag();
#endif
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -47,11 +47,11 @@ typedef enum WASMOpcode {
/* parametric instructions */
WASM_OP_DROP = 0x1a, /* drop */
WASM_OP_SELECT = 0x1b, /* select */
WASM_OP_SELECT_T = 0x1c, /* select t */
WASM_OP_UNUSED_0x1c = 0x1c,
WASM_OP_UNUSED_0x1d = 0x1d,
WASM_OP_UNUSED_0x1e = 0x1e,
WASM_OP_UNUSED_0x1f = 0x1f,
WASM_OP_GET_GLOBAL_64 = 0x1d,
WASM_OP_SET_GLOBAL_64 = 0x1e,
WASM_OP_SET_GLOBAL_AUX_STACK = 0x1f,
/* variable instructions */
WASM_OP_GET_LOCAL = 0x20, /* get_local */
@ -60,9 +60,9 @@ typedef enum WASMOpcode {
WASM_OP_GET_GLOBAL = 0x23, /* get_global */
WASM_OP_SET_GLOBAL = 0x24, /* set_global */
WASM_OP_GET_GLOBAL_64 = 0x25,
WASM_OP_SET_GLOBAL_64 = 0x26,
WASM_OP_SET_GLOBAL_AUX_STACK = 0x27,
WASM_OP_TABLE_GET = 0x25, /* table.get */
WASM_OP_TABLE_SET = 0x26, /* table.set */
WASM_OP_UNUSED_0x27 = 0x27,
/* memory instructions */
WASM_OP_I32_LOAD = 0x28, /* i32.load */
@ -256,10 +256,16 @@ typedef enum WASMOpcode {
EXT_OP_COPY_STACK_TOP = 0xcc,
EXT_OP_COPY_STACK_TOP_I64 = 0xcd,
EXT_OP_COPY_STACK_VALUES = 0xce,
EXT_OP_BLOCK = 0xcf, /* block with blocktype */
EXT_OP_LOOP = 0xd0, /* loop with blocktype */
EXT_OP_IF = 0xd1, /* if with blocktype */
WASM_OP_IMPDEP = 0xd2,
WASM_OP_IMPDEP = 0xcf,
WASM_OP_REF_NULL = 0xd0, /* ref.null */
WASM_OP_REF_IS_NULL = 0xd1, /* ref.is_null */
WASM_OP_REF_FUNC = 0xd2, /* ref.func */
EXT_OP_BLOCK = 0xd3, /* block with blocktype */
EXT_OP_LOOP = 0xd4, /* loop with blocktype */
EXT_OP_IF = 0xd5, /* if with blocktype */
/* Post-MVP extend op prefix */
WASM_OP_MISC_PREFIX = 0xfc,
@ -276,15 +282,16 @@ typedef enum WASMMiscEXTOpcode {
WASM_OP_I64_TRUNC_SAT_U_F32 = 0x05,
WASM_OP_I64_TRUNC_SAT_S_F64 = 0x06,
WASM_OP_I64_TRUNC_SAT_U_F64 = 0x07,
#if WASM_ENABLE_BULK_MEMORY != 0
WASM_OP_MEMORY_INIT = 0x08,
WASM_OP_DATA_DROP = 0x09,
WASM_OP_MEMORY_COPY = 0x0a,
WASM_OP_MEMORY_FILL = 0x0b,
WASM_OP_TABLE_INIT = 0x0c,
WASM_OP_ELEM_DROP = 0x0d,
WASM_OP_TABLE_COPY = 0x0e
#endif
WASM_OP_TABLE_COPY = 0x0e,
WASM_OP_TABLE_GROW = 0x0f,
WASM_OP_TABLE_SIZE = 0x10,
WASM_OP_TABLE_FILL = 0x11,
} WASMMiscEXTOpcode;
typedef enum WASMSimdEXTOpcode {
@ -594,15 +601,6 @@ typedef enum WASMAtomicEXTOpcode {
}
#endif
/* Opcode prefix controlled by features */
#if WASM_ENABLE_SHARED_MEMORY != 0
#define DEF_ATOMIC_PREFIX_HANDLE(_name) \
_name[WASM_OP_ATOMIC_PREFIX] = \
HANDLE_OPCODE (WASM_OP_ATOMIC_PREFIX); /* 0xfe */
#else
#define DEF_ATOMIC_PREFIX_HANDLE(_name)
#endif
/*
* Macro used to generate computed goto tables for the C interpreter.
*/
@ -638,18 +636,18 @@ static type _name[WASM_INSTRUCTION_NUM] = { \
HANDLE_OPCODE (WASM_OP_UNUSED_0x19), /* 0x19 */ \
HANDLE_OPCODE (WASM_OP_DROP), /* 0x1a */ \
HANDLE_OPCODE (WASM_OP_SELECT), /* 0x1b */ \
HANDLE_OPCODE (WASM_OP_UNUSED_0x1c), /* 0x1c */ \
HANDLE_OPCODE (WASM_OP_UNUSED_0x1d), /* 0x1d */ \
HANDLE_OPCODE (WASM_OP_UNUSED_0x1e), /* 0x1e */ \
HANDLE_OPCODE (WASM_OP_UNUSED_0x1f), /* 0x1f */ \
HANDLE_OPCODE (WASM_OP_SELECT_T), /* 0x1c */ \
HANDLE_OPCODE (WASM_OP_GET_GLOBAL_64), /* 0x1d */ \
HANDLE_OPCODE (WASM_OP_SET_GLOBAL_64), /* 0x1e */ \
HANDLE_OPCODE (WASM_OP_SET_GLOBAL_AUX_STACK), /* 0x1f */ \
HANDLE_OPCODE (WASM_OP_GET_LOCAL), /* 0x20 */ \
HANDLE_OPCODE (WASM_OP_SET_LOCAL), /* 0x21 */ \
HANDLE_OPCODE (WASM_OP_TEE_LOCAL), /* 0x22 */ \
HANDLE_OPCODE (WASM_OP_GET_GLOBAL), /* 0x23 */ \
HANDLE_OPCODE (WASM_OP_SET_GLOBAL), /* 0x24 */ \
HANDLE_OPCODE (WASM_OP_GET_GLOBAL_64), /* 0x25 */ \
HANDLE_OPCODE (WASM_OP_SET_GLOBAL_64), /* 0x26 */ \
HANDLE_OPCODE (WASM_OP_SET_GLOBAL_AUX_STACK), /* 0x27 */ \
HANDLE_OPCODE (WASM_OP_TABLE_GET), /* 0x25 */ \
HANDLE_OPCODE (WASM_OP_TABLE_SET), /* 0x26 */ \
HANDLE_OPCODE (WASM_OP_UNUSED_0x27), /* 0x27 */ \
HANDLE_OPCODE (WASM_OP_I32_LOAD), /* 0x28 */ \
HANDLE_OPCODE (WASM_OP_I64_LOAD), /* 0x29 */ \
HANDLE_OPCODE (WASM_OP_F32_LOAD), /* 0x2a */ \
@ -817,14 +815,19 @@ static type _name[WASM_INSTRUCTION_NUM] = { \
HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP), /* 0xcc */ \
HANDLE_OPCODE (EXT_OP_COPY_STACK_TOP_I64), /* 0xcd */ \
HANDLE_OPCODE (EXT_OP_COPY_STACK_VALUES), /* 0xce */ \
HANDLE_OPCODE (EXT_OP_BLOCK), /* 0xcf */ \
HANDLE_OPCODE (EXT_OP_LOOP), /* 0xd0 */ \
HANDLE_OPCODE (EXT_OP_IF), /* 0xd1 */ \
HANDLE_OPCODE (WASM_OP_IMPDEP), /* 0xd2 */ \
HANDLE_OPCODE (WASM_OP_IMPDEP), /* 0xcf */ \
HANDLE_OPCODE (WASM_OP_REF_NULL), /* 0xd0 */ \
HANDLE_OPCODE (WASM_OP_REF_IS_NULL), /* 0xd1 */ \
HANDLE_OPCODE (WASM_OP_REF_FUNC), /* 0xd2 */ \
HANDLE_OPCODE (EXT_OP_BLOCK), /* 0xd3 */ \
HANDLE_OPCODE (EXT_OP_LOOP), /* 0xd4 */ \
HANDLE_OPCODE (EXT_OP_IF), /* 0xd5 */ \
}; \
do { \
_name[WASM_OP_MISC_PREFIX] = \
HANDLE_OPCODE (WASM_OP_MISC_PREFIX); /* 0xfc */ \
DEF_ATOMIC_PREFIX_HANDLE(_name) \
_name[WASM_OP_ATOMIC_PREFIX] = \
HANDLE_OPCODE (WASM_OP_ATOMIC_PREFIX); /* 0xfe */ \
} while (0)
#endif /* end of _WASM_OPCODE_H */

View File

@ -499,9 +499,12 @@ tables_instantiate(const WASMModule *module,
else
#endif
{
/* it is a built-in table */
total_size = offsetof(WASMTableInstance, base_addr)
+ sizeof(uint32) * (uint64)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;
}
if (!(table = tables[table_index++] = runtime_malloc
@ -530,8 +533,15 @@ tables_instantiate(const WASMModule *module,
/* instantiate tables from table section */
for (i = 0; i < module->table_count; i++) {
total_size = offsetof(WASMTableInstance, base_addr) +
sizeof(uint32) * (uint64)module->tables[i].init_size;
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;
#else
total_size += module->tables[i].possible_grow
? sizeof(uint32) * (uint64)module->tables[i].max_size
: sizeof(uint32) * (uint64)module->tables[i].init_size;
#endif
if (!(table = tables[table_index++] = runtime_malloc
(total_size, error_buf, error_buf_size))) {
tables_deinstantiate(tables, table_count);
@ -764,6 +774,11 @@ globals_instantiate(const WASMModule *module,
&(globals[init_expr->u.global_index].initial_value),
sizeof(globals[init_expr->u.global_index].initial_value));
}
#if WASM_ENABLE_REF_TYPES != 0
else if (init_expr->init_expr_type == INIT_EXPR_TYPE_REFNULL_CONST) {
global->initial_value.u32 = (uint32)NULL_REF;
}
#endif
else {
bh_memcpy_s(&(global->initial_value), sizeof(WASMValue),
&(init_expr->u), sizeof(init_expr->u));
@ -1216,6 +1231,10 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
switch (global->type) {
case VALUE_TYPE_I32:
case VALUE_TYPE_F32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_FUNCREF:
case VALUE_TYPE_EXTERNREF:
#endif
*(int32*)global_data = global->initial_value.i32;
global_data += sizeof(int32);
break;
@ -1285,13 +1304,18 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
.initial_value.i32;
}
/* check offset since length might negative */
/* check offset */
base_offset = (uint32)data_seg->base_offset.u.i32;
if (base_offset > memory_size) {
LOG_DEBUG("base_offset(%d) > memory_size(%d)", base_offset,
memory_size);
#if WASM_ENABLE_REF_TYPES != 0
set_error_buf(error_buf, error_buf_size,
"out of bounds memory access");
#else
set_error_buf(error_buf, error_buf_size,
"data segment does not fit");
#endif
goto fail;
}
@ -1300,8 +1324,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
if (base_offset + length > memory_size) {
LOG_DEBUG("base_offset(%d) + length(%d) > memory_size(%d)",
base_offset, length, memory_size);
#if WASM_ENABLE_REF_TYPES != 0
set_error_buf(error_buf, error_buf_size,
"out of bounds memory access");
#else
set_error_buf(error_buf, error_buf_size,
"data segment does not fit");
#endif
goto fail;
}
@ -1314,12 +1343,23 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
/* Initialize the table data with table segment section */
module_inst->default_table =
module_inst->table_count ? module_inst->tables[0] : NULL;
for (i = 0; i < module->table_seg_count; i++) {
/* in case there is no table */
for (i = 0; module_inst->table_count > 0 && i < module->table_seg_count;
i++) {
WASMTableSeg *table_seg = module->table_segments + i;
/* has check it in loader */
WASMTableInstance *table = module_inst->tables[table_seg->table_index];
bh_assert(table);
#if WASM_ENABLE_REF_TYPES != 0
if (table->elem_type != VALUE_TYPE_FUNCREF
&& table->elem_type != VALUE_TYPE_EXTERNREF) {
set_error_buf(error_buf, error_buf_size,
"elements segment does not fit");
goto fail;
}
#endif
uint32 *table_data = (uint32 *)table->base_addr;
#if WASM_ENABLE_MULTI_MODULE != 0
table_data = table->table_inst_linked
@ -1328,11 +1368,20 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
#endif
bh_assert(table_data);
/* init vec(funcidx) */
bh_assert(table_seg->base_offset.init_expr_type
== INIT_EXPR_TYPE_I32_CONST
|| table_seg->base_offset.init_expr_type
== INIT_EXPR_TYPE_GET_GLOBAL);
#if WASM_ENABLE_REF_TYPES != 0
if (!wasm_elem_is_active(table_seg->mode))
continue;
#endif
/* init vec(funcidx) or vec(expr) */
bh_assert(
table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST
|| table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL
#if WASM_ENABLE_REF_TYPES != 0
|| table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST
|| table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_REFNULL_CONST
#endif
);
if (table_seg->base_offset.init_expr_type
== INIT_EXPR_TYPE_GET_GLOBAL) {
@ -1349,6 +1398,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
"elements segment does not fit");
goto fail;
}
table_seg->base_offset.u.i32 =
globals[table_seg->base_offset.u.global_index].initial_value.i32;
}
@ -1357,8 +1407,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
if ((uint32)table_seg->base_offset.u.i32 > table->cur_size) {
LOG_DEBUG("base_offset(%d) > table->cur_size(%d)",
table_seg->base_offset.u.i32, table->cur_size);
#if WASM_ENABLE_REF_TYPES != 0
set_error_buf(error_buf, error_buf_size,
"out of bounds table access");
#else
set_error_buf(error_buf, error_buf_size,
"elements segment does not fit");
#endif
goto fail;
}
@ -1367,8 +1422,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
if ((uint32)table_seg->base_offset.u.i32 + length > table->cur_size) {
LOG_DEBUG("base_offset(%d) + length(%d)> table->cur_size(%d)",
table_seg->base_offset.u.i32, length, table->cur_size);
#if WASM_ENABLE_REF_TYPES != 0
set_error_buf(error_buf, error_buf_size,
"out of bounds table access");
#else
set_error_buf(error_buf, error_buf_size,
"elements segment does not fit");
#endif
goto fail;
}
@ -1510,6 +1570,10 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
if (module_inst->global_data)
wasm_runtime_free(module_inst->global_data);
#if WASM_ENABLE_REF_TYPES != 0
wasm_externref_cleanup((WASMModuleInstanceCommon*)module_inst);
#endif
wasm_runtime_free(module_inst);
}
@ -1616,8 +1680,16 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
}
#endif
#if WASM_ENABLE_REF_TYPES != 0
wasm_runtime_prepare_call_function(exec_env, func);
#endif
ret = wasm_call_function(exec_env, func, argc, argv);
#if WASM_ENABLE_REF_TYPES != 0
wasm_runtime_finalize_call_function(exec_env, func, ret, argv);
#endif
#if WASM_ENABLE_THREAD_MGR != 0
/* don't destroy the exec_env if it's searched from the cluster */
if (!existing_exec_env)
@ -2025,8 +2097,47 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
return true;
}
#if WASM_ENABLE_REF_TYPES != 0
bool
wasm_enlarge_table(WASMModuleInstance *module_inst,
uint32 table_idx, uint32 inc_entries, uint32 init_val)
{
uint32 entry_count, *new_table_data_start, i;
WASMTableInstance *table_inst;
if (!inc_entries) {
return true;
}
bh_assert(table_idx < module_inst->table_count);
table_inst = wasm_get_table_inst(module_inst, table_idx);
if (!table_inst) {
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) {
return false;
}
/* fill in */
new_table_data_start =
(uint32 *)((uint8 *)table_inst + offsetof(WASMTableInstance, base_addr))
+ table_inst->cur_size;
for (i = 0; i < inc_entries; ++i) {
new_table_data_start[i] = init_val;
}
table_inst->cur_size = entry_count;
return true;
}
#endif /* WASM_ENABLE_REF_TYPES != 0 */
bool
wasm_call_indirect(WASMExecEnv *exec_env,
uint32_t tbl_idx,
uint32_t element_indices,
uint32_t argc, uint32_t argv[])
{
@ -2039,7 +2150,7 @@ wasm_call_indirect(WASMExecEnv *exec_env,
(WASMModuleInstance*)exec_env->module_inst;
bh_assert(module_inst);
table_inst = module_inst->default_table;
table_inst = module_inst->tables[tbl_idx];
if (!table_inst) {
wasm_set_exception(module_inst, "unknown table");
goto got_exception;
@ -2055,7 +2166,7 @@ wasm_call_indirect(WASMExecEnv *exec_env,
* to another module's table
**/
function_indices = ((uint32_t*)table_inst->base_addr)[element_indices];
if (function_indices == 0xFFFFFFFF) {
if (function_indices == NULL_REF) {
wasm_set_exception(module_inst, "uninitialized element");
goto got_exception;
}
@ -2247,8 +2358,16 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst,
* module_inst->table_count;
for (i = 0; i < module_inst->table_count; i++) {
WASMTableInstance *table = module_inst->tables[i];
size = offsetof(WASMTableInstance, base_addr)
+ sizeof(uint32) * table->cur_size;
#if WASM_ENABLE_MULTI_MODULE != 0
if (table->table_inst_linked) {
size = offsetof(WASMTableInstance, base_addr);
}
else
#endif
{
size = offsetof(WASMTableInstance, base_addr)
+ sizeof(uint32) * table->cur_size;
}
mem_conspn->tables_size += size;
}

View File

@ -60,7 +60,7 @@ struct WASMMemoryInstance {
};
struct WASMTableInstance {
/* The element type, TABLE_ELEM_TYPE_ANY_FUNC currently */
/* The element type, VALUE_TYPE_FUNCREF/EXTERNREF currently */
uint8 elem_type;
/* Current size */
uint32 cur_size;
@ -376,6 +376,7 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count);
bool
wasm_call_indirect(WASMExecEnv *exec_env,
uint32_t tbl_idx,
uint32_t element_indices,
uint32_t argc, uint32_t argv[]);
@ -397,6 +398,45 @@ void
wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module,
WASMModuleInstMemConsumption *mem_conspn);
#if WASM_ENABLE_REF_TYPES != 0
static inline bool
wasm_elem_is_active(uint32 mode)
{
return (mode & 0x1) == 0x0;
}
static inline bool
wasm_elem_is_passive(uint32 mode)
{
return (mode & 0x1) == 0x1;
}
static inline bool
wasm_elem_is_declarative(uint32 mode)
{
return (mode & 0x3) == 0x3;
}
bool
wasm_enlarge_table(WASMModuleInstance *module_inst,
uint32 table_idx, uint32 inc_entries, uint32 init_val);
#endif /* WASM_ENABLE_REF_TYPES != 0 */
static inline WASMTableInstance *
wasm_get_table_inst(const WASMModuleInstance *module_inst,
const uint32 tbl_idx)
{
/* careful, it might be a table in another module */
WASMTableInstance *tbl_inst = module_inst->tables[tbl_idx];
#if WASM_ENABLE_MULTI_MODULE != 0
if (tbl_inst->table_inst_linked) {
tbl_inst = tbl_inst->table_inst_linked;
}
#endif
bh_assert(tbl_inst);
return tbl_inst;
}
#if WASM_ENABLE_DUMP_CALL_STACK != 0
void
wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env);

View File

@ -307,7 +307,8 @@ bh_hash_map_get_elem_struct_size()
}
bool
bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback)
bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback,
void *user_data)
{
uint32 index;
HashMapElem *elem, *next;
@ -325,7 +326,7 @@ bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback)
elem = map->elements[index];
while (elem) {
next = elem->next;
callback(elem->key, elem->value);
callback(elem->key, elem->value, user_data);
elem = next;
}
}

View File

@ -34,7 +34,7 @@ typedef void (*ValueDestroyFunc)(void *key);
/* traverse callback function:
auto called when traverse every hash element */
typedef void (*TraverseCallbackFunc)(void *key, void *value);
typedef void (*TraverseCallbackFunc)(void *key, void *value, void *user_data);
/**
* Create a hash map.
@ -150,14 +150,16 @@ bh_hash_map_get_elem_struct_size();
* Traverse the hash map and call the callback function
*
* @param map the hash map to traverse
* @callback the function to be called for every element
* @param callback the function to be called for every element
* @param user_data the argument to be passed to the callback function
*
* @return true if success, false otherwise
* Note: if the hash map has lock, the map will be locked during traverse,
* keep the callback function as simple as possible.
*/
bool
bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback);
bh_hash_map_traverse(HashMap *map, TraverseCallbackFunc callback,
void *user_data);
#ifdef __cplusplus
}

View File

@ -135,6 +135,9 @@ Currently we only profile the memory consumption of module, module_instance and
>
> and then use `cmake -DWAMR_BH_VPRINTF=my_vprintf ..` to pass the callback function, or add `BH_VPRINTF=my_vprintf` macro for the compiler, e.g. add line `add_defintions(-DBH_VPRINTF=my_vprintf)` in CMakeListst.txt.
#### **Enable reference types feature**
- **WAMR_BUILD_REF_TYPES**=1/0, default to disable if not set
**Combination of configurations:**
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:

View File

@ -85,7 +85,7 @@ The function signature field in **NativeSymbol** structure is a string for descr
Each letter in the "()" represents a parameter type, and the one following after ")" represents the return value type. The meaning of each letter:
- '**i**': i32
- '**i**': i32 or externref (for externref, developer should use `wasm_externref_obj2ref()` to map host object to externref index firstly)
- '**I**': i64
- '**f**': f32
- '**F**': f64

22
doc/ref_types.md Normal file
View File

@ -0,0 +1,22 @@
# WAMR reference-types introduction
WebAssembly [reference-types](https://github.com/WebAssembly/reference-types) proposal introduces the new type `externref` and makes it easier and more efficient to interoperate with host environment, allowing host references to be represented directly by type externref. And WASM modules can talk about host references directly, rather than requiring external glue code running in the host.
WAMR implements the reference-types proposal, allowing developer to pass the host object to WASM application and then restore and access the host object in native lib. In WAMR internal, the external host object is represented as externref index with `uint32` type, developer must firstly map the host object of `void *` type to the externref index, and then pass the index to the function to called as the function's externref argument.
Currently WAMR provides APIs as below:
```C
bool
wasm_externref_obj2ref(wasm_module_inst_t module_inst,
void *extern_obj, uint32_t *p_externref_idx);
WASM_RUNTIME_API_EXTERN bool
wasm_externref_ref2obj(uint32_t externref_idx, void **p_extern_obj);
WASM_RUNTIME_API_EXTERN bool
wasm_externref_retain(uint32 externref_idx);
```
The `wasm_externref_obj2ref()` API is used to map the host object to the externref index, and the `wasm_externref_ref2obj()` API is used to retrieve the original host object mapped. The `wasm_externref_retain()` API is to retain the host object if we don't want the object to be cleaned when it isn't used during externref object reclaim.
Please ref to the [sample](../samples/ref-types) for more details.

View File

@ -85,6 +85,11 @@ if (NOT DEFINED WAMR_BUILD_SIMD)
set (WAMR_BUILD_SIMD 1)
endif ()
if (NOT DEFINED WAMR_BUILD_REF_TYPES)
# Disable reference types by default
set (WAMR_BUILD_REF_TYPES 0)
endif ()
if (COLLECT_CODE_COVERAGE EQUAL 1)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
endif ()

View File

@ -0,0 +1,108 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required (VERSION 2.8)
if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows")
project(ref-types)
else()
project (ref-types C ASM)
enable_language (ASM_MASM)
endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
################ runtime settings ################
string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
if (APPLE)
add_definitions(-DBH_PLATFORM_DARWIN)
endif ()
# Resetdefault linker flags
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
# WAMR features switch
set(WAMR_BUILD_TARGET "X86_64")
if(NOT DEFINED WAMR_BUILD_INTERP)
set(WAMR_BUILD_INTERP 1)
endif()
if(NOT DEFINED WAMR_BUILD_AOT)
set(WAMR_BUILD_AOT 0)
endif()
if(NOT DEFINED WAMR_BUILD_JOT)
set(WAMR_BUILD_JIT 0)
endif()
if(NOT DEFINED WAMR_BUILD_FAST_INTERP)
set(WAMR_BUILD_FAST_INTERP 1)
endif()
if(NOT DEFINED WAMR_BUILD_LIBC_BUILTIN)
set(WAMR_BUILD_LIBC_BUILTIN 1)
endif()
# Enable reference-types feature
set(WAMR_BUILD_REF_TYPES 1)
if (NOT MSVC)
# compiling and linking flags
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE")
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
endif ()
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security")
if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register")
endif ()
endif ()
endif()
# build out vmlib
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
set(WAMRC ${WAMR_ROOT_DIR}/wamr-compiler/build/wamrc)
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE})
if (MSVC)
target_compile_definitions(vmlib PRIVATE WASM_API_EXTERN=)
endif()
################ application related ################
## locate wat2wasm
find_program(WAT2WASM
wat2wasm
PATHS /opt/wabt/bin
REQUIRED
)
if(NOT WAT2WASM)
message(SEND_ERROR "can not find wat2wasm")
endif()
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
add_executable(hello src/hello.c ${UNCOMMON_SHARED_SOURCE})
target_include_directories(hello PRIVATE ${UNCOMMON_SHARED_DIR})
target_link_libraries(hello vmlib -lpthread -lm)
if (MSVC)
target_compile_definitions(hello PRIVATE WASM_API_EXTERN=)
endif()
# wat to wasm
file(GLOB WAT_FILE src/hello.wat)
add_custom_target(hello_wasm ALL
COMMAND ${WAT2WASM} ${WAT_FILE} -o ${PROJECT_BINARY_DIR}/hello.wasm
DEPENDS ${WAT_FILE}
BYPRODUCTS ${PROJECT_BINARY_DIR}/hello.wasm
VERBATIM
SOURCES ${WAT_FILE}
)

View File

@ -0,0 +1,165 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_platform.h"
#include "bh_read_file.h"
#include "wasm_export.h"
#define USE_GLOBAL_HEAP_BUF 0
#if USE_GLOBAL_HEAP_BUF != 0
static char global_heap_buf[10 * 1024 * 1024] = { 0 };
#endif
static int
test_write_wrapper(wasm_exec_env_t exec_env,
uint32 externref_idx_of_file,
const char *str, int len)
{
FILE *file;
char buf[16];
printf("## retrieve file handle from externref index\n");
if (!wasm_externref_ref2obj(externref_idx_of_file, (void **)&file)) {
printf("failed to get host object from externref index!\n");
return -1;
}
snprintf(buf, sizeof(buf), "%%%ds", len);
printf("## write string to file: ");
printf(buf, str);
return fprintf(file, buf, str);
}
static NativeSymbol native_symbols[] = {
{ "test_write", test_write_wrapper, "(i*~)i", NULL }
};
int
main(int argc, char *argv[])
{
char *wasm_file = "hello.wasm";
uint8 *wasm_file_buf = NULL;
uint32 wasm_file_size, externref_idx;
uint32 stack_size = 16 * 1024, heap_size = 16 * 1024;
wasm_module_t wasm_module = NULL;
wasm_module_inst_t wasm_module_inst = NULL;
wasm_function_inst_t func_inst = NULL;
wasm_exec_env_t exec_env = NULL;
RuntimeInitArgs init_args;
char error_buf[128] = { 0 };
const char *exce;
unsigned argv1[8];
#if WASM_ENABLE_LOG != 0
int log_verbose_level = 2;
#endif
FILE *file;
memset(&init_args, 0, sizeof(RuntimeInitArgs));
#if USE_GLOBAL_HEAP_BUF != 0
init_args.mem_alloc_type = Alloc_With_Pool;
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
#else
init_args.mem_alloc_type = Alloc_With_Allocator;
init_args.mem_alloc_option.allocator.malloc_func = malloc;
init_args.mem_alloc_option.allocator.realloc_func = realloc;
init_args.mem_alloc_option.allocator.free_func = free;
#endif
init_args.n_native_symbols = sizeof(native_symbols) / sizeof(NativeSymbol);
init_args.native_module_name = "env";
init_args.native_symbols = native_symbols;
/* initialize runtime environment */
if (!wasm_runtime_full_init(&init_args)) {
printf("Init runtime environment failed.\n");
return -1;
}
#if WASM_ENABLE_LOG != 0
bh_log_set_verbose_level(log_verbose_level);
#endif
/* load WASM byte buffer from WASM bin file */
if (!(wasm_file_buf =
(uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size)))
goto fail1;
/* load WASM module */
if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size,
error_buf, sizeof(error_buf)))) {
printf("%s\n", error_buf);
goto fail2;
}
/* instantiate the module */
if (!(wasm_module_inst =
wasm_runtime_instantiate(wasm_module, stack_size, heap_size,
error_buf, sizeof(error_buf)))) {
printf("%s\n", error_buf);
goto fail3;
}
/* lookup function instance */
if (!(func_inst = wasm_runtime_lookup_function(wasm_module_inst,
"test", NULL))) {
printf("%s\n", "lookup function test failed");
goto fail4;
}
if (!(exec_env =
wasm_runtime_create_exec_env(wasm_module_inst, stack_size))) {
printf("%s\n", "create exec env failed");
goto fail4;
}
printf("## open file test.txt\n");
if (!(file = fopen("test.txt", "wb+"))) {
printf("%s\n", "open file text.txt failed");
goto fail5;
}
printf("## map file handle to externref index\n");
if (!wasm_externref_obj2ref(wasm_module_inst, file, &externref_idx)) {
printf("%s\n", "map host object to externref index failed");
goto fail6;
}
printf("## call wasm function with externref index\n");
argv1[0] = externref_idx;
wasm_runtime_call_wasm(exec_env, func_inst, 1, argv1);
if ((exce = wasm_runtime_get_exception(wasm_module_inst))) {
printf("Exception: %s\n", exce);
}
fail6:
fclose(file);
fail5:
/* destroy exec env */
wasm_runtime_destroy_exec_env(exec_env);
fail4:
/* destroy the module instance */
wasm_runtime_deinstantiate(wasm_module_inst);
fail3:
/* unload the module */
wasm_runtime_unload(wasm_module);
fail2:
/* free the file buffer */
wasm_runtime_free(wasm_file_buf);
fail1:
/* destroy runtime environment */
wasm_runtime_destroy();
return 0;
}

View File

@ -0,0 +1,22 @@
;; Copyright (C) 2019 Intel Corporation. All rights reserved.
;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
(module
;; import test_write function which is implemented by host
(import "env" "test_write"
(func $test_write (param externref i32 i32) (result i32)))
;; memory with one page (64KiB).
(memory (export "memory") 1)
(data (i32.const 0x8) "Hello, world!\n")
;; function that writes string to a given open file handle
(func (export "test") (param externref)
(local.get 0)
(i32.const 0x8)
(i32.const 14)
(call $test_write)
drop
)
)

View File

@ -31,6 +31,7 @@ add_definitions(-DWASM_ENABLE_SHARED_MEMORY=1)
add_definitions(-DWASM_ENABLE_THREAD_MGR=1)
add_definitions(-DWASM_ENABLE_TAIL_CALL=1)
add_definitions(-DWASM_ENABLE_SIMD=1)
add_definitions(-DWASM_ENABLE_REF_TYPES=1)
add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1)
add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1)
add_definitions(-DWASM_ENABLE_PERF_PROFILING=1)
@ -90,6 +91,10 @@ if (NOT CMAKE_BUILD_TYPE)
endif (NOT CMAKE_BUILD_TYPE)
message ("-- CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE})
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DBH_DEBUG=1)
endif ()
# Enable LLVM
set (LLVM_SRC_ROOT "${PROJECT_SOURCE_DIR}/../core/deps/llvm")
if (WAMR_BUILD_PLATFORM STREQUAL "windows")

View File

@ -9,6 +9,12 @@
#include "wasm_export.h"
#include "aot_export.h"
#if WASM_ENABLE_REF_TYPES != 0
extern void
wasm_set_ref_types_flag(bool enable);
#endif
static int
print_help()
{
@ -47,6 +53,7 @@ print_help()
printf(" currently 128-bit SIMD is only supported for x86-64 target,\n");
printf(" and by default it is enabled in x86-64 target and disabled\n");
printf(" in other targets\n");
printf(" --enable-ref-types Enable the post-MVP reference types feature\n");
printf(" --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n");
printf(" --enable-dump-call-stack Enable stack trace feature\n");
printf(" --enable-perf-profiling Enable function performance profiling\n");
@ -166,6 +173,9 @@ main(int argc, char *argv[])
else if (!strcmp(argv[0], "--disable-simd")) {
option.enable_simd = false;
}
else if (!strcmp(argv[0], "--enable-ref-types")) {
option.enable_ref_types = true;
}
else if (!strcmp(argv[0], "--disable-aux-stack-check")) {
option.enable_aux_stack_check = false;
}
@ -187,6 +197,10 @@ main(int argc, char *argv[])
option.is_sgx_platform = true;
}
#if WASM_ENABLE_REF_TYPES != 0
wasm_set_ref_types_flag(option.enable_ref_types);
#endif
wasm_file_name = argv[0];
memset(&init_args, 0, sizeof(RuntimeInitArgs));