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:
@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user