Enable AoT and wamr-sdk, and change arguments of call wasm API (#157)

* Implement memory profiler, optimize memory usage, modify code indent

* Implement memory.grow and limit heap space base offset to 1G; modify iwasm build type to Release and 64 bit by default

* Add a new extension library: connection

* Fix bug of reading magic number and version in big endian platform

* Re-org platform APIs: move most platform APIs from iwasm to shared-lib

* Enhance wasm loader to fix some security issues

* Fix issue about illegal load of EXC_RETURN into PC on stm32 board

* Updates that let a restricted version of the interpreter run in SGX

* Enable native/app address validation and conversion for wasm app

* Remove wasm_application_exectue_* APIs from wasm_export.h which makes confused

* Refine binary size and fix several minor issues

Optimize interpreter LOAD/STORE opcodes to decrease the binary size
Fix issues when using iwasm library: _bh_log undefined, bh_memory.h not found
Remove unused _stdin/_stdout/_stderr global variables resolve in libc wrapper
Add macros of global heap size, stack size, heap size for Zephyr main.c
Clear compile warning of wasm_application.c

* Add more strict security checks for libc wrapper API's

* Use one libc wrapper copy for sgx and other platforms; remove bh_printf macro for other platform header files

* Enhance security of libc strcpy/sprintf wrapper function

* Fix issue of call native for x86_64/arm/mips, add module inst parameter for native wrapper functions

* Remove get_module_inst() and fix issue of call native

* Refine wgl lib: remove module_inst parameter from widget functions; move function index check to runtime instantiate

* Refine interpreter call native process, refine memory boudary check

* Fix issues of invokeNative function of arm/mips/general version

* Add a switch to build simple sample without gui support

* Add BUILD_TARGET setting in makefile to replace cpu compiler flags in source code

* Re-org shared lib header files, remove unused info; fix compile issues of vxworks

* Add build target general

* Remove unused files

* Update license header

* test push

* Restore file

* Sync up with internal/feature

* Sync up with internal/feature

* Rename build_wamr_app to build_wasm_app

* Fix small issues of README

* Enhance malformed wasm file checking
Fix issue of print hex int and implement utf8 string check
Fix wasi file read/write right issue
Fix minor issue of build wasm app doc

* Sync up with internal/feature

* Sync up with internal/feature: fix interpreter arm issue, fix read leb issue

* Sync up with internal/feature

* Fix bug of config.h and rename wasi config.h to ssp_config.h

* Sync up with internal/feature

* Import wamr aot

* update document

* update document

* Update document, disable WASI in 32bit

* update document

* remove files

* update document

* Update document

* update document

* update document

* update samples

* Sync up with internal repo
This commit is contained in:
wenyongh
2020-01-21 13:26:14 +08:00
committed by Wang Xin
parent 2a4528c749
commit 46b93b9d22
464 changed files with 25137 additions and 7911 deletions

2511
core/iwasm/aot/aot_loader.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,858 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "aot_runtime.h"
#include "bh_memory.h"
#include "bh_log.h"
#include "mem_alloc.h"
static void
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
{
if (error_buf != NULL)
snprintf(error_buf, error_buf_size, "%s", string);
}
static bool
global_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
char *error_buf, uint32 error_buf_size)
{
uint32 i;
InitializerExpression *init_expr;
uint8 *p = (uint8*)module_inst->global_data.ptr;
AOTImportGlobal *import_global = module->import_globals;;
AOTGlobal *global = module->globals;
/* Initialize import global data */
for (i = 0; i < module->import_global_count; i++, import_global++) {
bh_assert(import_global->data_offset ==
p - (uint8*)module_inst->global_data.ptr);
memcpy(p, &import_global->global_data_linked, import_global->size);
p += import_global->size;
}
/* Initialize defined global data */
for (i = 0; i < module->global_count; i++, global++) {
bh_assert(global->data_offset ==
p - (uint8*)module_inst->global_data.ptr);
init_expr = &global->init_expr;
switch (init_expr->init_expr_type) {
case INIT_EXPR_TYPE_GET_GLOBAL:
bh_assert(init_expr->u.global_index < module->import_global_count);
memcpy(p,
&module->import_globals[init_expr->u.global_index].global_data_linked,
global->size);
break;
default:
/* TODO: check whether global type and init_expr type are matching */
memcpy(p, &init_expr->u, global->size);
break;
}
p += global->size;
}
bh_assert(module_inst->global_data_size == p - (uint8*)module_inst->global_data.ptr);
return true;
}
static bool
table_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
char *error_buf, uint32 error_buf_size)
{
uint32 i, global_index, global_data_offset, base_offset, length;
AOTTableInitData *table_seg;
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);
/* 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);
}
else
base_offset = (uint32)table_seg->offset.u.i32;
/* 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));
}
}
}
return true;
}
static bool
memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
char *error_buf, uint32 error_buf_size)
{
uint32 i, global_index, global_data_offset, base_offset, length;
AOTMemInitData *data_seg;
uint64 total_size = (uint64)NumBytesPerPage * module->mem_init_page_count;
/* Allocate memory */
if (total_size >= UINT32_MAX
|| !(module_inst->memory_data.ptr = wasm_malloc((uint32)total_size))) {
set_error_buf(error_buf, error_buf_size,
"AOT module instantiate failed: allocate memory failed.");
return false;
}
memset(module_inst->memory_data.ptr, 0, (uint32)total_size);
/* Init memory info */
module_inst->memory_data_end.ptr = (uint8*)module_inst->memory_data.ptr
+ total_size;
module_inst->memory_data_size = (uint32)total_size;
module_inst->mem_cur_page_count = module->mem_init_page_count;
module_inst->mem_max_page_count = module->mem_max_page_count;
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);
/* 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;
base_offset = *(uint32*)
((uint8*)module_inst->global_data.ptr + global_data_offset);
}
else
base_offset = (uint32)data_seg->offset.u.i32;
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)) {
wasm_free(module_inst->memory_data.ptr);
module_inst->memory_data.ptr = NULL;
set_error_buf(error_buf, error_buf_size,
"AOT module instantiate failed: data segment out of range.");
return false;
}
/* Copy memory data */
memcpy((uint8*)module_inst->memory_data.ptr + base_offset,
data_seg->bytes, length);
}
}
return true;
}
static bool
init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module,
char *error_buf, uint32 error_buf_size)
{
uint32 i;
void **func_ptrs;
uint64 total_size =
((uint64)module->import_func_count + module->func_count) * sizeof(void*);
/* Allocate memory */
if (total_size >= UINT32_MAX
|| !(module_inst->func_ptrs.ptr = wasm_malloc((uint32)total_size))) {
set_error_buf(error_buf, error_buf_size,
"AOT module instantiate failed: allocate memory failed.");
return false;
}
memset(module_inst->func_ptrs.ptr, 0, (uint32)total_size);
/* Set import function pointers */
func_ptrs = (void**)module_inst->func_ptrs.ptr;
for (i = 0; i < module->import_func_count; i++, func_ptrs++)
*func_ptrs = (void*)module->import_funcs[i].func_ptr_linked;
/* Set defined function pointers */
memcpy(func_ptrs, module->func_ptrs, module->func_count * sizeof(void*));
return true;
}
static bool
init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module,
char *error_buf, uint32 error_buf_size)
{
uint32 i;
uint32 *func_type_index;
uint64 total_size =
((uint64)module->import_func_count + module->func_count) * sizeof(uint32);
/* Allocate memory */
if (total_size >= UINT32_MAX
|| !(module_inst->func_type_indexes.ptr = wasm_malloc((uint32)total_size))) {
set_error_buf(error_buf, error_buf_size,
"AOT module instantiate failed: allocate memory failed.");
return false;
}
memset(module_inst->func_type_indexes.ptr, 0, (uint32)total_size);
/* Set import function type indexes */
func_type_index = (uint32*)module_inst->func_type_indexes.ptr;
for (i = 0; i < module->import_func_count; i++, func_type_index++)
*func_type_index = module->import_funcs[i].func_type_index;
memcpy(func_type_index, module->func_type_indexes,
module->func_count * sizeof(uint32));
return true;
}
static bool
execute_post_inst_function(AOTModuleInstance *module_inst)
{
AOTFunctionInstance *post_inst_func =
aot_lookup_function(module_inst, "__post_instantiate", "()");
if (!post_inst_func)
/* Not found */
return true;
return aot_create_exec_env_and_call_function(module_inst, post_inst_func, 0, NULL);
}
static bool
execute_start_function(AOTModuleInstance *module_inst)
{
AOTModule *module = (AOTModule*)module_inst->aot_module.ptr;
WASMExecEnv *exec_env;
typedef void (*F)(WASMExecEnv*);
union { F f; void *v; } u;
if (!module->start_function)
return true;
if (!(exec_env = wasm_exec_env_create((WASMModuleInstanceCommon*)module_inst,
module_inst->default_wasm_stack_size))) {
aot_set_exception(module_inst, "allocate memory failed.");
return false;
}
u.v = module->start_function;
u.f(exec_env);
wasm_exec_env_destroy(exec_env);
return !aot_get_exception(module_inst);
}
AOTModuleInstance*
aot_instantiate(AOTModule *module,
uint32 stack_size, uint32 heap_size,
char *error_buf, uint32 error_buf_size)
{
AOTModuleInstance *module_inst;
uint32 module_inst_struct_size =
offsetof(AOTModuleInstance, global_table_heap_data.bytes);
uint64 table_data_size = (uint64)module->table_size * sizeof(uint32);
uint64 total_size = (uint64)module_inst_struct_size
+ module->global_data_size
+ table_data_size + heap_size;
void *heap_handle;
uint8 *p;
/* Check heap size */
heap_size = align_uint(heap_size, 8);
if (heap_size == 0)
heap_size = APP_HEAP_SIZE_DEFAULT;
if (heap_size < APP_HEAP_SIZE_MIN)
heap_size = APP_HEAP_SIZE_MIN;
if (heap_size > APP_HEAP_SIZE_MAX)
heap_size = APP_HEAP_SIZE_MAX;
/* Allocate module instance, global data, table data and heap data */
if (total_size >= UINT32_MAX
|| !(module_inst = wasm_malloc((uint32)total_size))) {
set_error_buf(error_buf, error_buf_size,
"AOT module instantiate failed: allocate memory failed.");
return NULL;
}
memset(module_inst, 0, total_size);
module_inst->module_type = Wasm_Module_AoT;
module_inst->aot_module.ptr = module;
/* Initialize global info */
p = (uint8*)module_inst + module_inst_struct_size;
module_inst->global_data.ptr = p;
module_inst->global_data_size = module->global_data_size;
if (!global_instantiate(module_inst, module, error_buf, error_buf_size))
goto fail;
/* Initialize table info */
p += module->global_data_size;
module_inst->table_data.ptr = p;
module_inst->table_size = module->table_size;
/* Set all elements to -1 to mark them as uninitialized elements */
memset(module_inst->table_data.ptr, -1, (uint32)table_data_size);
if (!table_instantiate(module_inst, module, error_buf, error_buf_size))
goto fail;
/* Initialize heap info */
p += (uint32)table_data_size;
module_inst->heap_data.ptr = p;
p += heap_size;
module_inst->heap_data_end.ptr = p;
module_inst->heap_data_size = heap_size;
#if WASM_ENABLE_MEMORY_GROW != 0
module_inst->heap_base_offset = DEFAULT_APP_HEAP_BASE_OFFSET;
#else
module_inst->heap_base_offset = module_inst->memory_data_size;
#endif
if (!(heap_handle = mem_allocator_create(module_inst->heap_data.ptr,
heap_size))) {
set_error_buf(error_buf, error_buf_size,
"AOT module instantiate failed: init app heap failed.");
goto fail;
}
module_inst->heap_handle.ptr = heap_handle;
/* Initialize memory space */
if (!memory_instantiate(module_inst, module, error_buf, error_buf_size))
goto fail;
/* Initialize function pointers */
if (!init_func_ptrs(module_inst, module, error_buf, error_buf_size))
goto fail;
/* Initialize function type indexes */
if (!init_func_type_indexes(module_inst, module, error_buf, error_buf_size))
goto fail;
#if WASM_ENABLE_LIBC_WASI != 0
if (!wasm_runtime_init_wasi((WASMModuleInstanceCommon*)module_inst,
module->wasi_args.dir_list,
module->wasi_args.dir_count,
module->wasi_args.map_dir_list,
module->wasi_args.map_dir_count,
module->wasi_args.env,
module->wasi_args.env_count,
module->wasi_args.argv,
module->wasi_args.argc,
error_buf, error_buf_size))
goto fail;
#endif
/* Initialize the thread related data */
if (stack_size == 0)
stack_size = DEFAULT_WASM_STACK_SIZE;
module_inst->default_wasm_stack_size = stack_size;
/* Execute __post_instantiate function and start function*/
if (!execute_post_inst_function(module_inst)
|| !execute_start_function(module_inst)) {
set_error_buf(error_buf, error_buf_size,
module_inst->cur_exception);
goto fail;
}
return module_inst;
fail:
aot_deinstantiate(module_inst);
return NULL;
}
void
aot_deinstantiate(AOTModuleInstance *module_inst)
{
#if WASM_ENABLE_LIBC_WASI != 0
/* Destroy wasi resource before freeing app heap, since some fields of
wasi contex are allocated from app heap, and if app heap is freed,
these fields will be set to NULL, we cannot free their internal data
which may allocated from global heap. */
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst);
#endif
if (module_inst->memory_data.ptr)
wasm_free(module_inst->memory_data.ptr);
if (module_inst->heap_handle.ptr)
mem_allocator_destroy(module_inst->heap_handle.ptr);
if (module_inst->func_ptrs.ptr)
wasm_free(module_inst->func_ptrs.ptr);
if (module_inst->func_type_indexes.ptr)
wasm_free(module_inst->func_type_indexes.ptr);
wasm_free(module_inst);
}
static bool
check_type(uint8 type, const char *p)
{
const char *str = "i32";
if (strlen(p) < 3)
return false;
switch (type) {
case VALUE_TYPE_I32:
str = "i32";
break;
case VALUE_TYPE_I64:
str = "i64";
break;
case VALUE_TYPE_F32:
str = "f32";
break;
case VALUE_TYPE_F64:
str = "f64";
break;
}
if (strncmp(p, str, 3))
return false;
return true;
}
static bool
check_function_type(const WASMType *type,
const char *signature)
{
uint32 i;
const char *p = signature;
if (!p || *p++ != '(')
return false;
for (i = 0; i < type->param_count; i++) {
if (!check_type(type->types[i], p))
return false;
p += 3;
}
if (*p++ != ')')
return false;
if (type->result_count) {
if (!check_type(type->types[type->param_count], p))
return false;
p += 3;
}
if (*p != '\0')
return false;
return true;
}
AOTFunctionInstance*
aot_lookup_function(const AOTModuleInstance *module_inst,
const char *name, const char *signature)
{
uint32 i;
AOTModule *module = (AOTModule*)module_inst->aot_module.ptr;
for (i = 0; i < module->export_func_count; i++) {
if (!strcmp(module->export_funcs[i].func_name, name)
&& check_function_type(module->export_funcs[i].func_type,
signature))
return &module->export_funcs[i];
}
return NULL;
}
#define PUT_I64_TO_ADDR(addr, value) do { \
union { int64 val; uint32 parts[2]; } u; \
u.val = (value); \
(addr)[0] = u.parts[0]; \
(addr)[1] = u.parts[1]; \
} while (0)
#define PUT_F64_TO_ADDR(addr, value) do { \
union { float64 val; uint32 parts[2]; } u; \
u.val = (value); \
(addr)[0] = u.parts[0]; \
(addr)[1] = u.parts[1]; \
} while (0)
bool
aot_call_function(WASMExecEnv *exec_env,
AOTFunctionInstance *function,
unsigned argc, uint32 argv[])
{
AOTModuleInstance *module_inst = (AOTModuleInstance*)exec_env->module_inst;
AOTFuncType *func_type = function->func_type;
bool ret = wasm_runtime_invoke_native(function->func_ptr, func_type,
exec_env, argv, argc, argv);
return ret && !aot_get_exception(module_inst) ? true : false;
}
bool
aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst,
AOTFunctionInstance *func,
unsigned argc, uint32 argv[])
{
WASMExecEnv *exec_env;
bool ret;
if (!(exec_env = wasm_exec_env_create((WASMModuleInstanceCommon*)module_inst,
module_inst->default_wasm_stack_size))) {
aot_set_exception(module_inst, "allocate memory failed.");
return false;
}
ret = aot_call_function(exec_env, func, argc, argv);
wasm_exec_env_destroy(exec_env);
return ret;
}
void
aot_set_exception(AOTModuleInstance *module_inst,
const char *exception)
{
if (exception)
snprintf(module_inst->cur_exception,
sizeof(module_inst->cur_exception),
"Exception: %s", exception);
else
module_inst->cur_exception[0] = '\0';
}
void
aot_set_exception_with_id(AOTModuleInstance *module_inst,
uint32 id)
{
switch (id) {
case EXCE_UNREACHABLE:
aot_set_exception(module_inst, "unreachable");
break;
case EXCE_OUT_OF_MEMORY:
aot_set_exception(module_inst, "allocate memory failed");
break;
case EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS:
aot_set_exception(module_inst, "out of bounds memory access");
break;
case EXCE_INTEGER_OVERFLOW:
aot_set_exception(module_inst, "integer overflow");
break;
case EXCE_INTEGER_DIVIDE_BY_ZERO:
aot_set_exception(module_inst, "integer divide by zero");
break;
case EXCE_INVALID_CONVERSION_TO_INTEGER:
aot_set_exception(module_inst, "invalid conversion to integer");
break;
case EXCE_INVALID_FUNCTION_TYPE_INDEX:
aot_set_exception(module_inst, "indirect call type mismatch");
break;
case EXCE_INVALID_FUNCTION_INDEX:
aot_set_exception(module_inst, "invalid function index");
break;
case EXCE_UNDEFINED_ELEMENT:
aot_set_exception(module_inst, "undefined element");
break;
case EXCE_UNINITIALIZED_ELEMENT:
aot_set_exception(module_inst, "uninitialized element");
break;
case EXCE_CALL_UNLINKED_IMPORT_FUNC:
aot_set_exception(module_inst, "fail to call unlinked import function");
break;
default:
break;
}
}
const char*
aot_get_exception(AOTModuleInstance *module_inst)
{
if (module_inst->cur_exception[0] == '\0')
return NULL;
else
return module_inst->cur_exception;
}
void
aot_clear_exception(AOTModuleInstance *module_inst)
{
module_inst->cur_exception[0] = '\0';
}
int32
aot_module_malloc(AOTModuleInstance *module_inst, uint32 size)
{
uint8 *addr =
mem_allocator_malloc(module_inst->heap_handle.ptr, size);
if (!addr) {
aot_set_exception(module_inst, "out of memory");
return 0;
}
return (int32)(module_inst->heap_base_offset
+ (addr - (uint8*)module_inst->heap_data.ptr));
}
void
aot_module_free(AOTModuleInstance *module_inst, int32 ptr)
{
if (ptr) {
uint8 *addr = (uint8*)module_inst->heap_data.ptr
+ (ptr - module_inst->heap_base_offset);
if ((uint8*)module_inst->heap_data.ptr < addr
&& addr < (uint8*)module_inst->heap_data_end.ptr)
mem_allocator_free(module_inst->heap_handle.ptr, addr);
}
}
int32
aot_module_dup_data(AOTModuleInstance *module_inst,
const char *src, uint32 size)
{
int32 buffer_offset = aot_module_malloc(module_inst, size);
if (buffer_offset != 0) {
char *buffer;
buffer = aot_addr_app_to_native(module_inst, buffer_offset);
memcpy(buffer, src, size);
}
return buffer_offset;
}
bool
aot_validate_app_addr(AOTModuleInstance *module_inst,
int32 app_offset, uint32 size)
{
uint8 *addr;
/* integer overflow check */
if(app_offset + (int32)size < app_offset) {
goto fail;
}
if (0 <= app_offset
&& app_offset < (int32)module_inst->memory_data_size) {
addr = (uint8*)module_inst->memory_data.ptr + app_offset;
if (!((uint8*)module_inst->memory_data.ptr <= addr
&& addr + size <= (uint8*)module_inst->memory_data_end.ptr))
goto fail;
return true;
}
/* Currently heap_size is no more than 1G, and heap_base_offset is 1G,
heap_base_offset + heap_data_size will not be larger than INT32_MAX */
else if (module_inst->heap_base_offset < app_offset
&& app_offset < module_inst->heap_base_offset
+ (int32)module_inst->heap_data_size) {
addr = (uint8*)module_inst->heap_data.ptr
+ (app_offset - module_inst->heap_base_offset);
if (!((uint8*)module_inst->heap_data.ptr <= addr
&& addr + size <= (uint8*)module_inst->heap_data_end.ptr))
goto fail;
return true;
}
fail:
aot_set_exception(module_inst, "out of bounds memory access");
return false;
}
bool
aot_validate_native_addr(AOTModuleInstance *module_inst,
void *native_ptr, uint32 size)
{
uint8 *addr = native_ptr;
/* integer overflow check */
if (addr + size < addr) {
goto fail;
}
if (((uint8*)module_inst->memory_data.ptr <= addr
&& addr + size <= (uint8*)module_inst->memory_data_end.ptr)
|| ((uint8*)module_inst->heap_data.ptr <= addr
&& addr + size <= (uint8*)module_inst->heap_data_end.ptr)
)
return true;
fail:
aot_set_exception(module_inst, "out of bounds memory access");
return false;
}
void *
aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset)
{
if (0 <= app_offset && app_offset < module_inst->heap_base_offset)
return (uint8*)module_inst->memory_data.ptr + app_offset;
if (module_inst->heap_base_offset < app_offset
&& app_offset < module_inst->heap_base_offset
+ (int32)module_inst->heap_data_size)
return (uint8*)module_inst->heap_data.ptr
+ (app_offset - module_inst->heap_base_offset);
return NULL;
}
int32
aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr)
{
if ((uint8*)module_inst->memory_data.ptr <= (uint8*)native_ptr
&& (uint8*)native_ptr < (uint8*)module_inst->memory_data_end.ptr)
return (int32)((uint8*)native_ptr - (uint8*)module_inst->memory_data.ptr);
if ((uint8*)module_inst->heap_data.ptr <= (uint8*)native_ptr
&& (uint8*)native_ptr < (uint8*)module_inst->heap_data_end.ptr)
return (int32)(module_inst->heap_base_offset
+ ((uint8*)native_ptr - (uint8*)module_inst->heap_data.ptr));
return 0;
}
bool
aot_get_app_addr_range(AOTModuleInstance *module_inst,
int32 app_offset,
int32 *p_app_start_offset,
int32 *p_app_end_offset)
{
int32 app_start_offset, app_end_offset;
if (0 <= app_offset && app_offset < (int32)module_inst->memory_data_size) {
app_start_offset = 0;
app_end_offset = (int32)module_inst->memory_data_size;
}
else if (module_inst->heap_base_offset < app_offset
&& app_offset < module_inst->heap_base_offset
+ (int32)module_inst->heap_data_size) {
app_start_offset = module_inst->heap_base_offset;
app_end_offset = module_inst->heap_base_offset
+ (int32)module_inst->heap_data_size;
}
else
return false;
if (p_app_start_offset)
*p_app_start_offset = app_start_offset;
if (p_app_end_offset)
*p_app_end_offset = app_end_offset;
return true;
}
bool
aot_get_native_addr_range(AOTModuleInstance *module_inst,
uint8 *native_ptr,
uint8 **p_native_start_addr,
uint8 **p_native_end_addr)
{
uint8 *native_start_addr, *native_end_addr;
if ((uint8*)module_inst->memory_data.ptr <= (uint8*)native_ptr
&& (uint8*)native_ptr < (uint8*)module_inst->memory_data_end.ptr) {
native_start_addr = (uint8*)module_inst->memory_data.ptr;
native_end_addr = (uint8*)module_inst->memory_data_end.ptr;
}
else if ((uint8*)module_inst->heap_data.ptr <= (uint8*)native_ptr
&& (uint8*)native_ptr < (uint8*)module_inst->heap_data_end.ptr) {
native_start_addr = (uint8*)module_inst->heap_data.ptr;
native_end_addr = (uint8*)module_inst->heap_data_end.ptr;
}
else
return false;
if (p_native_start_addr)
*p_native_start_addr = native_start_addr;
if (p_native_end_addr)
*p_native_end_addr = native_end_addr;
return true;
}
bool
aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count)
{
uint8 *mem_data_old = module_inst->memory_data.ptr, *mem_data_new;
uint32 cur_page_count = module_inst->mem_cur_page_count;
uint32 max_page_count = module_inst->mem_max_page_count;
uint32 total_page_count = cur_page_count + inc_page_count;
uint32 old_size = NumBytesPerPage * cur_page_count;
uint64 total_size = (uint64)NumBytesPerPage * total_page_count;
if (inc_page_count <= 0)
/* No need to enlarge memory */
return true;
if (total_page_count < cur_page_count /* integer overflow */
|| total_page_count > max_page_count) {
aot_set_exception(module_inst, "fail to enlarge memory.");
return false;
}
if (total_size >= UINT32_MAX
|| !(mem_data_new = wasm_malloc((uint32)total_size))) {
aot_set_exception(module_inst, "fail to enlarge memory.");
return false;
}
memcpy(mem_data_new, mem_data_old, old_size);
memset(mem_data_new + old_size, 0, (uint32)total_size - old_size);
module_inst->mem_cur_page_count = total_page_count;
module_inst->memory_data_size = (uint32)total_size;
module_inst->memory_data.ptr = mem_data_new;
module_inst->memory_data_end.ptr = mem_data_new + (uint32)total_size;
wasm_free(mem_data_old);
return true;
}
bool
aot_is_wasm_type_equal(AOTModuleInstance *module_inst,
uint32 type1_idx, uint32 type2_idx)
{
WASMType *type1, *type2;
AOTModule *module = (AOTModule*)module_inst->aot_module.ptr;
if (type1_idx >= module->func_type_count
|| type2_idx >= module->func_type_count) {
aot_set_exception(module_inst, "type index out of bounds");
return false;
}
if (type1_idx == type2_idx)
return true;
type1 = module->func_types[type1_idx];
type2 = module->func_types[type2_idx];
return wasm_type_equal(type1, type2);
}

View File

@ -0,0 +1,434 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _AOT_RUNTIME_H_
#define _AOT_RUNTIME_H_
#include "bh_platform.h"
#include "../common/wasm_runtime_common.h"
#include "../interpreter/wasm_runtime.h"
#include "../compilation/aot.h"
#if WASM_ENABLE_JIT != 0
#include "../compilation/aot_llvm.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define AOT_MAGIC_NUMBER 0x746f6100
#define AOT_CURRENT_VERSION 1
typedef enum AOTExceptionID {
EXCE_UNREACHABLE = 0,
EXCE_OUT_OF_MEMORY,
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
EXCE_INTEGER_OVERFLOW,
EXCE_INTEGER_DIVIDE_BY_ZERO,
EXCE_INVALID_CONVERSION_TO_INTEGER,
EXCE_INVALID_FUNCTION_TYPE_INDEX,
EXCE_INVALID_FUNCTION_INDEX,
EXCE_UNDEFINED_ELEMENT,
EXCE_UNINITIALIZED_ELEMENT,
EXCE_CALL_UNLINKED_IMPORT_FUNC,
EXCE_NUM,
} AOTExceptionID;
typedef enum AOTSectionType {
AOT_SECTION_TYPE_TARGET_INFO = 0,
AOT_SECTION_TYPE_INIT_DATA,
AOT_SECTION_TYPE_TEXT,
AOT_SECTION_TYPE_FUNCTION,
AOT_SECTION_TYPE_EXPORT,
AOT_SECTION_TYPE_RELOCATION,
AOT_SECTION_TYPE_SIGANATURE
} AOTSectionType;
typedef struct AOTObjectDataSection {
char *name;
uint8 *data;
uint32 size;
} AOTObjectDataSection;
/* Relocation info */
typedef struct AOTRelocation {
uint64 relocation_offset;
uint64 relocation_addend;
uint32 relocation_type;
char *symbol_name;
/* index in the symbol offset field */
uint32 symbol_index;
} AOTRelocation;
/* Relocation Group */
typedef struct AOTRelocationGroup {
char *section_name;
/* index in the symbol offset field */
uint32 name_index;
uint32 relocation_count;
AOTRelocation *relocations;
} AOTRelocationGroup;
typedef struct AOTModule {
uint32 module_type;
/* memory info */
uint32 mem_init_page_count;
uint32 mem_max_page_count;
uint32 mem_init_data_count;
AOTMemInitData **mem_init_data_list;
/* table info */
uint32 table_size;
uint32 table_init_data_count;
AOTTableInitData **table_init_data_list;
/* function type info */
uint32 func_type_count;
AOTFuncType **func_types;
/* import global varaible info */
uint32 import_global_count;
AOTImportGlobal *import_globals;
/* global variable info */
uint32 global_count;
AOTGlobal *globals;
/* total global variable size */
uint32 global_data_size;
/* import function info */
uint32 import_func_count;
AOTImportFunc *import_funcs;
/* function info */
uint32 func_count;
/* point to AOTed/JITed functions */
void **func_ptrs;
/* function type indexes */
uint32 *func_type_indexes;
/* export function info */
uint32 export_func_count;
AOTExportFunc *export_funcs;
/* start function index, -1 denotes no start function */
uint32 start_func_index;
/* start function, point to AOTed/JITed function */
void *start_function;
/* AOTed code, NULL for JIT mode */
void *code;
uint32 code_size;
/* data sections in AOT object file, including .data, .rodata
* and .rodata.cstN. NULL for JIT mode. */
AOTObjectDataSection *data_sections;
uint32 data_section_count;
/* constant string set */
HashMap *const_str_set;
/* is jit mode or not */
bool is_jit_mode;
#if WASM_ENABLE_JIT
WASMModule *wasm_module;
AOTCompContext *comp_ctx;
AOTCompData *comp_data;
#endif
#if WASM_ENABLE_LIBC_WASI != 0
WASIArguments wasi_args;
bool is_wasi_module;
#endif
} AOTModule;
typedef union {
uint64 _make_it_8_bytes_;
void *ptr;
} AOTPointer;
typedef struct AOTModuleInstance {
uint32 module_type;
/* memory space info */
uint32 mem_cur_page_count;
uint32 mem_max_page_count;
uint32 memory_data_size;
AOTPointer memory_data;
AOTPointer memory_data_end;
/* heap space info */
int32 heap_base_offset;
uint32 heap_data_size;
AOTPointer heap_data;
AOTPointer heap_data_end;
AOTPointer heap_handle;
/* global and table info */
uint32 global_data_size;
uint32 table_size;
AOTPointer global_data;
AOTPointer table_data;
/* funciton pointer array */
AOTPointer func_ptrs;
/* function type indexes */
AOTPointer func_type_indexes;
/* The exception buffer for current thread. */
char cur_exception[128];
/* The custom data that can be set/get by
* wasm_runtime_set_custom_data/wasm_runtime_get_custom_data */
AOTPointer custom_data;
/* The AOT module */
AOTPointer aot_module;
/* WASI context */
AOTPointer wasi_ctx;
/* others */
int32 temp_ret;
uint32 llvm_stack;
int32 DYNAMICTOP_PTR_offset;
uint32 default_wasm_stack_size;
/* reserved */
uint32 reserved[16];
union {
uint64 _make_it_8_byte_aligned_;
uint8 bytes[1];
} global_table_heap_data;
} AOTModuleInstance;
typedef AOTExportFunc AOTFunctionInstance;
/* Target info, read from ELF header of object file */
typedef struct AOTTargetInfo {
/* Binary type, elf32l/elf32b/elf64l/elf64b */
uint32 bin_type;
/* Object file type */
uint16 e_type;
/* Architecture */
uint16 e_machine;
/* Object file version */
uint32 e_version;
/* Processor-specific flags */
uint32 e_flags;
/* Reserved */
uint32 reserved;
/* Arch name */
char arch[16];
} AOTTargetInfo;
/**
* Load a AOT module from aot file buffer
* @param buf the byte buffer which contains the AOT file data
* @param size the size of the buffer
* @param error_buf output of the error info
* @param error_buf_size the size of the error string
*
* @return return AOT module loaded, NULL if failed
*/
AOTModule*
aot_load_from_aot_file(const uint8 *buf, uint32 size,
char *error_buf, uint32 error_buf_size);
/**
* Load a AOT module from a specified AOT section list.
*
* @param section_list the section list which contains each section data
* @param error_buf output of the error info
* @param error_buf_size the size of the error string
*
* @return return AOT module loaded, NULL if failed
*/
AOTModule*
aot_load_from_sections(AOTSection *section_list,
char *error_buf, uint32 error_buf_size);
#if WASM_ENABLE_JIT != 0
/**
* Convert WASM module to AOT module
*
* @param wasm_module the WASM module to convert
* @param error_buf output of the error info
* @param error_buf_size the size of the error string
*
* @return return AOT module loaded, NULL if failed
*/
AOTModule*
aot_convert_wasm_module(WASMModule *wasm_module,
char *error_buf, uint32 error_buf_size);
#endif
/**
* Unload a AOT module.
*
* @param module the module to be unloaded
*/
void
aot_unload(AOTModule *module);
/**
* Instantiate a AOT module.
*
* @param module the AOT module to instantiate
* @param heap_size the default heap size of the module instance, a heap will
* be created besides the app memory space. Both wasm app and native
* function can allocate memory from the heap. If heap_size is 0, the
* default heap size will be used.
* @param error_buf buffer to output the error info if failed
* @param error_buf_size the size of the error buffer
*
* @return return the instantiated AOT module instance, NULL if failed
*/
AOTModuleInstance*
aot_instantiate(AOTModule *module,
uint32 stack_size, uint32 heap_size,
char *error_buf, uint32 error_buf_size);
/**
* Deinstantiate a AOT module instance, destroy the resources.
*
* @param module_inst the AOT module instance to destroy
*/
void
aot_deinstantiate(AOTModuleInstance *module_inst);
/**
* Lookup an exported function in the AOT module instance.
*
* @param module_inst the module instance
* @param name the name of the function
* @param signature the signature of the function, use "i32"/"i64"/"f32"/"f64"
* to represent the type of i32/i64/f32/f64, e.g. "(i32i64)" "(i32)f32"
*
* @return the function instance found
*/
AOTFunctionInstance*
aot_lookup_function(const AOTModuleInstance *module_inst,
const char *name, const char *signature);
/**
* Call the given AOT function of a AOT module instance with
* arguments.
*
* @param exec_env the execution environment
* @param function the function to be called
* @param argc the number of arguments
* @param argv the arguments. If the function method has return value,
* the first (or first two in case 64-bit return value) element of
* argv stores the return value of the called AOT function after this
* function returns.
*
* @return true if success, false otherwise and exception will be thrown,
* the caller can call aot_get_exception to get exception info.
*/
bool
aot_call_function(WASMExecEnv *exec_env,
AOTFunctionInstance *function,
unsigned argc, uint32 argv[]);
bool
aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst,
AOTFunctionInstance *function,
unsigned argc, uint32 argv[]);
/**
* Set AOT module instance exception with exception string
*
* @param module the AOT module instance
*
* @param exception current exception string
*/
void
aot_set_exception(AOTModuleInstance *module_inst,
const char *exception);
void
aot_set_exception_with_id(AOTModuleInstance *module_inst,
uint32 id);
/**
* Get exception info of the AOT module instance.
*
* @param module_inst the AOT module instance
*
* @return the exception string
*/
const char*
aot_get_exception(AOTModuleInstance *module_inst);
/**
* Clear exception info of the AOT module instance.
*
* @param module_inst the AOT module instance
*/
void
aot_clear_exception(AOTModuleInstance *module_inst);
int32
aot_module_malloc(AOTModuleInstance *module_inst, uint32 size);
void
aot_module_free(AOTModuleInstance *module_inst, int32 ptr);
int32
aot_module_dup_data(AOTModuleInstance *module_inst,
const char *src, uint32 size);
bool
aot_validate_app_addr(AOTModuleInstance *module_inst,
int32 app_offset, uint32 size);
bool
aot_validate_native_addr(AOTModuleInstance *module_inst,
void *native_ptr, uint32 size);
void *
aot_addr_app_to_native(AOTModuleInstance *module_inst, int32 app_offset);
int32
aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr);
bool
aot_get_app_addr_range(AOTModuleInstance *module_inst,
int32 app_offset,
int32 *p_app_start_offset,
int32 *p_app_end_offset);
bool
aot_get_native_addr_range(AOTModuleInstance *module_inst,
uint8 *native_ptr,
uint8 **p_native_start_addr,
uint8 **p_native_end_addr);
bool
aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count);
/**
* Compare whether two wasm types are equal according to the indexs
*
* @param module_inst the AOT module instance
* @param type1_idx index of the first wasm type
* @param type2_idx index of the second wasm type
*
* @return true if equal, false otherwise
*/
bool
aot_is_wasm_type_equal(AOTModuleInstance *module_inst,
uint32 type1_idx, uint32 type2_idx);
uint32
aot_get_plt_table_size();
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* end of _AOT_RUNTIME_H_ */

View File

@ -0,0 +1,13 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (IWASM_AOT_DIR ${CMAKE_CURRENT_LIST_DIR})
add_definitions (-DWASM_ENABLE_AOT=1)
include_directories (${IWASM_AOT_DIR})
file (GLOB c_source_all ${IWASM_AOT_DIR}/*.c)
set (IWASM_AOT_SOURCE ${c_source_all})