Implement multi-module feature and bulk-memory feature (#271)
Refine wasm loader and aot loader Fix potential issue of os_mmap/os_munmap Update document
This commit is contained in:
@ -238,6 +238,15 @@ LOAD_I16(void *addr)
|
||||
goto out_of_bounds; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) do { \
|
||||
uint64 offset1 = (int32)(start); \
|
||||
if (offset1 + bytes <= linear_mem_size) \
|
||||
/* App heap space is not valid space for bulk memory operation */ \
|
||||
maddr = memory->memory_data + offset1; \
|
||||
else \
|
||||
goto out_of_bounds; \
|
||||
} while (0)
|
||||
|
||||
static inline uint32
|
||||
rotl32(uint32 n, uint32 c)
|
||||
{
|
||||
@ -815,6 +824,59 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
|
||||
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static void
|
||||
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
WASMExecEnv *exec_env,
|
||||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame);
|
||||
|
||||
static void
|
||||
wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||
WASMExecEnv *exec_env,
|
||||
WASMFunctionInstance *cur_func,
|
||||
WASMInterpFrame *prev_frame)
|
||||
{
|
||||
WASMModuleInstance *sub_module_inst = cur_func->import_module_inst;
|
||||
WASMFunctionInstance *sub_func_inst = cur_func->import_func_inst;
|
||||
WASMFunctionImport *func_import = cur_func->u.func_import;
|
||||
uint8 *ip = prev_frame->ip;
|
||||
char buf[128];
|
||||
|
||||
if (!sub_func_inst) {
|
||||
snprintf(buf, sizeof(buf),
|
||||
"fail to call unlinked import function (%s, %s)",
|
||||
func_import->module_name, func_import->field_name);
|
||||
wasm_set_exception(module_inst, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set ip NULL to make call_func_bytecode return after executing
|
||||
this function */
|
||||
prev_frame->ip = NULL;
|
||||
|
||||
/* replace exec_env's module_inst with sub_module_inst so we can
|
||||
call it */
|
||||
exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst;
|
||||
|
||||
/* call function of sub-module*/
|
||||
wasm_interp_call_func_bytecode(sub_module_inst, exec_env,
|
||||
sub_func_inst, prev_frame);
|
||||
|
||||
/* restore ip and module_inst */
|
||||
prev_frame->ip = ip;
|
||||
exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst;
|
||||
|
||||
/* transfer exception if it is thrown */
|
||||
if (wasm_get_exception(sub_module_inst)) {
|
||||
bh_memcpy_s(module_inst->cur_exception,
|
||||
sizeof(module_inst->cur_exception),
|
||||
sub_module_inst->cur_exception,
|
||||
sizeof(sub_module_inst->cur_exception));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_OPCODE_COUNTER != 0
|
||||
typedef struct OpcodeInfo {
|
||||
char *name;
|
||||
@ -894,6 +956,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
uint32 total_mem_size = memory ? num_bytes_per_page * memory->cur_page_count
|
||||
- heap_base_offset : 0;
|
||||
uint8 *global_data = module->global_data;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
uint32 linear_mem_size = memory ? num_bytes_per_page * memory->cur_page_count : 0;
|
||||
#endif
|
||||
WASMTableInstance *table = module->default_table;
|
||||
WASMGlobalInstance *globals = module->globals;
|
||||
uint8 opcode_IMPDEP = WASM_OP_IMPDEP;
|
||||
@ -997,6 +1062,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
HANDLE_OP (WASM_OP_CALL_INDIRECT):
|
||||
{
|
||||
WASMType *cur_type, *cur_func_type;
|
||||
WASMTableInstance *cur_table_inst;
|
||||
|
||||
tidx = GET_OPERAND(int32, 0);
|
||||
val = GET_OPERAND(int32, 2);
|
||||
@ -1008,21 +1074,41 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
}
|
||||
cur_type = module->module->types[tidx];
|
||||
|
||||
if (val < 0 || val >= (int32)table->cur_size) {
|
||||
/* 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) {
|
||||
wasm_set_exception(module, "undefined element");
|
||||
goto got_exception;
|
||||
}
|
||||
|
||||
fidx = ((uint32*)table->base_addr)[val];
|
||||
fidx = ((uint32*)cur_table_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) {
|
||||
wasm_set_exception(module, "unknown function");
|
||||
goto got_exception;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* always call module own functions */
|
||||
cur_func = module->functions + fidx;
|
||||
|
||||
if (cur_func->is_import_func)
|
||||
cur_func_type = cur_func->u.func_import->func_type;
|
||||
if (cur_func->is_import_func
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
&& !cur_func->import_func_inst
|
||||
#endif
|
||||
)
|
||||
cur_func_type = cur_func->u.func_import->func_type;
|
||||
else
|
||||
cur_func_type = cur_func->u.func->func_type;
|
||||
if (!wasm_type_equal(cur_type, cur_func_type)) {
|
||||
@ -1115,7 +1201,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
|
||||
bh_assert(global_idx < module->global_count);
|
||||
global = globals + global_idx;
|
||||
global_addr = global_data + global->data_offset;
|
||||
global_addr =
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
global->import_global_inst
|
||||
? global->import_module_inst->global_data
|
||||
+ global->import_global_inst->data_offset
|
||||
:
|
||||
#endif
|
||||
global_data + global->data_offset;
|
||||
|
||||
switch (global->type) {
|
||||
case VALUE_TYPE_I32:
|
||||
@ -1141,7 +1234,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
|
||||
bh_assert(global_idx < module->global_count);
|
||||
global = globals + global_idx;
|
||||
global_addr = global_data + global->data_offset;
|
||||
global_addr =
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
global->import_global_inst
|
||||
? global->import_module_inst->global_data
|
||||
+ global->import_global_inst->data_offset
|
||||
:
|
||||
#endif
|
||||
global_data + global->data_offset;
|
||||
|
||||
switch (global->type) {
|
||||
case VALUE_TYPE_I32:
|
||||
@ -1429,6 +1529,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
memory = module->default_memory;
|
||||
total_mem_size = num_bytes_per_page * memory->cur_page_count
|
||||
- heap_base_offset;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
||||
#endif
|
||||
}
|
||||
|
||||
(void)reserved;
|
||||
@ -2295,6 +2398,76 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
DEF_OP_TRUNC_SAT_F64(-1.0, 18446744073709551616.0,
|
||||
false, false);
|
||||
break;
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
case WASM_OP_MEMORY_INIT:
|
||||
{
|
||||
uint32 addr, segment;
|
||||
uint64 bytes, offset, seg_len;
|
||||
uint8* data;
|
||||
|
||||
segment = GET_OPERAND(uint32, 0);
|
||||
frame_ip += 2;
|
||||
|
||||
bytes = (uint64)POP_I32();
|
||||
offset = (uint64)POP_I32();
|
||||
addr = POP_I32();
|
||||
|
||||
CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
|
||||
|
||||
seg_len = (uint64)module->module->data_segments[segment]->data_length;
|
||||
data = module->module->data_segments[segment]->data;
|
||||
if (offset + bytes > seg_len)
|
||||
goto out_of_bounds;
|
||||
|
||||
bh_memcpy_s(maddr, linear_mem_size - addr,
|
||||
data + offset, bytes);
|
||||
break;
|
||||
}
|
||||
case WASM_OP_DATA_DROP:
|
||||
{
|
||||
uint32 segment;
|
||||
|
||||
segment = GET_OPERAND(uint32, 0);
|
||||
frame_ip += 2;
|
||||
|
||||
module->module->data_segments[segment]->data_length = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_COPY:
|
||||
{
|
||||
uint32 dst, src, len;
|
||||
uint8 *mdst, *msrc;
|
||||
|
||||
len = POP_I32();
|
||||
src = POP_I32();
|
||||
dst = POP_I32();
|
||||
|
||||
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
|
||||
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
|
||||
|
||||
/* allowing the destination and source to overlap */
|
||||
bh_memmove_s(mdst, linear_mem_size - dst,
|
||||
msrc, len);
|
||||
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_FILL:
|
||||
{
|
||||
uint32 dst, len;
|
||||
uint8 val, *mdst;
|
||||
|
||||
len = POP_I32();
|
||||
val = POP_I32();
|
||||
dst = POP_I32();
|
||||
|
||||
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
|
||||
|
||||
memset(mdst, val, len);
|
||||
|
||||
break;
|
||||
}
|
||||
#endif /* WASM_ENABLE_BULK_MEMORY */
|
||||
default:
|
||||
wasm_set_exception(module, "WASM interp failed: unsupported opcode.");
|
||||
goto got_exception;
|
||||
@ -2310,7 +2483,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
|
||||
HANDLE_OP (WASM_OP_CALL):
|
||||
fidx = frame_lp[GET_OFFSET()];
|
||||
bh_assert(fidx < module->function_count);
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (fidx >= module->function_count) {
|
||||
wasm_set_exception(module, "unknown function");
|
||||
goto got_exception;
|
||||
}
|
||||
#endif
|
||||
cur_func = module->functions + fidx;
|
||||
goto call_func_from_interp;
|
||||
|
||||
@ -2383,7 +2561,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
GET_OPERAND(int64, (2 * (cur_func->param_count - i - 1)));
|
||||
outs_area->lp += 2;
|
||||
} else {
|
||||
*(outs_area->lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1)));;
|
||||
*(outs_area->lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1)));
|
||||
outs_area->lp ++;
|
||||
}
|
||||
}
|
||||
@ -2397,14 +2575,25 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
call_func_from_entry:
|
||||
{
|
||||
if (cur_func->is_import_func) {
|
||||
wasm_interp_call_func_native(module, exec_env, cur_func, prev_frame);
|
||||
prev_frame = frame->prev_frame;
|
||||
cur_func = frame->function;
|
||||
UPDATE_ALL_FROM_FRAME();
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (cur_func->import_func_inst) {
|
||||
wasm_interp_call_func_import(module, exec_env, cur_func,
|
||||
prev_frame);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
wasm_interp_call_func_native(module, exec_env, cur_func,
|
||||
prev_frame);
|
||||
}
|
||||
|
||||
memory = module->default_memory;
|
||||
if (wasm_get_exception(module))
|
||||
goto got_exception;
|
||||
prev_frame = frame->prev_frame;
|
||||
cur_func = frame->function;
|
||||
UPDATE_ALL_FROM_FRAME();
|
||||
|
||||
memory = module->default_memory;
|
||||
if (wasm_get_exception(module))
|
||||
goto got_exception;
|
||||
}
|
||||
else {
|
||||
WASMFunction *cur_wasm_func = cur_func->u.func;
|
||||
@ -2528,10 +2717,28 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst,
|
||||
|
||||
wasm_exec_env_set_cur_frame(exec_env, frame);
|
||||
|
||||
if (function->is_import_func)
|
||||
wasm_interp_call_func_native(module_inst, exec_env, function, frame);
|
||||
else
|
||||
if (function->is_import_func) {
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (function->import_module_inst) {
|
||||
LOG_DEBUG("it is a function of a sub module");
|
||||
wasm_interp_call_func_import(module_inst,
|
||||
exec_env,
|
||||
function,
|
||||
frame);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LOG_DEBUG("it is an native function");
|
||||
wasm_interp_call_func_native(module_inst,
|
||||
exec_env,
|
||||
function,
|
||||
frame);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame);
|
||||
}
|
||||
|
||||
/* Output the return value to the caller */
|
||||
if (!wasm_get_exception(module_inst)) {
|
||||
|
||||
Reference in New Issue
Block a user