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:
wenyongh
2020-06-02 14:53:06 +08:00
committed by GitHub
parent e81f72d41f
commit 752826a667
57 changed files with 4902 additions and 818 deletions

View File

@ -363,6 +363,11 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
for (i = 0; i < module->mem_init_data_count; i++) {
uint32 init_expr_type, byte_count;
uint64 init_expr_value;
uint32 is_passive;
uint32 memory_index;
read_uint32(buf, buf_end, is_passive);
read_uint32(buf, buf_end, memory_index);
read_uint32(buf, buf_end, init_expr_type);
read_uint64(buf, buf_end, init_expr_value);
read_uint32(buf, buf_end, byte_count);
@ -375,6 +380,11 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
return false;
}
#if WASM_ENABLE_BULK_MEMORY != 0
/* is_passive and memory_index is only used in bulk memory mode */
data_list[i]->is_passive = (bool)is_passive;
data_list[i]->memory_index = memory_index;
#endif
data_list[i]->offset.init_expr_type = (uint8)init_expr_type;
data_list[i]->offset.u.i64 = (int64)init_expr_value;
data_list[i]->byte_count = byte_count;
@ -773,8 +783,7 @@ load_import_funcs(const uint8 **p_buf, const uint8 *buf_end,
read_uint16(buf, buf_end, import_funcs[i].func_type_index);
if (import_funcs[i].func_type_index >= module->func_type_count) {
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: "
"invalid function type index.");
"AOT module load failed: unknown type.");
return false;
}
import_funcs[i].func_type = module->func_types[import_funcs[i].func_type_index];
@ -1067,8 +1076,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
read_uint32(p, p_end, module->func_type_indexes[i]);
if (module->func_type_indexes[i] >= module->func_type_count) {
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: "
"invalid function type index.");
"AOT module load failed: unknown type.");
return false;
}
}

View File

@ -12,6 +12,30 @@ typedef struct {
#define REG_SYM(symbol) { #symbol, (void*)symbol }
#if WASM_ENABLE_BULK_MEMORY != 0
#define REG_COMMON_SYMBOLS \
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(fmin), \
REG_SYM(fminf), \
REG_SYM(fmax), \
REG_SYM(fmaxf), \
REG_SYM(ceil), \
REG_SYM(ceilf), \
REG_SYM(floor), \
REG_SYM(floorf), \
REG_SYM(trunc), \
REG_SYM(truncf), \
REG_SYM(rint), \
REG_SYM(rintf), \
REG_SYM(memset), \
REG_SYM(memmove), \
REG_SYM(aot_memory_init), \
REG_SYM(aot_data_drop)
#else
#define REG_COMMON_SYMBOLS \
REG_SYM(aot_set_exception_with_id), \
REG_SYM(aot_invoke_native), \
@ -30,6 +54,7 @@ typedef struct {
REG_SYM(truncf), \
REG_SYM(rint), \
REG_SYM(rintf)
#endif
#define CHECK_RELOC_OFFSET(data_size) do { \
if (!check_reloc_offset(target_section_size, reloc_offset, data_size, \

View File

@ -68,42 +68,62 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
uint32 i, global_index, global_data_offset, base_offset, length;
AOTTableInitData *table_seg;
if (module->table_init_data_count > 0) {
for (i = 0; i < module->table_init_data_count; i++) {
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);
for (i = 0; i < module->table_init_data_count; i++) {
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);
/* Resolve table data base offset */
if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
global_index = table_seg->offset.u.global_index;
bh_assert(global_index <
module->import_global_count + module->global_count);
/* TODO: && globals[table_seg->offset.u.global_index].type ==
VALUE_TYPE_I32*/
if (global_index < module->import_global_count)
global_data_offset =
module->import_globals[global_index].data_offset;
else
global_data_offset =
module->globals[global_index - module->import_global_count]
.data_offset;
base_offset = *(uint32*)
((uint8*)module_inst->global_data.ptr + global_data_offset);
}
/* Resolve table data base offset */
if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
global_index = table_seg->offset.u.global_index;
bh_assert(global_index <
module->import_global_count + module->global_count);
/* TODO: && globals[table_seg->offset.u.global_index].type ==
VALUE_TYPE_I32*/
if (global_index < module->import_global_count)
global_data_offset =
module->import_globals[global_index].data_offset;
else
base_offset = (uint32)table_seg->offset.u.i32;
global_data_offset =
module->globals[global_index - module->import_global_count]
.data_offset;
/* Copy table data */
length = table_seg->func_index_count;
if (base_offset < module_inst->table_size) {
memcpy((uint32*)module_inst->table_data.ptr + base_offset,
table_seg->func_indexes, length * sizeof(uint32));
}
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);
set_error_buf(error_buf, error_buf_size,
"elements segment does not fit");
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);
set_error_buf(error_buf, error_buf_size,
"elements segment does not fit");
return false;
}
/**
* 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));
}
return true;
@ -169,50 +189,64 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
module_inst->mem_bound_check_8bytes = module_inst->total_mem_size - 8;
}
if (module->mem_init_page_count > 0) {
for (i = 0; i < module->mem_init_data_count; i++) {
data_seg = module->mem_init_data_list[i];
bh_assert(data_seg->offset.init_expr_type ==
INIT_EXPR_TYPE_I32_CONST
|| data_seg->offset.init_expr_type ==
INIT_EXPR_TYPE_GET_GLOBAL);
for (i = 0; i < module->mem_init_data_count; i++) {
data_seg = module->mem_init_data_list[i];
#if WASM_ENABLE_BULK_MEMORY != 0
if (data_seg->is_passive)
continue;
#endif
/* Resolve memory data base offset */
if (data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
global_index = data_seg->offset.u.global_index;
bh_assert(global_index <
module->import_global_count + module->global_count);
/* TODO: && globals[data_seg->offset.u.global_index].type ==
VALUE_TYPE_I32*/
if (global_index < module->import_global_count)
global_data_offset =
module->import_globals[global_index].data_offset;
else
global_data_offset =
module->globals[global_index - module->import_global_count]
.data_offset;
bh_assert(data_seg->offset.init_expr_type ==
INIT_EXPR_TYPE_I32_CONST
|| data_seg->offset.init_expr_type ==
INIT_EXPR_TYPE_GET_GLOBAL);
base_offset = *(uint32*)
((uint8*)module_inst->global_data.ptr + global_data_offset);
}
/* Resolve memory data base offset */
if (data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) {
global_index = data_seg->offset.u.global_index;
bh_assert(global_index <
module->import_global_count + module->global_count);
/* TODO: && globals[data_seg->offset.u.global_index].type ==
VALUE_TYPE_I32*/
if (global_index < module->import_global_count)
global_data_offset =
module->import_globals[global_index].data_offset;
else
base_offset = (uint32)data_seg->offset.u.i32;
global_data_offset =
module->globals[global_index - module->import_global_count]
.data_offset;
length = data_seg->byte_count;
/* Check memory data */
if (length > 0
&& (base_offset >= module_inst->memory_data_size
|| base_offset + length > module_inst->memory_data_size)) {
set_error_buf(error_buf, error_buf_size,
"AOT module instantiate failed: data segment out of range.");
goto fail2;
}
/* Copy memory data */
memcpy((uint8*)module_inst->memory_data.ptr + base_offset,
data_seg->bytes, length);
base_offset = *(uint32*)
((uint8*)module_inst->global_data.ptr + global_data_offset);
} else {
base_offset = (uint32)data_seg->offset.u.i32;
}
/* Copy memory data */
bh_assert(module_inst->memory_data.ptr);
/* Check memory data */
/* check offset since length might negative */
if (base_offset > module_inst->memory_data_size) {
LOG_DEBUG("base_offset(%d) > memory_data_size(%d)", base_offset,
module_inst->memory_data_size);
set_error_buf(error_buf, error_buf_size,
"data segment does not fit");
goto fail2;
}
/* check offset + length(could be zero) */
length = data_seg->byte_count;
if (base_offset + length > module_inst->memory_data_size) {
LOG_DEBUG("base_offset(%d) + length(%d) > memory_data_size(%d)",
base_offset, length, module_inst->memory_data_size);
set_error_buf(error_buf, error_buf_size,
"data segment does not fit");
goto fail2;
}
memcpy((uint8*)module_inst->memory_data.ptr + base_offset,
data_seg->bytes, length);
}
return true;
@ -952,3 +986,61 @@ aot_call_indirect(WASMExecEnv *exec_env,
func_type, signature, attachment,
argv, argc, argv);
}
#if WASM_ENABLE_BULK_MEMORY != 0
bool
aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index,
uint32 offset, uint32 len, uint32 dst)
{
AOTModule *aot_module;
uint8 *data = NULL;
uint8 *maddr;
uint64 seg_len = 0;
aot_module = (AOTModule *)module_inst->aot_module.ptr;
if (aot_module->is_jit_mode) {
#if WASM_ENABLE_JIT != 0
seg_len = aot_module->wasm_module->data_segments[seg_index]->data_length;
data = aot_module->wasm_module->data_segments[seg_index]->data;
#endif
}
else {
seg_len = aot_module->mem_init_data_list[seg_index]->byte_count;
data = aot_module->mem_init_data_list[seg_index]->bytes;
}
if (!aot_validate_app_addr(module_inst, dst, len))
return false;
if ((uint64)offset + (uint64)len > seg_len) {
aot_set_exception(module_inst, "out of bounds memory access");
return false;
}
maddr = aot_addr_app_to_native(module_inst, dst);
bh_memcpy_s(maddr, module_inst->memory_data_size - dst,
data + offset, len);
return true;
}
bool
aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index)
{
AOTModule *aot_module = (AOTModule *)(module_inst->aot_module.ptr);
if (aot_module->is_jit_mode) {
#if WASM_ENABLE_JIT != 0
aot_module->wasm_module->data_segments[seg_index]->data_length = 0;
/* Currently we can't free the dropped data segment
as they are stored in wasm bytecode */
#endif
}
else {
aot_module->mem_init_data_list[seg_index]->byte_count = 0;
/* Currently we can't free the dropped data segment
as the mem_init_data_count is a continuous array */
}
return true;
}
#endif /* WASM_ENABLE_BULK_MEMORY */

View File

@ -458,6 +458,15 @@ aot_call_indirect(WASMExecEnv *exec_env,
uint32
aot_get_plt_table_size();
#if WASM_ENABLE_BULK_MEMORY != 0
bool
aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index,
uint32 offset, uint32 len, uint32 dst);
bool
aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index);
#endif
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -243,6 +243,7 @@ wasm_native_init()
if (!wasm_native_register_natives("env",
native_symbols, n_native_symbols))
return false;
#endif /* WASM_ENABLE_LIBC_BUILTIN */
#if WASM_ENABLE_SPEC_TEST
n_native_symbols = get_spectest_export_apis(&native_symbols);
@ -250,7 +251,6 @@ wasm_native_init()
native_symbols, n_native_symbols))
return false;
#endif /* WASM_ENABLE_SPEC_TEST */
#endif /* WASM_ENABLE_LIBC_BUILTIN */
#if WASM_ENABLE_LIBC_WASI != 0
n_native_symbols = get_libc_wasi_export_apis(&native_symbols);

View File

@ -16,6 +16,43 @@
#include "../aot/aot_runtime.h"
#endif
#if WASM_ENABLE_MULTI_MODULE != 0
/*
* a safety insurance to prevent
* circular depencies leading a stack overflow
* try break early
*/
typedef struct LoadingModule {
bh_list_link l;
/* point to a string pool */
const char *module_name;
} LoadingModule;
static bh_list loading_module_list_head;
static bh_list *const loading_module_list = &loading_module_list_head;
static korp_mutex loading_module_list_lock;
/*
* a list about all exported functions, globals, memories, tables of every
* fully loaded module
*/
static bh_list registered_module_list_head;
static bh_list *const registered_module_list = &registered_module_list_head;
static korp_mutex registered_module_list_lock;
static void
wasm_runtime_destroy_registered_module_list();
#endif /* WASM_ENABLE_MULTI_MODULE */
void
set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format,
...)
{
va_list args;
va_start(args, format);
vsnprintf(error_buf, error_buf_size, format, args);
va_end(args);
}
static void
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
{
@ -34,11 +71,25 @@ wasm_runtime_env_init()
return false;
}
#if WASM_ENABLE_MULTI_MODULE
if (BHT_OK != os_mutex_init(&registered_module_list_lock)) {
wasm_native_destroy();
bh_platform_destroy();
return false;
}
if (BHT_OK != os_mutex_init(&loading_module_list_lock)) {
os_mutex_destroy(&registered_module_list_lock);
wasm_native_destroy();
bh_platform_destroy();
return false;
}
#endif
return true;
}
static bool
wasm_runtime_env_check(WASMExecEnv *exec_env)
wasm_runtime_exec_env_check(WASMExecEnv *exec_env)
{
return !(!exec_env
|| !exec_env->module_inst
@ -65,8 +116,17 @@ wasm_runtime_init()
void
wasm_runtime_destroy()
{
/* runtime env destroy */
#if WASM_ENABLE_MULTI_MODULE
wasm_runtime_destroy_loading_module_list();
os_mutex_destroy(&loading_module_list_lock);
wasm_runtime_destroy_registered_module_list();
os_mutex_destroy(&registered_module_list_lock);
#endif
wasm_native_destroy();
bh_platform_destroy();
wasm_runtime_memory_destroy();
}
@ -105,10 +165,342 @@ get_package_type(const uint8 *buf, uint32 size)
return Package_Type_Unknown;
}
#if WASM_ENABLE_MULTI_MODULE != 0
static module_reader reader;
static module_destroyer destroyer;
void
wasm_runtime_set_module_reader(const module_reader reader_cb,
const module_destroyer destroyer_cb)
{
reader = reader_cb;
destroyer = destroyer_cb;
}
module_reader
wasm_runtime_get_module_reader()
{
return reader;
}
module_destroyer
wasm_runtime_get_module_destroyer()
{
return destroyer;
}
static WASMRegisteredModule *
wasm_runtime_find_module_registered_by_reference(WASMModuleCommon *module)
{
WASMRegisteredModule *reg_module = NULL;
os_mutex_lock(&registered_module_list_lock);
reg_module = bh_list_first_elem(registered_module_list);
while (reg_module && module != reg_module->module) {
reg_module = bh_list_elem_next(reg_module);
}
os_mutex_unlock(&registered_module_list_lock);
return reg_module;
}
bool
wasm_runtime_register_module_internal(const char *module_name,
WASMModuleCommon *module,
uint8 *orig_file_buf,
uint32 orig_file_buf_size,
char *error_buf,
uint32_t error_buf_size)
{
WASMRegisteredModule *node = NULL;
node = wasm_runtime_find_module_registered_by_reference(module);
if (node) { /* module has been registered */
if (node->module_name) { /* module has name */
if (strcmp(node->module_name, module_name)) {
/* module has different name */
LOG_DEBUG("module(%p) has been registered with name %s",
module, node->module_name);
set_error_buf_v(error_buf, error_buf_size,
"can not rename the module");
return false;
}
else {
/* module has the same name */
LOG_DEBUG("module(%p) has been registered with the same name %s",
module, node->module_name);
return true;
}
}
else {
/* module has empyt name, reset it */
node->module_name = module_name;
return true;
}
}
/* module hasn't been registered */
node = wasm_runtime_malloc(sizeof(WASMRegisteredModule));
if (!node) {
LOG_DEBUG("malloc WASMRegisteredModule failed. SZ=%d",
sizeof(WASMRegisteredModule));
set_error_buf_v(error_buf, error_buf_size,
"malloc WASMRegisteredModule failed. SZ=%d",
sizeof(WASMRegisteredModule));
return false;
}
/* share the string and the module */
node->module_name = module_name;
node->module = module;
node->orig_file_buf = orig_file_buf;
node->orig_file_buf_size = orig_file_buf_size;
os_mutex_lock(&registered_module_list_lock);
bh_list_status ret = bh_list_insert(registered_module_list, node);
bh_assert(BH_LIST_SUCCESS == ret);
(void)ret;
os_mutex_unlock(&registered_module_list_lock);
return true;
}
bool
wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module,
char *error_buf, uint32_t error_buf_size)
{
if (!error_buf || !error_buf_size) {
LOG_ERROR("error buffer is required");
return false;
}
if (!module_name || !module) {
LOG_DEBUG("module_name and module are required");
set_error_buf_v(error_buf, error_buf_size,
"module_name and module are required");
return false;
}
if (wasm_runtime_is_built_in_module(module_name)) {
LOG_DEBUG("%s is a built-in module name", module_name);
set_error_buf(error_buf, error_buf_size,
"can not register as a built-in module");
return false;
}
return wasm_runtime_register_module_internal(
module_name, module, NULL, 0,
error_buf, error_buf_size);
}
void
wasm_runtime_unregister_module(const WASMModuleCommon *module)
{
WASMRegisteredModule *registered_module = NULL;
os_mutex_lock(&registered_module_list_lock);
registered_module = bh_list_first_elem(registered_module_list);
while (registered_module && module != registered_module->module) {
registered_module = bh_list_elem_next(registered_module);
}
/* it does not matter if it is not exist. after all, it is gone */
if (registered_module) {
bh_list_remove(registered_module_list, registered_module);
wasm_runtime_free(registered_module);
}
os_mutex_unlock(&registered_module_list_lock);
}
WASMModuleCommon *
wasm_runtime_find_module_registered(const char *module_name)
{
WASMRegisteredModule *module = NULL, *module_next;
os_mutex_lock(&registered_module_list_lock);
module = bh_list_first_elem(registered_module_list);
while (module) {
module_next = bh_list_elem_next(module);
if (module->module_name
&& !strcmp(module_name, module->module_name)) {
break;
}
module = module_next;
}
os_mutex_unlock(&registered_module_list_lock);
return module ? module->module : NULL;
}
bool
wasm_runtime_is_module_registered(const char *module_name)
{
return NULL != wasm_runtime_find_module_registered(module_name);
}
/*
* simply destroy all
*/
static void
wasm_runtime_destroy_registered_module_list()
{
WASMRegisteredModule *reg_module = NULL;
os_mutex_lock(&registered_module_list_lock);
reg_module = bh_list_first_elem(registered_module_list);
while (reg_module) {
WASMRegisteredModule *next_reg_module = bh_list_elem_next(reg_module);
bh_list_remove(registered_module_list, reg_module);
/* now, it is time to release every module in the runtime */
#if WASM_ENABLE_INTERP != 0
if (reg_module->module->module_type == Wasm_Module_Bytecode)
wasm_unload((WASMModule *)reg_module->module);
#endif
#if WASM_ENABLE_AOT != 0
if (reg_module->module->module_type == Wasm_Module_AoT)
aot_unload((AOTModule *)reg_module->module);
#endif
/* destroy the file buffer */
if (destroyer && reg_module->orig_file_buf) {
destroyer(reg_module->orig_file_buf,
reg_module->orig_file_buf_size);
reg_module->orig_file_buf = NULL;
reg_module->orig_file_buf_size = 0;
}
wasm_runtime_free(reg_module);
reg_module = next_reg_module;
}
os_mutex_unlock(&registered_module_list_lock);
}
bool
wasm_runtime_add_loading_module(const char *module_name, char *error_buf,
uint32 error_buf_size)
{
LOG_DEBUG("add %s into a loading list", module_name);
LoadingModule *loadingModule = wasm_runtime_malloc(sizeof(LoadingModule));
if (!loadingModule) {
set_error_buf_v(error_buf, error_buf_size,
"malloc LoadingModule failed. SZ=%d",
sizeof(LoadingModule));
return false;
}
/* share the incoming string */
loadingModule->module_name = module_name;
os_mutex_lock(&loading_module_list_lock);
bh_list_status ret = bh_list_insert(loading_module_list, loadingModule);
bh_assert(BH_LIST_SUCCESS == ret);
(void)ret;
os_mutex_unlock(&loading_module_list_lock);
return true;
}
void
wasm_runtime_delete_loading_module(const char *module_name)
{
LOG_DEBUG("delete %s from a loading list", module_name);
LoadingModule *module = NULL;
os_mutex_lock(&loading_module_list_lock);
module = bh_list_first_elem(loading_module_list);
while (module && strcmp(module->module_name, module_name)) {
module = bh_list_elem_next(module);
}
/* it does not matter if it is not exist. after all, it is gone */
if (module) {
bh_list_remove(loading_module_list, module);
wasm_runtime_free(module);
}
os_mutex_unlock(&loading_module_list_lock);
}
bool
wasm_runtime_is_loading_module(const char *module_name)
{
LOG_DEBUG("find %s in a loading list", module_name);
LoadingModule *module = NULL;
os_mutex_lock(&loading_module_list_lock);
module = bh_list_first_elem(loading_module_list);
while (module && strcmp(module_name, module->module_name)) {
module = bh_list_elem_next(module);
}
os_mutex_unlock(&loading_module_list_lock);
return module != NULL;
}
void
wasm_runtime_destroy_loading_module_list()
{
LoadingModule *module = NULL;
os_mutex_lock(&loading_module_list_lock);
module = bh_list_first_elem(loading_module_list);
while (module) {
LoadingModule *next_module = bh_list_elem_next(module);
bh_list_remove(loading_module_list, module);
/*
* will not free the module_name since it is
* shared one of the const string pool
*/
wasm_runtime_free(module);
module = next_module;
}
os_mutex_unlock(&loading_module_list_lock);
}
#endif /* WASM_ENABLE_MULTI_MODULE */
bool
wasm_runtime_is_built_in_module(const char *module_name)
{
return (!strcmp("env", module_name)
|| !strcmp("wasi_unstable", module_name)
|| !strcmp("wasi_snapshot_preview1", module_name)
|| !strcmp("spectest", module_name)
);
}
static WASMModuleCommon *
register_module_with_null_name(WASMModuleCommon *module_common,
char *error_buf, uint32 error_buf_size)
{
#if WASM_ENABLE_MULTI_MODULE != 0
if (module_common) {
if (!wasm_runtime_register_module_internal(NULL, module_common,
NULL, 0,
error_buf,
error_buf_size)) {
wasm_runtime_unload(module_common);
return NULL;
}
return module_common;
}
else
return NULL;
#else
return module_common;
#endif
}
WASMModuleCommon *
wasm_runtime_load(const uint8 *buf, uint32 size,
char *error_buf, uint32 error_buf_size)
{
WASMModuleCommon *module_common = NULL;
if (get_package_type(buf, size) == Wasm_Module_Bytecode) {
#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0
AOTModule *aot_module;
@ -121,18 +513,24 @@ wasm_runtime_load(const uint8 *buf, uint32 size,
wasm_unload(module);
return NULL;
}
return (WASMModuleCommon*)aot_module;
module_common = (WASMModuleCommon*)aot_module;
return register_module_with_null_name(module_common,
error_buf, error_buf_size);
#elif WASM_ENABLE_INTERP != 0
return (WASMModuleCommon*)
module_common = (WASMModuleCommon*)
wasm_load(buf, size, error_buf, error_buf_size);
return register_module_with_null_name(module_common,
error_buf, error_buf_size);
#endif
}
else if (get_package_type(buf, size) == Wasm_Module_AoT) {
#if WASM_ENABLE_AOT != 0
return (WASMModuleCommon*)
module_common = (WASMModuleCommon*)
aot_load_from_aot_file(buf, size, error_buf, error_buf_size);
#endif /* end of WASM_ENABLE_AOT */
return register_module_with_null_name(module_common,
error_buf, error_buf_size);
#endif
}
if (size < 4)
@ -148,17 +546,25 @@ WASMModuleCommon *
wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
char *error_buf, uint32_t error_buf_size)
{
WASMModuleCommon *module_common;
#if WASM_ENABLE_INTERP != 0
if (!is_aot)
return (WASMModuleCommon*)
if (!is_aot) {
module_common = (WASMModuleCommon*)
wasm_load_from_sections(section_list,
error_buf, error_buf_size);
return register_module_with_null_name(module_common,
error_buf, error_buf_size);
}
#endif
#if WASM_ENABLE_AOT != 0
if (is_aot)
return (WASMModuleCommon*)
if (is_aot) {
module_common = (WASMModuleCommon*)
aot_load_from_sections(section_list,
error_buf, error_buf_size);
return register_module_with_null_name(module_common,
error_buf, error_buf_size);
}
#endif
set_error_buf(error_buf, error_buf_size,
@ -169,12 +575,21 @@ wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
void
wasm_runtime_unload(WASMModuleCommon *module)
{
#if WASM_ENABLE_MULTI_MODULE != 0
/**
* since we will unload and free all module when runtime_destroy()
* we don't want users to unwillingly disrupt it
*/
return;
#endif
#if WASM_ENABLE_INTERP != 0
if (module->module_type == Wasm_Module_Bytecode) {
wasm_unload((WASMModule*)module);
return;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module->module_type == Wasm_Module_AoT) {
aot_unload((AOTModule*)module);
@ -285,9 +700,9 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon * const module_inst,
bool
wasm_runtime_call_wasm(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
unsigned argc, uint32 argv[])
uint32 argc, uint32 argv[])
{
if (!wasm_runtime_env_check(exec_env)) {
if (!wasm_runtime_exec_env_check(exec_env)) {
LOG_ERROR("Invalid exec env stack info.");
return false;
}
@ -313,7 +728,7 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
bool
wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst,
WASMFunctionInstanceCommon *function,
unsigned argc, uint32 argv[])
uint32 argc, uint32 argv[])
{
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode)
@ -1077,7 +1492,7 @@ check_main_func_type(const WASMType *type)
bool
wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
int argc, char *argv[])
int32 argc, char *argv[])
{
WASMFunctionInstanceCommon *func;
WASMType *func_type = NULL;
@ -1165,6 +1580,54 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
argc1, argv1);
}
#if WASM_ENABLE_MULTI_MODULE != 0
static WASMModuleInstance *
get_sub_module_inst(const WASMModuleInstance *parent_module_inst,
const char *sub_module_name)
{
WASMSubModInstNode *node =
bh_list_first_elem(parent_module_inst->sub_module_inst_list);
while (node && strcmp(node->module_name, sub_module_name)) {
node = bh_list_elem_next(node);
}
return node ? node->module_inst : NULL;
}
static bool
parse_function_name(char *orig_function_name, char **p_module_name,
char **p_function_name)
{
if (orig_function_name[0] != '$') {
*p_module_name = NULL;
*p_function_name = orig_function_name;
return true;
}
/**
* $module_name$function_name\0
* ===>
* module_name\0function_name\0
* ===>
* module_name
* function_name
*/
char *p1 = orig_function_name;
char *p2 = strchr(p1 + 1, '$');
if (!p2) {
LOG_DEBUG("can not parse the incoming function name");
return false;
}
*p_module_name = p1 + 1;
*p2 = '\0';
*p_function_name = p2 + 1;
return strlen(*p_module_name) && strlen(*p_function_name);
}
#endif
/**
* Implementation of wasm_application_execute_func()
*/
@ -1173,32 +1636,76 @@ static WASMFunctionInstanceCommon*
resolve_function(const WASMModuleInstanceCommon *module_inst,
const char *name)
{
uint32 i;
uint32 i = 0;
WASMFunctionInstanceCommon *ret = NULL;
#if WASM_ENABLE_MULTI_MODULE != 0
WASMModuleInstance *sub_module_inst = NULL;
char *orig_name = NULL;
char *sub_module_name = NULL;
char *function_name = NULL;
uint32 length = strlen(name) + 1;
orig_name = wasm_runtime_malloc(sizeof(char) * length);
if (!orig_name) {
return NULL;
}
memset(orig_name, 0, sizeof(char) * length);
strncpy(orig_name, name, length);
if (!parse_function_name(orig_name, &sub_module_name, &function_name)) {
goto LEAVE;
}
LOG_DEBUG("%s -> %s and %s", name, sub_module_name, function_name);
if (sub_module_name) {
sub_module_inst = get_sub_module_inst(
(WASMModuleInstance *)module_inst, sub_module_name);
if (!sub_module_inst) {
LOG_DEBUG("can not find a sub module named %s", sub_module_name);
goto LEAVE;
}
}
#else
const char *function_name = name;
#endif
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
WASMModuleInstance *wasm_inst = (WASMModuleInstance*)module_inst;
#if WASM_ENABLE_MULTI_MODULE != 0
wasm_inst = sub_module_inst ? sub_module_inst : wasm_inst;
#endif /* WASM_ENABLE_MULTI_MODULE */
for (i = 0; i < wasm_inst->export_func_count; i++) {
if (!strcmp(wasm_inst->export_functions[i].name, name))
return wasm_inst->export_functions[i].function;
if (!strcmp(wasm_inst->export_functions[i].name, function_name)) {
ret = wasm_inst->export_functions[i].function;
break;
}
}
return NULL;
}
#endif
#endif /* WASM_ENABLE_INTERP */
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
AOTModuleInstance *aot_inst = (AOTModuleInstance*)module_inst;
AOTModule *module = (AOTModule*)aot_inst->aot_module.ptr;
for (i = 0; i < module->export_func_count; i++) {
if (!strcmp(module->export_funcs[i].func_name, name))
return (WASMFunctionInstance*)&module->export_funcs[i];
if (!strcmp(module->export_funcs[i].func_name, function_name)) {
ret = (WASMFunctionInstance*)&module->export_funcs[i];
break;
}
}
return NULL;
}
#endif
return NULL;
#if WASM_ENABLE_MULTI_MODULE != 0
LEAVE:
wasm_runtime_free(orig_name);
#endif
return ret;
}
union ieee754_float {
@ -1251,7 +1758,7 @@ static union {
bool
wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
const char *name, int argc, char *argv[])
const char *name, int32 argc, char *argv[])
{
WASMFunctionInstanceCommon *func;
WASMType *type = NULL;
@ -1262,6 +1769,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
char buf[128];
bh_assert(argc >= 0);
LOG_DEBUG("call a function \"%s\" with %d arguments", name, argc);
func = resolve_function(module_inst, name);
if (!func) {
@ -1273,7 +1781,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
WASMFunctionInstance *wasm_func = (WASMFunctionInstance*)func;
if (wasm_func->is_import_func) {
if (wasm_func->is_import_func
#if WASM_ENABLE_MULTI_MODULE != 0
&& !wasm_func->import_func_inst
#endif
) {
snprintf(buf, sizeof(buf), "lookup function %s failed.", name);
wasm_runtime_set_exception(module_inst, buf);
goto fail;
@ -2146,7 +2658,7 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env,
uint32_t element_indices,
uint32_t argc, uint32_t argv[])
{
if (!wasm_runtime_env_check(exec_env)) {
if (!wasm_runtime_exec_env_check(exec_env)) {
LOG_ERROR("Invalid exec env stack info.");
return false;
}

View File

@ -21,7 +21,6 @@
extern "C" {
#endif
typedef struct WASMModuleCommon {
/* Module type, for module loaded from WASM bytecode binary,
this field is Wasm_Module_Bytecode, and this structure should
@ -56,9 +55,25 @@ typedef struct WASIContext {
} WASIContext;
#endif
#if WASM_ENABLE_MULTI_MODULE != 0
typedef struct WASMRegisteredModule {
bh_list_link l;
/* point to a string pool */
const char *module_name;
WASMModuleCommon *module;
/* to store the original module file buffer address */
uint8 *orig_file_buf;
uint32 orig_file_buf_size;
} WASMRegisteredModule;
#endif
typedef package_type_t PackageType;
typedef wasm_section_t WASMSection, AOTSection;
void
set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format,
...);
/* See wasm_export.h for description */
bool
wasm_runtime_init();
@ -75,6 +90,7 @@ wasm_runtime_destroy();
PackageType
get_package_type(const uint8 *buf, uint32 size);
/* See wasm_export.h for description */
WASMModuleCommon *
wasm_runtime_load(const uint8 *buf, uint32 size,
@ -83,7 +99,7 @@ wasm_runtime_load(const uint8 *buf, uint32 size,
/* See wasm_export.h for description */
WASMModuleCommon *
wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
char *error_buf, uint32_t error_buf_size);
char *error_buf, uint32 error_buf_size);
/* See wasm_export.h for description */
void
@ -119,21 +135,21 @@ wasm_runtime_get_module_inst(WASMExecEnv *exec_env);
/* See wasm_export.h for description */
void *
wasm_runtime_get_function_attachment(wasm_exec_env_t exec_env);
wasm_runtime_get_function_attachment(WASMExecEnv *exec_env);
/* See wasm_export.h for description */
void
wasm_runtime_set_user_data(wasm_exec_env_t exec_env, void *user_data);
wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data);
/* See wasm_export.h for description */
void *
wasm_runtime_get_user_data(wasm_exec_env_t exec_env);
wasm_runtime_get_user_data(WASMExecEnv *exec_env);
/* See wasm_export.h for description */
bool
wasm_runtime_call_wasm(WASMExecEnv *exec_env,
WASMFunctionInstanceCommon *function,
unsigned argc, uint32 argv[]);
uint32 argc, uint32 argv[]);
/**
* Call a function reference of a given WASM runtime instance with
@ -154,23 +170,23 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env,
*/
bool
wasm_runtime_call_indirect(WASMExecEnv *exec_env,
uint32_t element_indices,
uint32_t argc, uint32_t argv[]);
uint32 element_indices,
uint32 argc, uint32 argv[]);
bool
wasm_runtime_create_exec_env_and_call_wasm(WASMModuleInstanceCommon *module_inst,
WASMFunctionInstanceCommon *function,
unsigned argc, uint32 argv[]);
uint32 argc, uint32 argv[]);
/* See wasm_export.h for description */
bool
wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
int argc, char *argv[]);
int32 argc, char *argv[]);
/* See wasm_export.h for description */
bool
wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
const char *name, int argc, char *argv[]);
const char *name, int32 argc, char *argv[]);
/* See wasm_export.h for description */
void
@ -261,6 +277,48 @@ void
wasm_runtime_set_llvm_stack(WASMModuleInstanceCommon *module_inst,
uint32 llvm_stack);
#if WASM_ENABLE_MULTI_MODULE != 0
void
wasm_runtime_set_module_reader(const module_reader reader,
const module_destroyer destroyer);
module_reader
wasm_runtime_get_module_reader();
module_destroyer
wasm_runtime_get_module_destroyer();
bool
wasm_runtime_register_module_internal(const char *module_name,
WASMModuleCommon *module,
uint8 *orig_file_buf,
uint32 orig_file_buf_size,
char *error_buf,
uint32 error_buf_size);
void
wasm_runtime_unregister_module(const WASMModuleCommon *module);
bool
wasm_runtime_is_module_registered(const char *module_name);
bool
wasm_runtime_add_loading_module(const char *module_name,
char *error_buf, uint32 error_buf_size);
void
wasm_runtime_delete_loading_module(const char *module_name);
bool
wasm_runtime_is_loading_module(const char *module_name);
void
wasm_runtime_destroy_loading_module_list();
#endif /* WASM_ENALBE_MULTI_MODULE */
bool
wasm_runtime_is_built_in_module(const char *module_name);
#if WASM_ENABLE_LIBC_WASI != 0
/* See wasm_export.h for description */
void

View File

@ -60,6 +60,10 @@ aot_create_mem_init_data_list(const WASMModule *module)
goto fail;
}
#if WASM_ENABLE_BULK_MEMORY != 0
data_list[i]->is_passive = module->data_segments[i]->is_passive;
data_list[i]->memory_index = module->data_segments[i]->memory_index;
#endif
data_list[i]->offset = module->data_segments[i]->base_offset;
data_list[i]->byte_count = module->data_segments[i]->data_length;
memcpy(data_list[i]->bytes, module->data_segments[i]->data,

View File

@ -24,6 +24,12 @@ typedef WASMType AOTFuncType;
* A segment of memory init data
*/
typedef struct AOTMemInitData {
#if WASM_ENABLE_BULK_MEMORY != 0
/* Passive flag */
bool is_passive;
/* memory index */
uint32 memory_index;
#endif
/* Start address of init data */
AOTInitExpr offset;
/* Byte count */

View File

@ -741,6 +741,39 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
if (!aot_compile_op_i64_trunc_f64(comp_ctx, func_ctx, sign, true))
return false;
break;
#if WASM_ENABLE_BULK_MEMORY != 0
case WASM_OP_MEMORY_INIT:
{
uint32 seg_index;
read_leb_uint32(frame_ip, frame_ip_end, seg_index);
frame_ip ++;
if (!aot_compile_op_memory_init(comp_ctx, func_ctx, seg_index))
return false;
break;
}
case WASM_OP_DATA_DROP:
{
uint32 seg_index;
read_leb_uint32(frame_ip, frame_ip_end, seg_index);
if (!aot_compile_op_data_drop(comp_ctx, func_ctx, seg_index))
return false;
break;
}
case WASM_OP_MEMORY_COPY:
{
frame_ip += 2;
if (!aot_compile_op_memory_copy(comp_ctx, func_ctx))
return false;
break;
}
case WASM_OP_MEMORY_FILL:
{
frame_ip ++;
if (!aot_compile_op_memory_fill(comp_ctx, func_ctx))
return false;
break;
}
#endif /* WASM_ENABLE_BULK_MEMORY */
default:
break;
}

View File

@ -124,8 +124,18 @@ get_mem_init_data_size(AOTMemInitData *mem_init_data)
{
/* init expr type (4 bytes) + init expr value (8 bytes)
+ byte count (4 bytes) + bytes */
return (uint32)(sizeof(uint32) + sizeof(uint64)
+ sizeof(uint32) + mem_init_data->byte_count);
uint32 total_size =
(uint32)(sizeof(uint32) + sizeof(uint64)
+ sizeof(uint32) + mem_init_data->byte_count);
/* bulk_memory enabled:
is_passive (4 bytes) + memory_index (4 bytes)
bulk memory disabled:
placeholder (4 bytes) + placeholder (4 bytes)
*/
total_size += (sizeof(uint32) + sizeof(uint32));
return total_size;
}
static uint32
@ -682,7 +692,8 @@ get_relocation_section_size(AOTObjectData *obj_data)
}
static uint32
get_aot_file_size(AOTCompData *comp_data, AOTObjectData *obj_data)
get_aot_file_size(AOTCompContext *comp_ctx, AOTCompData *comp_data,
AOTObjectData *obj_data)
{
uint32 size = 0;
@ -868,7 +879,8 @@ aot_emit_target_info_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
static bool
aot_emit_mem_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
AOTCompData *comp_data, AOTObjectData *obj_data)
AOTCompContext *comp_ctx, AOTCompData *comp_data,
AOTObjectData *obj_data)
{
uint32 offset = *p_offset, i;
AOTMemInitData **init_datas = comp_data->mem_init_data_list;
@ -882,6 +894,18 @@ aot_emit_mem_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
for (i = 0; i < comp_data->mem_init_data_count; i++) {
offset = align_uint(offset, 4);
#if WASM_ENABLE_BULK_MEMORY != 0
if (comp_ctx->enable_bulk_memory) {
EMIT_U32(init_datas[i]->is_passive);
EMIT_U32(init_datas[i]->memory_index);
}
else
#endif
{
/* emit two placeholder to keep the same size */
EMIT_U32(0);
EMIT_U32(0);
}
EMIT_U32(init_datas[i]->offset.init_expr_type);
EMIT_U64(init_datas[i]->offset.u.i64);
EMIT_U32(init_datas[i]->byte_count);
@ -1077,7 +1101,8 @@ aot_emit_object_data_section_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
static bool
aot_emit_init_data_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
AOTCompData *comp_data, AOTObjectData *obj_data)
AOTCompContext *comp_ctx, AOTCompData *comp_data,
AOTObjectData *obj_data)
{
uint32 section_size = get_init_data_section_size(comp_data, obj_data);
uint32 offset = *p_offset;
@ -1087,7 +1112,7 @@ aot_emit_init_data_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
EMIT_U32(AOT_SECTION_TYPE_INIT_DATA);
EMIT_U32(section_size);
if (!aot_emit_mem_info(buf, buf_end, &offset, comp_data, obj_data)
if (!aot_emit_mem_info(buf, buf_end, &offset, comp_ctx, comp_data, obj_data)
|| !aot_emit_table_info(buf, buf_end, &offset, comp_data, obj_data)
|| !aot_emit_func_type_info(buf, buf_end, &offset, comp_data, obj_data)
|| !aot_emit_import_global_info(buf, buf_end, &offset, comp_data, obj_data)
@ -1405,7 +1430,8 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
obj_data->target_info.bin_type = bin_type - LLVMBinaryTypeELF32L;
if (bin_type == LLVMBinaryTypeELF32L || bin_type == LLVMBinaryTypeELF32B) {
if (bin_type == LLVMBinaryTypeELF32L
|| bin_type == LLVMBinaryTypeELF32B) {
struct elf32_ehdr *elf_header;
bool is_little_bin = bin_type == LLVMBinaryTypeELF32L;
@ -1420,7 +1446,8 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
SET_TARGET_INFO(e_version, e_version, uint32, is_little_bin);
SET_TARGET_INFO(e_flags, e_flags, uint32, is_little_bin);
}
else {
else if (bin_type == LLVMBinaryTypeELF64L
|| bin_type == LLVMBinaryTypeELF64B) {
struct elf64_ehdr *elf_header;
bool is_little_bin = bin_type == LLVMBinaryTypeELF64L;
@ -1435,6 +1462,19 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
SET_TARGET_INFO(e_version, e_version, uint32, is_little_bin);
SET_TARGET_INFO(e_flags, e_flags, uint32, is_little_bin);
}
else if (bin_type == LLVMBinaryTypeMachO32L
|| bin_type == LLVMBinaryTypeMachO32B) {
/* TODO: parse file type of Mach-O 32 */
aot_set_last_error("invaid llvm binary bin_type.");
return false;
}
else if (bin_type == LLVMBinaryTypeMachO64L
|| bin_type == LLVMBinaryTypeMachO64B) {
/* TODO: parse file type of Mach-O 64 */
aot_set_last_error("invaid llvm binary bin_type.");
return false;
}
strncpy(obj_data->target_info.arch, comp_ctx->target_arch,
sizeof(obj_data->target_info.arch));
@ -1941,7 +1981,7 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data,
bh_print_time("Begin to emit AOT file");
aot_file_size = get_aot_file_size(comp_data, obj_data);
aot_file_size = get_aot_file_size(comp_ctx, comp_data, obj_data);
if (!(buf = aot_file_buf = wasm_runtime_malloc(aot_file_size))) {
aot_set_last_error("allocate memory failed.");
@ -1953,7 +1993,7 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data,
if (!aot_emit_file_header(buf, buf_end, &offset, comp_data, obj_data)
|| !aot_emit_target_info_section(buf, buf_end, &offset, comp_data, obj_data)
|| !aot_emit_init_data_section(buf, buf_end, &offset, comp_data, obj_data)
|| !aot_emit_init_data_section(buf, buf_end, &offset, comp_ctx, comp_data, obj_data)
|| !aot_emit_text_section(buf, buf_end, &offset, comp_data, obj_data)
|| !aot_emit_func_section(buf, buf_end, &offset, comp_data, obj_data)
|| !aot_emit_export_section(buf, buf_end, &offset, comp_data, obj_data)

View File

@ -626,3 +626,290 @@ fail:
return false;
}
#if WASM_ENABLE_BULK_MEMORY != 0
static LLVMValueRef
check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef offset, LLVMValueRef bytes)
{
LLVMValueRef maddr, max_addr, cmp;
LLVMValueRef mem_base_addr;
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMBasicBlockRef check_succ;
uint32 off = offsetof(AOTModuleInstance, memory_data_size);
LLVMValueRef mem_size_offset, mem_size_ptr, mem_size;
/* Get memory base address and memory data size */
if (func_ctx->mem_space_unchanged) {
mem_base_addr = func_ctx->mem_base_addr;
}
else {
if (!(mem_base_addr = LLVMBuildLoad(comp_ctx->builder,
func_ctx->mem_base_addr,
"mem_base"))) {
aot_set_last_error("llvm build load failed.");
goto fail;
}
}
/* return addres directly if constant offset and inside memory space */
if (LLVMIsConstant(offset) && LLVMIsConstant(bytes)) {
uint64 mem_offset = (uint64)LLVMConstIntGetZExtValue(offset);
uint64 mem_len = (uint64)LLVMConstIntGetZExtValue(bytes);
uint32 num_bytes_per_page = comp_ctx->comp_data->num_bytes_per_page;
uint32 init_page_count = comp_ctx->comp_data->mem_init_page_count;
uint32 mem_data_size = num_bytes_per_page * init_page_count;
if (mem_data_size > 0
&& mem_offset + mem_len <= mem_data_size) {
/* inside memory space */
/* maddr = mem_base_addr + moffset */
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder,
mem_base_addr,
&offset, 1, "maddr"))) {
aot_set_last_error("llvm build add failed.");
goto fail;
}
return maddr;
}
}
/* mem_size_offset = aot_inst + off */
mem_size_offset = I32_CONST(off);
if (!(mem_size_ptr = LLVMBuildInBoundsGEP(comp_ctx->builder,
func_ctx->aot_inst,
&mem_size_offset, 1,
"mem_size_ptr_tmp"))) {
aot_set_last_error("llvm build inbounds gep failed.");
return NULL;
}
/* cast to int32* */
if (!(mem_size_ptr = LLVMBuildBitCast(comp_ctx->builder, mem_size_ptr,
INT32_PTR_TYPE, "mem_size_ptr"))) {
aot_set_last_error("llvm build bitcast failed.");
return NULL;
}
/* load memory size */
if (!(mem_size = LLVMBuildLoad(comp_ctx->builder,
mem_size_ptr, "mem_size"))) {
aot_set_last_error("llvm build load failed.");
return NULL;
}
ADD_BASIC_BLOCK(check_succ, "check_succ");
LLVMMoveBasicBlockAfter(check_succ, block_curr);
offset = LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset");
bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len");
mem_size = LLVMBuildZExt(comp_ctx->builder, mem_size, I64_TYPE, "extend_size");
BUILD_OP(Add, offset, bytes, max_addr, "max_addr");
BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp,
"cmp_max_mem_addr");
if (!aot_emit_exception(comp_ctx, func_ctx,
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
true, cmp, check_succ)) {
goto fail;
}
/* maddr = mem_base_addr + offset */
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr,
&offset, 1, "maddr"))) {
aot_set_last_error("llvm build add failed.");
goto fail;
}
return maddr;
fail:
return NULL;
}
#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_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 seg_index)
{
LLVMValueRef seg, offset, dst, len, param_values[5], ret_value, func, value;
LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMBasicBlockRef mem_init_fail, init_success;
seg = I32_CONST(seg_index);
POP_I32(len);
POP_I32(offset);
POP_I32(dst);
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 = INT8_TYPE;
GET_AOT_FUNCTION(aot_memory_init, 5);
/* Call function aot_memory_init() */
param_values[0] = func_ctx->aot_inst;
param_values[1] = seg;
param_values[2] = offset;
param_values[3] = len;
param_values[4] = dst;
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
param_values, 5, "call"))) {
aot_set_last_error("llvm build call failed.");
return false;
}
BUILD_ICMP(LLVMIntUGT, ret_value, I8_ZERO, ret_value, "mem_init_ret");
ADD_BASIC_BLOCK(mem_init_fail, "mem_init_fail");
ADD_BASIC_BLOCK(init_success, "init_success");
LLVMMoveBasicBlockAfter(mem_init_fail, block_curr);
LLVMMoveBasicBlockAfter(init_success, block_curr);
if (!LLVMBuildCondBr(comp_ctx->builder, ret_value,
init_success, mem_init_fail)) {
aot_set_last_error("llvm build cond br failed.");
goto fail;
}
/* If memory.init failed, return this function
so the runtime can catch the exception */
LLVMPositionBuilderAtEnd(comp_ctx->builder, mem_init_fail);
if (aot_func_type->result_count) {
switch (aot_func_type->types[aot_func_type->param_count]) {
case VALUE_TYPE_I32:
LLVMBuildRet(comp_ctx->builder, I32_ZERO);
break;
case VALUE_TYPE_I64:
LLVMBuildRet(comp_ctx->builder, I64_ZERO);
break;
case VALUE_TYPE_F32:
LLVMBuildRet(comp_ctx->builder, F32_ZERO);
break;
case VALUE_TYPE_F64:
LLVMBuildRet(comp_ctx->builder, F64_ZERO);
break;
}
}
else {
LLVMBuildRetVoid(comp_ctx->builder);
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, init_success);
return true;
fail:
return false;
}
bool
aot_compile_op_data_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 seg_index)
{
LLVMValueRef seg, param_values[2], ret_value, func, value;
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
seg = I32_CONST(seg_index);
param_types[0] = INT8_PTR_TYPE;
param_types[1] = I32_TYPE;
ret_type = INT8_TYPE;
GET_AOT_FUNCTION(aot_data_drop, 2);
/* Call function aot_data_drop() */
param_values[0] = func_ctx->aot_inst;
param_values[1] = seg;
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
param_values, 2, "call"))) {
aot_set_last_error("llvm build call failed.");
return false;
}
return true;
}
bool
aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef src, dst, src_addr, dst_addr, len, res;
POP_I32(len);
POP_I32(src);
POP_I32(dst);
if (!(src_addr =
check_bulk_memory_overflow(comp_ctx, func_ctx, src, len)))
return false;
if (!(dst_addr =
check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len)))
return false;
if (!(res = LLVMBuildMemMove(comp_ctx->builder, dst_addr, 1,
src_addr, 1, len))) {
aot_set_last_error("llvm build memmove failed.");
return false;
}
return true;
fail:
return false;
}
bool
aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef val, dst, dst_addr, len, res;
POP_I32(len);
POP_I32(val);
POP_I32(dst);
if (!(dst_addr =
check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len)))
return false;
val = LLVMBuildIntCast2(comp_ctx->builder, val, INT8_TYPE, true, "mem_set_value");
if (!(res = LLVMBuildMemSet(comp_ctx->builder, dst_addr,
val, len, 1))) {
aot_set_last_error("llvm build memset failed.");
return false;
}
return true;
fail:
return false;
}
#endif /* WASM_ENABLE_BULK_MEMORY */

View File

@ -50,6 +50,22 @@ aot_compile_op_memory_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
#if WASM_ENABLE_BULK_MEMORY != 0
bool
aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 seg_index);
bool
aot_compile_op_data_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 seg_index);
bool
aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
bool
aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
#endif
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -914,6 +914,9 @@ aot_create_comp_context(AOTCompData *comp_data,
goto fail;
}
if (option->enable_bulk_memory)
comp_ctx->enable_bulk_memory = true;
if (option->is_jit_mode) {
/* Create LLVM execution engine */
LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options));

View File

@ -185,6 +185,9 @@ typedef struct AOTCompContext {
LLVMExecutionEngineRef exec_engine;
bool is_jit_mode;
/* Bulk memory feature */
bool enable_bulk_memory;
/* Whether optimize the JITed code */
bool optimize;
@ -223,6 +226,7 @@ typedef struct AOTCompOption{
char *target_abi;
char *target_cpu;
char *cpu_features;
bool enable_bulk_memory;
uint32 opt_level;
uint32 size_level;
uint32 output_format;

View File

@ -39,6 +39,7 @@ typedef struct AOTCompOption{
char *target_abi;
char *target_cpu;
char *cpu_features;
bool enable_bulk_memory;
uint32_t opt_level;
uint32_t size_level;
uint32_t output_format;

View File

@ -6,7 +6,7 @@
#ifndef _LIB_EXPORT_H_
#define _LIB_EXPORT_H_
#include <inttypes.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {

View File

@ -6,7 +6,7 @@
#ifndef _WASM_EXPORT_H
#define _WASM_EXPORT_H
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include "lib_export.h"
@ -178,6 +178,56 @@ void wasm_runtime_free(void *ptr);
package_type_t
get_package_type(const uint8_t *buf, uint32_t size);
#if WASM_ENABLE_MULTI_MODULE != 0
/**
* It is a callback for WAMR providing by embedding to load a module file
* into a buffer
*/
typedef bool (*module_reader)(const char *module_name,
uint8_t **p_buffer, uint32_t *p_size);
/**
* It is a callback for WAMR providing by embedding to release the buffer which
* is used by loading a module file
*/
typedef void (*module_destroyer)(uint8_t *buffer, uint32_t size);
/**
* To setup callbacks for reading and releasing a buffer about a module file
*
* @param reader a callback to read a module file into a buffer
* @param destroyer a callback to release above buffer
*/
void
wasm_runtime_set_module_reader(const module_reader reader,
const module_destroyer destroyer);
/**
* Give the "module" a name "module_name".
* can not assign a new name to a module if it already has a name
*
* @param module_name indicate a name
* @param module the target module
* @param error_buf output of the exception info
* @param error_buf_size the size of the exception string
*
* @return true means success, false means failed
*/
bool
wasm_runtime_register_module(const char *module_name, wasm_module_t module,
char *error_buf, uint32_t error_buf_size);
/**
* To check if there is already a loaded module named module_name in the
* runtime. you will not want to load repeately
*
* @param module_name indicate a name
*
* @return return WASM module loaded, NULL if failed
*/
wasm_module_t
wasm_runtime_find_module_registered(const char *module_name);
#endif /* WASM_ENABLE_MULTI_MODULE */
/**
* Load a WASM module from a specified byte buffer. The byte buffer can be
* WASM binary data when interpreter or JIT is enabled, or AOT binary data
@ -348,7 +398,9 @@ wasm_application_execute_main(wasm_module_inst_t module_inst,
* and execute that function.
*
* @param module_inst the WASM module instance
* @param name the name of the function to execute
* @param name the name of the function to execute.
* to indicate the module name via: $module_name$function_name
* or just a function name: function_name
* @param argc the number of arguments
* @param argv the arguments array
*

View File

@ -22,6 +22,8 @@ extern "C" {
#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
@ -50,6 +52,9 @@ extern "C" {
#define SECTION_TYPE_ELEM 9
#define SECTION_TYPE_CODE 10
#define SECTION_TYPE_DATA 11
#if WASM_ENABLE_BULK_MEMORY != 0
#define SECTION_TYPE_DATACOUNT 12
#endif
#define IMPORT_KIND_FUNC 0
#define IMPORT_KIND_TABLE 1
@ -66,6 +71,10 @@ extern "C" {
#define BLOCK_TYPE_IF 2
#define BLOCK_TYPE_FUNCTION 3
typedef struct WASMModule WASMModule;
typedef struct WASMFunction WASMFunction;
typedef struct WASMGlobal WASMGlobal;
typedef union WASMValue {
int32 i32;
uint32 u32;
@ -119,6 +128,10 @@ typedef struct WASMTableImport {
uint32 init_size;
/* specified if (flags & 1), else it is 0x10000 */
uint32 max_size;
#if WASM_ENABLE_MULTI_MODULE != 0
WASMModule *import_module;
WASMTable *import_table_linked;
#endif
} WASMTableImport;
typedef struct WASMMemoryImport {
@ -128,6 +141,10 @@ typedef struct WASMMemoryImport {
uint32 num_bytes_per_page;
uint32 init_page_count;
uint32 max_page_count;
#if WASM_ENABLE_MULTI_MODULE != 0
WASMModule *import_module;
WASMMemory *import_memory_linked;
#endif
} WASMMemoryImport;
typedef struct WASMFunctionImport {
@ -135,13 +152,17 @@ typedef struct WASMFunctionImport {
char *field_name;
/* function type */
WASMType *func_type;
/* function pointer after linked */
/* native function pointer after linked */
void *func_ptr_linked;
/* signature from registered native symbols */
const char *signature;
/* attachment */
void *attachment;
bool call_conv_raw;
#if WASM_ENABLE_MULTI_MODULE != 0
WASMModule *import_module;
WASMFunction *import_func_linked;
#endif
} WASMFunctionImport;
typedef struct WASMGlobalImport {
@ -151,6 +172,12 @@ typedef struct WASMGlobalImport {
bool is_mutable;
/* global data after linked */
WASMValue global_data_linked;
#if WASM_ENABLE_MULTI_MODULE != 0
/* imported function pointer after linked */
// TODO: remove if not necessary
WASMModule *import_module;
WASMGlobal *import_global_linked;
#endif
} WASMGlobalImport;
typedef struct WASMImport {
@ -223,6 +250,9 @@ typedef struct WASMDataSeg {
uint32 memory_index;
InitializerExpression base_offset;
uint32 data_length;
#if WASM_ENABLE_BULK_MEMORY != 0
bool is_passive;
#endif
uint8 *data;
} WASMDataSeg;
@ -266,7 +296,12 @@ typedef struct WASMModule {
uint32 global_count;
uint32 export_count;
uint32 table_seg_count;
/* data seg count read from data segment section */
uint32 data_seg_count;
#if WASM_ENABLE_BULK_MEMORY != 0
/* data count read from datacount section */
uint32 data_seg_count1;
#endif
uint32 import_function_count;
uint32 import_table_count;
@ -308,6 +343,12 @@ typedef struct WASMModule {
WASIArguments wasi_args;
bool is_wasi_module;
#endif
#if WASM_ENABLE_MULTI_MODULE != 0
// TODO: mutex ? mutli-threads ?
bh_list import_module_list_head;
bh_list *import_module_list;
#endif
} WASMModule;
typedef struct WASMBranchBlock {
@ -430,5 +471,4 @@ wasm_type_equal(const WASMType *type1, const WASMType *type2)
} /* end of extern "C" */
#endif
#endif /* end of _WASM_H_ */
#endif /* end of _WASM_H_ */

View File

@ -236,6 +236,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)
{
@ -877,6 +886,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_LABELS_AS_VALUES != 0
#define HANDLE_OP(opcode) HANDLE_##opcode
@ -902,6 +964,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;
@ -1086,14 +1151,27 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP (WASM_OP_CALL):
read_leb_uint32(frame_ip, frame_ip_end, fidx);
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;
HANDLE_OP (WASM_OP_CALL_INDIRECT):
{
WASMType *cur_type, *cur_func_type;
WASMTableInstance *cur_table_inst;
/**
* type check. compiler will make sure all like
* (call_indirect (type $x) (i32.const 1))
* the function type has to be defined in the module also
* 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, "type index is overflow");
@ -1105,27 +1183,48 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
frame_ip++;
val = POP_I32();
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)) {
wasm_set_exception(module, "indirect call type mismatch");
goto got_exception;
}
goto call_func_from_interp;
}
@ -1264,7 +1363,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:
@ -1289,7 +1395,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:
@ -1521,6 +1634,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;
@ -2357,6 +2473,78 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
DEF_OP_TRUNC_SAT_F64(-1.0f, 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;
read_leb_uint32(frame_ip, frame_ip_end, segment);
/* skip memory index */
frame_ip++;
bytes = (uint64)(uint32)POP_I32();
offset = (uint64)(uint32)POP_I32();
addr = (uint32)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;
read_leb_uint32(frame_ip, frame_ip_end, segment);
module->module->data_segments[segment]->data_length = 0;
break;
}
case WASM_OP_MEMORY_COPY:
{
uint32 dst, src, len;
uint8 *mdst, *msrc;
frame_ip += 2;
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;
frame_ip++;
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;
@ -2430,14 +2618,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;
@ -2521,6 +2720,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst,
WASMFunctionInstance *function,
uint32 argc, uint32 argv[])
{
// TODO: since module_inst = exec_env->module_inst, shall we remove the 1st arg?
WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env);
WASMInterpFrame *frame, *outs_area;
@ -2559,15 +2759,44 @@ 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");
/* it is a native function */
wasm_interp_call_func_native(module_inst,
exec_env,
function,
frame);
}
}
else {
LOG_DEBUG("it is a function of the module itself");
wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame);
}
/* Output the return value to the caller */
if (!wasm_get_exception(module_inst)) {
for (i = 0; i < function->ret_cell_num; i++)
for (i = 0; i < function->ret_cell_num; i++) {
argv[i] = *(frame->sp + i - function->ret_cell_num);
}
if (function->ret_cell_num) {
LOG_DEBUG("first return value argv[0]=%d", argv[0]);
} else {
LOG_DEBUG("no return value");
}
} else {
LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst));
}
wasm_exec_env_set_cur_frame(exec_env, prev_frame);

View File

@ -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)) {

File diff suppressed because it is too large Load Diff

View File

@ -262,7 +262,7 @@ typedef enum WASMOpcode {
WASM_OP_MISC_PREFIX = 0xfc,
} WASMOpcode;
typedef enum WASMEXTOpcode {
typedef enum WASMMiscEXTOpcode {
WASM_OP_I32_TRUNC_SAT_S_F32 = 0x00,
WASM_OP_I32_TRUNC_SAT_U_F32 = 0x01,
WASM_OP_I32_TRUNC_SAT_S_F64 = 0x02,
@ -271,7 +271,16 @@ typedef enum WASMEXTOpcode {
WASM_OP_I64_TRUNC_SAT_U_F32 = 0x05,
WASM_OP_I64_TRUNC_SAT_S_F64 = 0x06,
WASM_OP_I64_TRUNC_SAT_U_F64 = 0x07,
} WASMEXTOpcode;
#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
} WASMMiscEXTOpcode;
#ifdef __cplusplus
}

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,12 @@
extern "C" {
#endif
typedef struct WASMModuleInstance WASMModuleInstance;
typedef struct WASMFunctionInstance WASMFunctionInstance;
typedef struct WASMMemoryInstance WASMMemoryInstance;
typedef struct WASMTableInstance WASMTableInstance;
typedef struct WASMGlobalInstance WASMGlobalInstance;
typedef struct WASMMemoryInstance {
/* Number bytes per page */
uint32 num_bytes_per_page;
@ -36,6 +42,10 @@ typedef struct WASMMemoryInstance {
/* End address of memory */
uint8 *end_addr;
#if WASM_ENABLE_MULTI_MODULE != 0
/* to indicate which module instance create it */
WASMModuleInstance *owner;
#endif
/* Base address, the layout is:
heap_data + memory data
memory data init size is: num_bytes_per_page * cur_page_count
@ -52,6 +62,10 @@ typedef struct WASMTableInstance {
uint32 cur_size;
/* Maximum size */
uint32 max_size;
#if WASM_ENABLE_MULTI_MODULE != 0
/* just for import, keep the reference here */
WASMTableInstance *table_inst_linked;
#endif
/* Base address */
uint8 base_addr[1];
} WASMTableInstance;
@ -65,6 +79,11 @@ typedef struct WASMGlobalInstance {
uint32 data_offset;
/* initial value */
WASMValue initial_value;
#if WASM_ENABLE_MULTI_MODULE != 0
/* just for import, keep the reference here */
WASMModuleInstance *import_module_inst;
WASMGlobalInstance *import_global_inst;
#endif
} WASMGlobalInstance;
typedef struct WASMFunctionInstance {
@ -93,6 +112,10 @@ typedef struct WASMFunctionInstance {
WASMFunctionImport *func_import;
WASMFunction *func;
} u;
#if WASM_ENABLE_MULTI_MODULE != 0
WASMModuleInstance *import_module_inst;
WASMFunctionInstance *import_func_inst;
#endif
} WASMFunctionInstance;
typedef struct WASMExportFuncInstance {
@ -100,6 +123,23 @@ typedef struct WASMExportFuncInstance {
WASMFunctionInstance *function;
} WASMExportFuncInstance;
#if WASM_ENABLE_MULTI_MODULE != 0
typedef struct WASMExportGlobInstance {
char *name;
WASMGlobalInstance *global;
} WASMExportGlobInstance;
typedef struct WASMExportTabInstance {
char *name;
WASMTableInstance *table;
} WASMExportTabInstance;
typedef struct WASMExportMemInstance {
char *name;
WASMMemoryInstance *memory;
} WASMExportMemInstance;
#endif
typedef struct WASMModuleInstance {
/* Module instance type, for module instance loaded from
WASM bytecode binary, this field is Wasm_Module_Bytecode;
@ -112,13 +152,25 @@ typedef struct WASMModuleInstance {
uint32 table_count;
uint32 global_count;
uint32 function_count;
uint32 export_func_count;
#if WASM_ENABLE_MULTI_MODULE != 0
uint32 export_glob_count;
uint32 export_mem_count;
uint32 export_tab_count;
#endif
WASMMemoryInstance **memories;
WASMTableInstance **tables;
WASMGlobalInstance *globals;
WASMFunctionInstance *functions;
WASMExportFuncInstance *export_functions;
#if WASM_ENABLE_MULTI_MODULE != 0
WASMExportGlobInstance *export_globals;
WASMExportMemInstance *export_memories;
WASMExportTabInstance *export_tables;
#endif
WASMMemoryInstance *default_memory;
WASMTableInstance *default_table;
@ -148,11 +200,26 @@ typedef struct WASMModuleInstance {
/* Main exec env */
WASMExecEnv *main_exec_env;
#if WASM_ENABLE_MULTI_MODULE != 0
// TODO: mutex ? mutli-threads ?
bh_list sub_module_inst_list_head;
bh_list *sub_module_inst_list;
#endif
} WASMModuleInstance;
struct WASMInterpFrame;
typedef struct WASMInterpFrame WASMRuntimeFrame;
#if WASM_ENABLE_MULTI_MODULE != 0
typedef struct WASMSubModInstNode {
bh_list_link l;
/* point to a string pool */
const char *module_name;
WASMModuleInstance *module_inst;
} WASMSubModInstNode;
#endif
/**
* Return the code block of a function.
*
@ -182,10 +249,11 @@ wasm_get_func_code_end(WASMFunctionInstance *func)
{
#if WASM_ENABLE_FAST_INTERP == 0
return func->is_import_func
? NULL : func->u.func->code + func->u.func->code_size;
? NULL : func->u.func->code + func->u.func->code_size;
#else
return func->is_import_func
? NULL : func->u.func->code_compiled + func->u.func->code_compiled_size;
? NULL
: func->u.func->code_compiled + func->u.func->code_compiled_size;
#endif
}
@ -212,6 +280,17 @@ WASMFunctionInstance *
wasm_lookup_function(const WASMModuleInstance *module_inst,
const char *name, const char *signature);
#if WASM_ENABLE_MULTI_MODULE != 0
WASMGlobalInstance *
wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name);
WASMMemoryInstance *
wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name);
WASMTableInstance *
wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name);
#endif
bool
wasm_call_function(WASMExecEnv *exec_env,
WASMFunctionInstance *function,

View File

@ -1098,7 +1098,7 @@ static NativeSymbol native_symbols_spectest[] = {
REG_NATIVE_FUNC(print, "()"),
REG_NATIVE_FUNC(print_i32, "(i)"),
REG_NATIVE_FUNC(print_i32_f32, "(if)"),
REG_NATIVE_FUNC(print_f64_f64, "(fF)"),
REG_NATIVE_FUNC(print_f64_f64, "(FF)"),
REG_NATIVE_FUNC(print_f32, "(f)"),
REG_NATIVE_FUNC(print_f64, "(F)")
};