mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-06 06:55:07 +00:00
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:
parent
7706e4b151
commit
03d45f1d62
10
README.md
10
README.md
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -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_ */
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 { \
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
487
core/iwasm/compilation/aot_emit_table.c
Normal file
487
core/iwasm/compilation/aot_emit_table.c
Normal 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 */
|
71
core/iwasm/compilation/aot_emit_table.h
Normal file
71
core/iwasm/compilation/aot_emit_table.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
22
doc/ref_types.md
Normal 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.
|
|
@ -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 ()
|
||||
|
|
108
samples/ref-types/CMakeLists.txt
Normal file
108
samples/ref-types/CMakeLists.txt
Normal 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}
|
||||
)
|
165
samples/ref-types/src/hello.c
Normal file
165
samples/ref-types/src/hello.c
Normal 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;
|
||||
}
|
22
samples/ref-types/src/hello.wat
Normal file
22
samples/ref-types/src/hello.wat
Normal 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
|
||||
)
|
||||
)
|
|
@ -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")
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue
Block a user