Implement wasm-c-api frame/trap APIs for interpreter mode (#660)

And enable to cache compiled AOT file buffer for wasm-c-api JIT mode
Avoid checks that rely on undefined C behavior
Fix issues of wasm-c-api sample trap and callback_chain

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang 2021-07-06 17:05:59 +08:00 committed by GitHub
parent d91047cc37
commit b554a9d05d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 576 additions and 104 deletions

View File

@ -132,7 +132,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a
Project Technical Steering Committee Project Technical Steering Committee
==================================== ====================================
The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC. The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC.
The current TSC members: The current TSC members:
- [lum1n0us](https://github.com/lum1n0us) - **Liang He** <liang.he@intel.com> - [lum1n0us](https://github.com/lum1n0us) - **Liang He** <liang.he@intel.com>
- [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin** <xiaokang.qxk@antgroup.com> - [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin** <xiaokang.qxk@antgroup.com>

View File

@ -2,23 +2,23 @@
## Section 1. Guiding Principle ## Section 1. Guiding Principle
The WebAssembly Micro Runtime (WAMR) project is part of the The WebAssembly Micro Runtime (WAMR) project is part of the
Bytecode Alliance (BA) which operates transparently, openly, Bytecode Alliance (BA) which operates transparently, openly,
collaboratively, and ethically. Project proposals, timelines, and status collaboratively, and ethically. Project proposals, timelines, and status
must not merely be open, but also easily visible to outsiders. must not merely be open, but also easily visible to outsiders.
## Section 2. Project Governance under Bytecode Alliance ## Section 2. Project Governance under Bytecode Alliance
Technical leadership for the WAMR projects within the Bytecode Alliance Technical leadership for the WAMR projects within the Bytecode Alliance
is delegated to the projects through the project charter. Though the BA TSC is delegated to the projects through the project charter. Though the BA TSC
will not interfere with day-to-day discussions, votes or meetings of the PTSC, will not interfere with day-to-day discussions, votes or meetings of the PTSC,
the BA TSC may request additional amendments to the PTSC charter when the BA TSC may request additional amendments to the PTSC charter when
there is misalignment between the project charter and the BA mission and values. there is misalignment between the project charter and the BA mission and values.
The PTSC structure described in this document may be overhauled as part of The PTSC structure described in this document may be overhauled as part of
establishing a BA TSC in order to adhere to constraints or requirements that establishing a BA TSC in order to adhere to constraints or requirements that
TSC will impose on project-level governance. TSC will impose on project-level governance.
## Section 3. Establishment of the PTSC ## Section 3. Establishment of the PTSC
@ -26,7 +26,7 @@ TSC will impose on project-level governance.
PTSC memberships are not time-limited. There is no maximum size of the PTSC. PTSC memberships are not time-limited. There is no maximum size of the PTSC.
The size is expected to vary in order to ensure adequate coverage of important The size is expected to vary in order to ensure adequate coverage of important
areas of expertise, balanced with the ability to make decisions efficiently. areas of expertise, balanced with the ability to make decisions efficiently.
The PTSC must have at least four members. The PTSC must have at least four members.
There is no specific set of requirements or qualifications for PTSC There is no specific set of requirements or qualifications for PTSC
membership beyond these rules. The PTSC may add additional members to the membership beyond these rules. The PTSC may add additional members to the
@ -77,11 +77,11 @@ The PTSC will define WAMR projects release vehicles.
## Section 5. WAMR Project Operations ## Section 5. WAMR Project Operations
The PTSC will establish and maintain a development process for the WAMR The PTSC will establish and maintain a development process for the WAMR
project. The development process will establish guidelines project. The development process will establish guidelines
for how the developers and community will operate. It will, for example, for how the developers and community will operate. It will, for example,
establish appropriate timelines for PTSC review (e.g. agenda items must be establish appropriate timelines for PTSC review (e.g. agenda items must be
published at least a certain number of hours in advance of a PTSC published at least a certain number of hours in advance of a PTSC
meeting). meeting).
The PTSC and entire technical community will follow any processes as may The PTSC and entire technical community will follow any processes as may
@ -106,7 +106,7 @@ the candidate's election. Elections shall be done within the projects by
the Collaborators active in the project. the Collaborators active in the project.
The PTSC will elect from amongst voting PTSC members a PTSC Chairperson to The PTSC will elect from amongst voting PTSC members a PTSC Chairperson to
work on building an agenda for PTSC meetings. The PTSC shall hold annual work on building an agenda for PTSC meetings. The PTSC shall hold annual
elections to select a PTSC Chairperson; there are no limits on the number elections to select a PTSC Chairperson; there are no limits on the number
of terms a PTSC Chairperson may serve. of terms a PTSC Chairperson may serve.

View File

@ -1896,7 +1896,7 @@ aot_validate_app_addr(AOTModuleInstance *module_inst,
} }
/* integer overflow check */ /* integer overflow check */
if(app_offset + size < app_offset) { if(app_offset > UINT32_MAX - size) {
goto fail; goto fail;
} }
@ -1920,7 +1920,7 @@ aot_validate_native_addr(AOTModuleInstance *module_inst,
} }
/* integer overflow check */ /* integer overflow check */
if (addr + size < addr) { if ((uintptr_t)addr > UINTPTR_MAX - size) {
goto fail; goto fail;
} }

View File

@ -189,7 +189,7 @@ failed: \
size_t i = 0; \ size_t i = 0; \
memset(out, 0, sizeof(Vector)); \ memset(out, 0, sizeof(Vector)); \
\ \
if (!src->size) { \ if (!src || !src->size) { \
return; \ return; \
} \ } \
\ \
@ -232,6 +232,7 @@ WASM_DEFINE_VEC_OWN(store, wasm_store_delete)
WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal)
WASM_DEFINE_VEC_OWN(instance, wasm_instance_delete_internal) WASM_DEFINE_VEC_OWN(instance, wasm_instance_delete_internal)
WASM_DEFINE_VEC_OWN(extern, wasm_extern_delete) WASM_DEFINE_VEC_OWN(extern, wasm_extern_delete)
WASM_DEFINE_VEC_OWN(frame, wasm_frame_delete)
static inline bool static inline bool
valid_module_type(uint32 module_type) valid_module_type(uint32 module_type)
@ -255,6 +256,21 @@ valid_module_type(uint32 module_type)
return result; return result;
} }
/* conflicting declaration between aot_export.h and aot.h */
#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0
bool
aot_compile_wasm_file_init();
void
aot_compile_wasm_file_destroy();
uint8*
aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size,
uint32 opt_level, uint32 size_level,
char *error_buf, uint32 error_buf_size,
uint32 *p_aot_file_size);
#endif
/* Runtime Environment */ /* Runtime Environment */
static void static void
wasm_engine_delete_internal(wasm_engine_t *engine) wasm_engine_delete_internal(wasm_engine_t *engine)
@ -264,6 +280,10 @@ wasm_engine_delete_internal(wasm_engine_t *engine)
wasm_runtime_free(engine); wasm_runtime_free(engine);
} }
#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0
aot_compile_wasm_file_destroy();
#endif
wasm_runtime_destroy(); wasm_runtime_destroy();
} }
@ -311,6 +331,12 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts)
bh_log_set_verbose_level(3); bh_log_set_verbose_level(3);
#endif #endif
#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0
if (!aot_compile_wasm_file_init()) {
goto failed;
}
#endif
/* create wasm_engine_t */ /* create wasm_engine_t */
if (!(engine = malloc_internal(sizeof(wasm_engine_t)))) { if (!(engine = malloc_internal(sizeof(wasm_engine_t)))) {
goto failed; goto failed;
@ -1289,10 +1315,106 @@ wasm_val_same(const wasm_val_t *v1, const wasm_val_t *v2)
return false; return false;
} }
static wasm_frame_t *
wasm_frame_new(wasm_instance_t *instance,
size_t module_offset,
uint32 func_index,
size_t func_offset)
{
wasm_frame_t *frame;
if (!(frame = malloc_internal(sizeof(wasm_frame_t)))) {
return NULL;
}
frame->instance = instance;
frame->module_offset = module_offset;
frame->func_index = func_index;
frame->func_offset = func_offset;
return frame;
}
own wasm_frame_t *
wasm_frame_copy(const wasm_frame_t *src)
{
if (!src) {
return NULL;
}
return wasm_frame_new(src->instance, src->module_offset, src->func_index,
src->func_offset);
}
void
wasm_frame_delete(own wasm_frame_t *frame)
{
if (!frame) {
return;
}
wasm_runtime_free(frame);
}
struct wasm_instance_t *
wasm_frame_instance(const wasm_frame_t *frame)
{
return frame ? frame->instance : NULL;
}
size_t
wasm_frame_module_offset(const wasm_frame_t *frame)
{
return frame ? frame->module_offset : 0;
}
uint32_t
wasm_frame_func_index(const wasm_frame_t *frame)
{
return frame ? frame->func_index : 0;
}
size_t
wasm_frame_func_offset(const wasm_frame_t *frame)
{
return frame ? frame->func_offset : 0;
}
static wasm_trap_t * static wasm_trap_t *
wasm_trap_new_internal(const char *string) wasm_trap_new_internal(WASMModuleInstanceCommon *inst_comm_rt,
const char *default_error_info)
{ {
wasm_trap_t *trap; wasm_trap_t *trap;
const char *error_info = NULL;
wasm_instance_vec_t *instances;
wasm_instance_t *frame_instance = NULL;
uint32 i;
if (!singleton_engine || !singleton_engine->stores
|| !singleton_engine->stores->num_elems) {
return NULL;
}
#if WASM_ENABLE_INTERP != 0
if (inst_comm_rt->module_type == Wasm_Module_Bytecode) {
if (!(error_info =
wasm_get_exception((WASMModuleInstance *)inst_comm_rt))) {
return NULL;
}
}
#endif
#if WASM_ENABLE_AOT != 0
if (inst_comm_rt->module_type == Wasm_Module_AoT) {
if (!(error_info =
aot_get_exception((AOTModuleInstance *)inst_comm_rt))) {
return NULL;
}
}
#endif
if (!error_info && !(error_info = default_error_info)) {
return NULL;
}
if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) { if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) {
return NULL; return NULL;
@ -1302,11 +1424,39 @@ wasm_trap_new_internal(const char *string)
goto failed; goto failed;
} }
wasm_name_new_from_string(trap->message, string); wasm_name_new_from_string_nt(trap->message, error_info);
if (strlen(string) && !trap->message->data) { if (strlen(error_info) && !trap->message->data) {
goto failed; goto failed;
} }
#if WASM_ENABLE_DUMP_CALL_STACK != 0
#if WASM_ENABLE_INTERP != 0
if (inst_comm_rt->module_type == Wasm_Module_Bytecode) {
trap->frames = ((WASMModuleInstance *)inst_comm_rt)->frames;
}
#endif
#endif /* WASM_ENABLE_DUMP_CALL_STACK != 0 */
/* allow a NULL frames list */
if (!trap->frames) {
return trap;
}
if (!(instances = singleton_engine->stores->data[0]->instances)) {
goto failed;
}
for (i = 0; i < instances->num_elems; i++) {
if (instances->data[i]->inst_comm_rt == inst_comm_rt) {
frame_instance = instances->data[i];
break;
}
}
for (i = 0; i < trap->frames->num_elems; i++) {
(((wasm_frame_t *)trap->frames->data) + i)->instance = frame_instance;
}
return trap; return trap;
failed: failed:
wasm_trap_delete(trap); wasm_trap_delete(trap);
@ -1342,6 +1492,7 @@ wasm_trap_delete(wasm_trap_t *trap)
} }
DEINIT_VEC(trap->message, wasm_byte_vec_delete); DEINIT_VEC(trap->message, wasm_byte_vec_delete);
/* reuse frames of WASMModuleInstance, do not free it here */
wasm_runtime_free(trap); wasm_runtime_free(trap);
} }
@ -1356,6 +1507,65 @@ wasm_trap_message(const wasm_trap_t *trap, own wasm_message_t *out)
wasm_byte_vec_copy(out, trap->message); wasm_byte_vec_copy(out, trap->message);
} }
own wasm_frame_t *
wasm_trap_origin(const wasm_trap_t *trap)
{
wasm_frame_t *latest_frame;
if (!trap || !trap->frames || !trap->frames->num_elems) {
return NULL;
}
/* first frame is the latest frame */
latest_frame = (wasm_frame_t *)trap->frames->data;
return wasm_frame_copy(latest_frame);
}
void
wasm_trap_trace(const wasm_trap_t *trap, own wasm_frame_vec_t *out)
{
uint32 i;
if (!trap || !out) {
return;
}
if (!trap->frames || !trap->frames->num_elems) {
wasm_frame_vec_new_empty(out);
return;
}
wasm_frame_vec_new_uninitialized(out, trap->frames->num_elems);
if (out->size && !out->data) {
return;
}
for (i = 0; i < trap->frames->num_elems; i++) {
wasm_frame_t *frame;
frame = ((wasm_frame_t *)trap->frames->data) + i;
if (!(out->data[i] =
wasm_frame_new(frame->instance, frame->module_offset,
frame->func_index, frame->func_offset))) {
goto failed;
}
out->num_elems++;
}
return;
failed:
for (i = 0; i < out->num_elems; i++) {
if (out->data[i]) {
wasm_runtime_free(out->data[i]);
}
}
if (out->data) {
wasm_runtime_free(out->data);
}
}
struct wasm_module_ex_t { struct wasm_module_ex_t {
struct WASMModuleCommon *module_comm_rt; struct WASMModuleCommon *module_comm_rt;
wasm_byte_vec_t *binary; wasm_byte_vec_t *binary;
@ -1386,6 +1596,10 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary)
{ {
char error_buf[128] = { 0 }; char error_buf[128] = { 0 };
wasm_module_ex_t *module_ex = NULL; wasm_module_ex_t *module_ex = NULL;
#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0
uint8 *aot_file_buf = NULL;
uint32 aot_file_size;
#endif
bh_assert(singleton_engine); bh_assert(singleton_engine);
@ -1401,12 +1615,35 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary)
INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data); INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data);
module_ex->module_comm_rt = wasm_runtime_load( #if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0
(uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, if (get_package_type((uint8 *)module_ex->binary->data,
error_buf, (uint32)sizeof(error_buf)); (uint32)module_ex->binary->size)
if (!(module_ex->module_comm_rt)) { == Wasm_Module_Bytecode) {
LOG_ERROR(error_buf); if (!(aot_file_buf = aot_compile_wasm_file(
goto failed; (uint8 *)module_ex->binary->data,
(uint32)module_ex->binary->size, 3, 3, error_buf,
(uint32)sizeof(error_buf), &aot_file_size))) {
LOG_ERROR(error_buf);
goto failed;
}
if (!(module_ex->module_comm_rt =
wasm_runtime_load(aot_file_buf, aot_file_size, error_buf,
(uint32)sizeof(error_buf)))) {
LOG_ERROR(error_buf);
goto failed;
}
}
else
#endif
{
module_ex->module_comm_rt = wasm_runtime_load(
(uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size,
error_buf, (uint32)sizeof(error_buf));
if (!(module_ex->module_comm_rt)) {
LOG_ERROR(error_buf);
goto failed;
}
} }
/* add it to a watching list in store */ /* add it to a watching list in store */
@ -2255,12 +2492,13 @@ failed:
if (argv != argv_buf) if (argv != argv_buf)
wasm_runtime_free(argv); wasm_runtime_free(argv);
/* trap -> exception -> trap */
if (wasm_runtime_get_exception(func->inst_comm_rt)) { if (wasm_runtime_get_exception(func->inst_comm_rt)) {
return wasm_trap_new_internal( return wasm_trap_new_internal(func->inst_comm_rt, NULL);
wasm_runtime_get_exception(func->inst_comm_rt));
} }
else { else {
return wasm_trap_new_internal("wasm_func_call failed"); return wasm_trap_new_internal(func->inst_comm_rt,
"wasm_func_call failed");
} }
} }
@ -3446,8 +3684,8 @@ wasm_instance_new(wasm_store_t *store,
own wasm_trap_t **traps) own wasm_trap_t **traps)
{ {
char error_buf[128] = { 0 }; char error_buf[128] = { 0 };
const uint32 stack_size = 16 * 1024; const uint32 stack_size = 32 * 1024;
const uint32 heap_size = 16 * 1024; const uint32 heap_size = 32 * 1024;
uint32 import_count = 0; uint32 import_count = 0;
wasm_instance_t *instance = NULL; wasm_instance_t *instance = NULL;
uint32 i = 0; uint32 i = 0;

View File

@ -86,8 +86,16 @@ struct wasm_ref_t {
uint32 obj; uint32 obj;
}; };
struct wasm_frame_t {
wasm_instance_t *instance;
uint32 module_offset;
uint32 func_index;
uint32 func_offset;
};
struct wasm_trap_t { struct wasm_trap_t {
wasm_byte_vec_t *message; wasm_byte_vec_t *message;
Vector *frames;
}; };
struct wasm_func_t { struct wasm_func_t {

View File

@ -2135,19 +2135,82 @@ extern void
wasm_set_ref_types_flag(bool enable); wasm_set_ref_types_flag(bool enable);
#endif #endif
typedef struct AOTFileMap {
uint8 *wasm_file_buf;
uint32 wasm_file_size;
uint8 *aot_file_buf;
uint32 aot_file_size;
struct AOTFileMap *next;
} AOTFileMap;
static bool aot_compile_wasm_file_inited = false;
static AOTFileMap *aot_file_maps = NULL;
static korp_mutex aot_file_map_lock;
bool
aot_compile_wasm_file_init()
{
if (aot_compile_wasm_file_inited) {
return true;
}
if (BHT_OK != os_mutex_init(&aot_file_map_lock)) {
return false;
}
aot_file_maps = NULL;
aot_compile_wasm_file_inited = true;
return true;
}
void
aot_compile_wasm_file_destroy()
{
AOTFileMap *file_map = aot_file_maps, *file_map_next;
if (!aot_compile_wasm_file_inited) {
return;
}
while (file_map) {
file_map_next = file_map->next;
wasm_runtime_free(file_map->wasm_file_buf);
wasm_runtime_free(file_map->aot_file_buf);
wasm_runtime_free(file_map);
file_map = file_map_next;
}
aot_file_maps = NULL;
os_mutex_destroy(&aot_file_map_lock);
aot_compile_wasm_file_inited = false;
}
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,
"WASM module load failed: %s", string);
}
}
uint8* uint8*
aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size,
uint32 opt_level, uint32 size_level, uint32 opt_level, uint32 size_level,
char *error_buf, uint32 error_buf_size,
uint32 *p_aot_file_size) uint32 *p_aot_file_size)
{ {
WASMModuleCommon *wasm_module = NULL; WASMModule *wasm_module = NULL;
AOTCompData *comp_data = NULL; AOTCompData *comp_data = NULL;
AOTCompContext *comp_ctx = NULL; AOTCompContext *comp_ctx = NULL;
RuntimeInitArgs init_args; RuntimeInitArgs init_args;
AOTCompOption option = { 0 }; AOTCompOption option = { 0 };
AOTFileMap *file_map = NULL, *file_map_next;
uint8 *wasm_file_buf_cloned = NULL;
uint8 *aot_file_buf = NULL; uint8 *aot_file_buf = NULL;
uint32 aot_file_size; uint32 aot_file_size;
char error_buf[128];
option.is_jit_mode = false; option.is_jit_mode = false;
option.opt_level = opt_level; option.opt_level = opt_level;
@ -2155,7 +2218,6 @@ aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size,
option.output_format = AOT_FORMAT_FILE; option.output_format = AOT_FORMAT_FILE;
/* default value, enable or disable depends on the platform */ /* default value, enable or disable depends on the platform */
option.bounds_checks = 2; option.bounds_checks = 2;
option.enable_simd = true;
option.enable_aux_stack_check = true; option.enable_aux_stack_check = true;
#if WASM_ENABLE_BULK_MEMORY != 0 #if WASM_ENABLE_BULK_MEMORY != 0
option.enable_bulk_memory = true; option.enable_bulk_memory = true;
@ -2187,46 +2249,94 @@ aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size,
init_args.mem_alloc_option.allocator.realloc_func = realloc; init_args.mem_alloc_option.allocator.realloc_func = realloc;
init_args.mem_alloc_option.allocator.free_func = free; init_args.mem_alloc_option.allocator.free_func = free;
/* load WASM module */ os_mutex_lock(&aot_file_map_lock);
if (!(wasm_module = (WASMModuleCommon*)
wasm_load(wasm_file_buf, wasm_file_size, /* lookup the file maps */
error_buf, sizeof(error_buf)))) { file_map = aot_file_maps;
os_printf("%s\n", error_buf); while (file_map) {
aot_set_last_error(error_buf); file_map_next = file_map->next;
return NULL;
if (wasm_file_size == file_map->wasm_file_size
&& memcmp(wasm_file_buf, file_map->wasm_file_buf,
wasm_file_size) == 0) {
os_mutex_unlock(&aot_file_map_lock);
/* found */
*p_aot_file_size = file_map->aot_file_size;
return file_map->aot_file_buf;
}
file_map = file_map_next;
} }
if (!(comp_data = aot_create_comp_data((WASMModule*)wasm_module))) { /* not found, initialize file map and clone wasm file */
os_printf("%s\n", aot_get_last_error()); if (!(file_map = wasm_runtime_malloc(sizeof(AOTFileMap)))
|| !(wasm_file_buf_cloned = wasm_runtime_malloc(wasm_file_size))) {
set_error_buf(error_buf, error_buf_size, "allocate memory failed");
goto fail1; goto fail1;
} }
if (!(comp_ctx = aot_create_comp_context(comp_data, &option))) { bh_memcpy_s(wasm_file_buf_cloned, wasm_file_size,
os_printf("%s\n", aot_get_last_error()); wasm_file_buf, wasm_file_size);
memset(file_map, 0, sizeof(AOTFileMap));
file_map->wasm_file_buf = wasm_file_buf_cloned;
file_map->wasm_file_size = wasm_file_size;
/* load WASM module */
if (!(wasm_module = wasm_load(wasm_file_buf, wasm_file_size,
error_buf, sizeof(error_buf)))) {
goto fail1;
}
if (!(comp_data = aot_create_comp_data(wasm_module))) {
set_error_buf(error_buf, error_buf_size, aot_get_last_error());
goto fail2; goto fail2;
} }
if (!aot_compile_wasm(comp_ctx)) { if (!(comp_ctx = aot_create_comp_context(comp_data, &option))) {
os_printf("%s\n", aot_get_last_error()); set_error_buf(error_buf, error_buf_size, aot_get_last_error());
goto fail3; goto fail3;
} }
if (!aot_compile_wasm(comp_ctx)) {
set_error_buf(error_buf, error_buf_size, aot_get_last_error());
goto fail4;
}
if (!(aot_file_buf = aot_emit_aot_file_buf(comp_ctx, comp_data, if (!(aot_file_buf = aot_emit_aot_file_buf(comp_ctx, comp_data,
&aot_file_size))) { &aot_file_size))) {
os_printf("%s\n", aot_get_last_error()); set_error_buf(error_buf, error_buf_size, aot_get_last_error());
goto fail3; goto fail4;
}
file_map->aot_file_buf = aot_file_buf;
file_map->aot_file_size = aot_file_size;
if (!aot_file_maps)
aot_file_maps = file_map;
else {
file_map->next = aot_file_maps;
aot_file_maps = file_map;
} }
*p_aot_file_size = aot_file_size; *p_aot_file_size = aot_file_size;
fail3: fail4:
/* Destroy compiler context */ /* Destroy compiler context */
aot_destroy_comp_context(comp_ctx); aot_destroy_comp_context(comp_ctx);
fail2: fail3:
/* Destroy compile data */ /* Destroy compile data */
aot_destroy_comp_data(comp_data); aot_destroy_comp_data(comp_data);
fail2:
wasm_unload(wasm_module);
fail1: fail1:
wasm_runtime_unload(wasm_module); if (!aot_file_buf) {
if (wasm_file_buf_cloned)
wasm_runtime_free(wasm_file_buf_cloned);
if (file_map)
wasm_runtime_free(file_map);
}
os_mutex_unlock(&aot_file_map_lock);
return aot_file_buf; return aot_file_buf;
} }

View File

@ -368,18 +368,19 @@ aot_emit_aot_file(AOTCompContext *comp_ctx,
AOTCompData *comp_data, AOTCompData *comp_data,
const char *file_name); const char *file_name);
uint8_t* uint8*
aot_emit_aot_file_buf(AOTCompContext *comp_ctx, aot_emit_aot_file_buf(AOTCompContext *comp_ctx,
AOTCompData *comp_data, AOTCompData *comp_data,
uint32_t *p_aot_file_size); uint32 *p_aot_file_size);
bool bool
aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name); aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name);
uint8_t* uint8*
aot_compile_wasm_file(const uint8_t *wasm_file_buf, uint32_t wasm_file_size, aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size,
uint32_t opt_level, uint32_t size_level, uint32 opt_level, uint32 size_level,
uint32_t *p_aot_file_size); char *error_buf, uint32 error_buf_size,
uint32 *p_aot_file_size);
#ifdef __cplusplus #ifdef __cplusplus
} /* end of extern "C" */ } /* end of extern "C" */

View File

@ -77,11 +77,18 @@ aot_emit_aot_file(aot_comp_context_t comp_ctx,
void void
aot_destroy_aot_file(uint8_t *aot_file); aot_destroy_aot_file(uint8_t *aot_file);
bool
aot_compile_wasm_file_init();
uint8_t* uint8_t*
aot_compile_wasm_file(const uint8_t *wasm_file_buf, uint32_t wasm_file_size, aot_compile_wasm_file(const uint8_t *wasm_file_buf, uint32_t wasm_file_size,
uint32_t opt_level, uint32_t size_level, uint32_t opt_level, uint32_t size_level,
char *error_buf, uint32_t error_buf_size,
uint32_t *p_aot_file_size); uint32_t *p_aot_file_size);
void
aot_compile_wasm_file_destroy();
char* char*
aot_get_last_error(); aot_get_last_error();

View File

@ -1950,7 +1950,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
local_type_index = 0; local_type_index = 0;
for (j = 0; j < local_set_count; j++) { for (j = 0; j < local_set_count; j++) {
read_leb_uint32(p_code, buf_code_end, sub_local_count); read_leb_uint32(p_code, buf_code_end, sub_local_count);
if (local_type_index + sub_local_count <= local_type_index if (!sub_local_count
|| local_type_index > UINT32_MAX - sub_local_count
|| local_type_index + sub_local_count > local_count) { || local_type_index + sub_local_count > local_count) {
set_error_buf(error_buf, error_buf_size, set_error_buf(error_buf, error_buf_size,
"invalid local count"); "invalid local count");

View File

@ -981,8 +981,10 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
local_type_index = 0; local_type_index = 0;
for (j = 0; j < local_set_count; j++) { for (j = 0; j < local_set_count; j++) {
read_leb_uint32(p_code, buf_code_end, sub_local_count); read_leb_uint32(p_code, buf_code_end, sub_local_count);
bh_assert(!(local_type_index + sub_local_count <= local_type_index bh_assert(sub_local_count
|| local_type_index + sub_local_count > local_count)); && local_type_index <= UINT32_MAX - sub_local_count
&& local_type_index + sub_local_count
<= local_count);
CHECK_BUF(p_code, buf_code_end, 1); CHECK_BUF(p_code, buf_code_end, 1);
/* 0x7F/0x7E/0x7D/0x7C */ /* 0x7F/0x7E/0x7D/0x7C */

View File

@ -1580,6 +1580,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
if (module_inst->exec_env_singleton) if (module_inst->exec_env_singleton)
wasm_exec_env_destroy(module_inst->exec_env_singleton); wasm_exec_env_destroy(module_inst->exec_env_singleton);
#if WASM_ENABLE_DUMP_CALL_STACK != 0
if (module_inst->frames) {
bh_vector_destroy(module_inst->frames);
wasm_runtime_free(module_inst->frames);
module_inst->frames = NULL;
}
#endif
wasm_runtime_free(module_inst); wasm_runtime_free(module_inst);
} }
@ -1925,7 +1933,7 @@ wasm_validate_app_addr(WASMModuleInstance *module_inst,
memory_data_size = memory->num_bytes_per_page * memory->cur_page_count; memory_data_size = memory->num_bytes_per_page * memory->cur_page_count;
/* integer overflow check */ /* integer overflow check */
if (app_offset + size < app_offset) { if (app_offset > UINT32_MAX - size) {
goto fail; goto fail;
} }
@ -1949,7 +1957,7 @@ wasm_validate_native_addr(WASMModuleInstance *module_inst,
} }
/* integer overflow check */ /* integer overflow check */
if (addr + size < addr) { if ((uintptr_t)addr > UINTPTR_MAX - size) {
goto fail; goto fail;
} }
@ -2421,19 +2429,59 @@ void
wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env)
{ {
WASMModuleInstance *module_inst = WASMModuleInstance *module_inst =
(WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env); (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env);
WASMInterpFrame *cur_frame = WASMInterpFrame *first_frame,
wasm_exec_env_get_cur_frame(exec_env); *cur_frame = wasm_exec_env_get_cur_frame(exec_env);
WASMFunctionInstance *func_inst; uint32 n = 0;
WASMExportFuncInstance *export_func;
const char *func_name = NULL;
uint32 n, i;
/* release previous stack frame */
if (module_inst->frames) {
bh_vector_destroy(module_inst->frames);
wasm_runtime_free(module_inst->frames);
module_inst->frames = NULL;
}
/* count frames includes a function */
first_frame = cur_frame;
while (cur_frame) {
if (cur_frame->function) {
n++;
}
cur_frame = cur_frame->prev_frame;
}
if (!(module_inst->frames = runtime_malloc(
(uint64)sizeof(Vector), module_inst->cur_exception, 128))) {
return;
}
if (!bh_vector_init(module_inst->frames, n, sizeof(struct WASMFrame))) {
wasm_runtime_free(module_inst->frames);
module_inst->frames = NULL;
return;
}
cur_frame = first_frame;
n = 0;
os_printf("\n"); os_printf("\n");
for (n = 0; cur_frame && cur_frame->function; n++) { while (cur_frame) {
func_name = NULL; struct WASMFrame frame = { 0 };
func_inst = cur_frame->function; WASMFunctionInstance *func_inst = cur_frame->function;
const char *func_name = NULL;
if (!func_inst) {
cur_frame = cur_frame->prev_frame;
continue;
}
/* place holder, will overwrite it in wasm_c_api */
frame.instance = module_inst;
frame.module_offset = 0;
frame.func_index = func_inst - module_inst->functions;
frame.func_offset =
cur_frame->ip ? cur_frame->ip - func_inst->u.func->code : 0;
/* look for the function name */
if (func_inst->is_import_func) { if (func_inst->is_import_func) {
func_name = func_inst->u.func_import->field_name; func_name = func_inst->u.func_import->field_name;
} }
@ -2444,8 +2492,10 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env)
/* if custom name section is not generated, /* if custom name section is not generated,
search symbols from export table */ search symbols from export table */
if (!func_name) { if (!func_name) {
uint32 i;
for (i = 0; i < module_inst->export_func_count; i++) { for (i = 0; i < module_inst->export_func_count; i++) {
export_func = module_inst->export_functions + i; WASMExportFuncInstance *export_func =
module_inst->export_functions + i;
if (export_func->function == func_inst) { if (export_func->function == func_inst) {
func_name = export_func->name; func_name = export_func->name;
break; break;
@ -2462,7 +2512,11 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env)
os_printf("#%02d %s \n", n, func_name); os_printf("#%02d %s \n", n, func_name);
} }
/* keep print */
bh_vector_append(module_inst->frames, &frame);
cur_frame = cur_frame->prev_frame; cur_frame = cur_frame->prev_frame;
n++;
} }
os_printf("\n"); os_printf("\n");
} }

View File

@ -150,6 +150,15 @@ typedef struct WASMExportMemInstance {
} WASMExportMemInstance; } WASMExportMemInstance;
#endif #endif
#if WASM_ENABLE_DUMP_CALL_STACK != 0
struct WASMFrame {
void *instance;
uint32 module_offset;
uint32 func_index;
uint32 func_offset;
};
#endif
struct WASMModuleInstance { struct WASMModuleInstance {
/* Module instance type, for module instance loaded from /* Module instance type, for module instance loaded from
WASM bytecode binary, this field is Wasm_Module_Bytecode; WASM bytecode binary, this field is Wasm_Module_Bytecode;
@ -209,6 +218,10 @@ struct WASMModuleInstance {
/* The exception buffer of wasm interpreter for current thread. */ /* The exception buffer of wasm interpreter for current thread. */
char cur_exception[128]; char cur_exception[128];
#if WASM_ENABLE_DUMP_CALL_STACK != 0
Vector *frames;
#endif
/* The custom data that can be set/get by /* The custom data that can be set/get by
* wasm_set_custom_data/wasm_get_custom_data */ * wasm_set_custom_data/wasm_get_custom_data */
void *custom_data; void *custom_data;

View File

@ -94,6 +94,12 @@ if (COLLECT_CODE_COVERAGE EQUAL 1)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
endif () endif ()
# UNDEFINED BEHAVIOR
# refer to https://en.cppreference.com/w/cpp/language/ub
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=bounds-strict,undefined -fno-sanitize-recover")
endif()
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)

View File

@ -41,6 +41,7 @@ endif()
set(WAMR_BUILD_LIBC_BUILTIN 1) set(WAMR_BUILD_LIBC_BUILTIN 1)
set(WAMR_BUILD_LIBC_WASI 0) set(WAMR_BUILD_LIBC_WASI 0)
set(WAMR_BUILD_MULTI_MODULE 1) set(WAMR_BUILD_MULTI_MODULE 1)
set(WAMR_BUILD_DUMP_CALL_STACK 1)
if(NOT DEFINED WAMR_BUILD_FAST_INTERP) if(NOT DEFINED WAMR_BUILD_FAST_INTERP)
set(WAMR_BUILD_FAST_INTERP 1) set(WAMR_BUILD_FAST_INTERP 1)

View File

@ -92,32 +92,6 @@ DEFINE_FUNCTION(log)
return NULL; return NULL;
} }
static inline void
create_import_function_list(wasm_store_t *store,
const wasm_extern_t *import_function_list[])
{
#define IMPORT_FUNCTION_VARIABLE_NAME(name, ...) \
own wasm_func_t *function_##name = NULL;
IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME)
#undef IMPORT_FUNCTION_VARIABLE_NAME
#define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \
{ \
own wasm_functype_t *type = CREATE_FUNC_TYPE; \
if (!(function_##name = wasm_func_new(store, type, STUB_##name))) { \
printf("> Error creating new function\n"); \
} \
wasm_functype_delete(type); \
}
IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION)
#undef CREATE_WASM_FUNCTION
#define ADD_TO_FUNCTION_LIST(name, index, ...) \
import_function_list[index] = wasm_func_as_extern(function_##name);
IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST)
#undef CREATE_IMPORT_FUNCTION
}
/**********************************************************************/ /**********************************************************************/
// all exportted wasm functions. check with "/opt/wabt/bin/wasm-objdump -x -j Export X.wasm" // all exportted wasm functions. check with "/opt/wabt/bin/wasm-objdump -x -j Export X.wasm"
// -1: memory // -1: memory
@ -221,11 +195,33 @@ main(int argc, const char *argv[])
// Instantiate. // Instantiate.
printf("Instantiating module...\n"); printf("Instantiating module...\n");
const wasm_extern_t *imports[10] = { 0 };
// Create external functions. // Create external functions.
printf("Creating callback...\n"); printf("Creating callback...\n");
create_import_function_list(store, imports); #define IMPORT_FUNCTION_VARIABLE_NAME(name, ...) \
own wasm_func_t *function_##name = NULL;
IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME)
#undef IMPORT_FUNCTION_VARIABLE_NAME
const wasm_extern_t *imports[10] = { 0 };
#define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \
{ \
own wasm_functype_t *type = CREATE_FUNC_TYPE; \
if (!(function_##name = wasm_func_new(store, type, STUB_##name))) { \
printf("> Error creating new function\n"); \
return 1; \
} \
wasm_functype_delete(type); \
}
IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION)
#undef CREATE_WASM_FUNCTION
#define ADD_TO_FUNCTION_LIST(name, index, ...) \
imports[index] = wasm_func_as_extern(function_##name);
IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST)
#undef CREATE_IMPORT_FUNCTION
own wasm_instance_t *instance = own wasm_instance_t *instance =
wasm_instance_new(store, module, imports, NULL); wasm_instance_new(store, module, imports, NULL);
@ -234,6 +230,11 @@ main(int argc, const char *argv[])
return 1; return 1;
} }
#define DESTROY_WASM_FUNCITON(name, index, ...) \
wasm_func_delete(function_##name);
IMPORT_FUNCTION_LIST(DESTROY_WASM_FUNCITON)
#undef DESTROY_WASM_FUNCITON
// Extract export. // Extract export.
printf("Extracting export...\n"); printf("Extracting export...\n");
wasm_instance_exports(instance, &exports); wasm_instance_exports(instance, &exports);

View File

@ -19,6 +19,17 @@ own wasm_trap_t* fail_callback(
return trap; return trap;
} }
void print_frame(wasm_frame_t* frame) {
printf("> %p @ 0x%zx = %"PRIu32".0x%zx\n",
wasm_frame_instance(frame),
wasm_frame_module_offset(frame),
wasm_frame_func_index(frame),
wasm_frame_func_offset(frame)
);
}
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
// Initialize. // Initialize.
printf("Initializing...\n"); printf("Initializing...\n");
@ -93,7 +104,6 @@ int main(int argc, const char* argv[]) {
// Call. // Call.
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
char buf[32];
const wasm_func_t* func = wasm_extern_as_func(exports.data[i]); const wasm_func_t* func = wasm_extern_as_func(exports.data[i]);
if (func == NULL) { if (func == NULL) {
printf("> Error accessing export!\n"); printf("> Error accessing export!\n");
@ -111,9 +121,29 @@ int main(int argc, const char* argv[]) {
printf("Printing message...\n"); printf("Printing message...\n");
own wasm_name_t message; own wasm_name_t message;
wasm_trap_message(trap, &message); wasm_trap_message(trap, &message);
snprintf(buf, sizeof(buf), "> %%.%us\n", (unsigned)message.size); printf("> %s\n", message.data);
printf(buf, message.data);
printf("Printing origin...\n");
own wasm_frame_t* frame = wasm_trap_origin(trap);
if (frame) {
print_frame(frame);
wasm_frame_delete(frame);
} else {
printf("> Empty origin.\n");
}
printf("Printing trace...\n");
own wasm_frame_vec_t trace;
wasm_trap_trace(trap, &trace);
if (trace.size > 0) {
for (size_t i = 0; i < trace.size; ++i) {
print_frame(trace.data[i]);
}
} else {
printf("> Empty trace.\n");
}
wasm_frame_vec_delete(&trace);
wasm_trap_delete(trap); wasm_trap_delete(trap);
wasm_name_delete(&message); wasm_name_delete(&message);
} }