Import reference-types feature (#612)

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

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang
2021-04-15 11:29:20 +08:00
committed by GitHub
parent 7706e4b151
commit 03d45f1d62
48 changed files with 5557 additions and 856 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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