Merge branch main into dev/thread_suspension

This commit is contained in:
Wenyong Huang 2024-01-12 19:19:37 +08:00
commit 6478f32437
70 changed files with 3301 additions and 789 deletions

View File

@ -1,3 +1,73 @@
## WAMR-1.3.1
### Breaking Changes
- In multi-threading, when an exception was thrown in wasm_func_call(),
the trap returned contains the stack frames of the thread where the
exception occurs, but not the stack frames of the main thread.
- Disable emitting custom name section to AOT file with
`wamrc --enable-dump-call-stack` option, instead, use
`wamrc --emit-custom-sections=name` to emit it and make it clear.
### New Features
- Enable AOT linux perf support (#2930)
### Bug Fixes
- Corrects Zephyr include files for current versions of Zephyr (#2881)
- Fix possible dead lock in wasm_cluster_spawn_exec_env (#2882)
- Handle ambiguous fstflags on fd_filestat_set_times (#2892)
- Fix memory size not updating after growing in interpreter (#2898)
- fixed(freertos): Fix crash when wasm app call pthread_exit(NULL) (#2970)
- fast-jit: Fix const shift and const i64 compare issues (#2969)
- Fix ref.is_null processing in fast-interp loader (#2971)
- simd-128: The input lanes of integer-to-integer narrowing ops should be interpreted as signed (#2850)
- Fix ref.func function declared check in wasm loader (#2972)
- Fix fast-interp polymorphic stack processing (#2974)
- Fix potential recursive lock in pthread_create_wrapper (#2980)
- Fix build failure on esp-idf platform (#2991)
- Return stack frames of crashed thread when using wasm-c-api (#2908)
- Fix compilation error on iOS due to macOS-specific API (#2995)
- Fix a bug when emit the custom name section to aot file (#2987)
- Fix linux-sgx build error when libc-wasi is disabled (#2997)
### Enhancements
- fix command-reactor: Look for _initialize only if _start not found (#2891)
- Refactor reloc symbols for riscv (#2894)
- Avoid memory import failure when wasi-threads is enabled (#2893)
- interpreter: Simplify memory.grow a bit (#2899)
- Avoid reporting timestamp if custom logger is used (#2905)
- Expose API to set log level in embedder (#2907)
- Add a script to translate jitted function names in flamegraph (#2906)
- Refine wasm-c-api wasm_func_call (#2922)
- Add VectorCombine pass for JIT and AOT (#2923)
- Enable wasm_runtime_terminate for single-threading (#2924)
- nuttx: Add CONFIG_INTERPRETERS_WAMR_DEBUG_AOT (#2929)
- Allow to control built-in libraries for wamrc from command line options (#2928)
- Fix a bug that appends '_precheck' to aot_func (#2936)
- freertos: Add os_cond_broadcast for pthread wrapper (#2937)
- Append .aot to .wasm as a custom section named "aot" (#2933)
- fix(sgx-ra): Fix building when enclave is built without librats ahead (#2968)
- Refine LLVM JIT function call process (#2925)
- Refine AOT function call process (#2940)
- Allow to set segue flags for wasm-c-api JIT (#2926)
- freertos: Minor changes for freertos libc_wasi build adaption (#2973)
- freertos: Change ssp_config.h due to clock_nanosleep() not supported in freertos (#2979)
- aot compiler: Some updates for LLVM 18 (#2981)
- Enable MAP_32BIT for macOS (#2992)
- Register quick call entries to speedup the aot/jit func call process (#2978)
- Refine AOT/JIT code call wasm-c-api import process (#2982)
### Others
- compilation_on_nuttx.yml: Use docker image to simplify env setup (#2878)
- samples/spawn-thread: Disable libc and pthread (#2883)
- Add arm64 to nuttx compilation test (#2886)
- samples/spawn-thread: Tweak to expose a bug (#2888)
- Fix typo in CI config and suppress STORE_U8 in TSAN (#2802)
- Using docker image for nuttx spectest (#2887)
- doc: Separate source_debugging.md into two files (#2932)
- doc/build_wasm_app.md: Add a note about aot abi compatibility (#2993)
---
## WAMR-1.3.0
### Breaking Changes

View File

@ -147,13 +147,20 @@ elseif (WAMR_BUILD_SANITIZER STREQUAL "asan")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fno-omit-frame-pointer -fsanitize=address -fno-sanitize-recover=all" )
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
endif()
elseif (WAMR_BUILD_SANITIZER STREQUAL "tsan")
elseif (WAMR_BUILD_SANITIZER STREQUAL "tsan")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fno-omit-frame-pointer -fsanitize=thread -fno-sanitize-recover=all" )
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
elseif (NOT (WAMR_BUILD_SANITIZER STREQUAL "") )
message(SEND_ERROR "Unsupported sanitizer: ${WAMR_BUILD_SANITIZER}")
endif()
if (WAMR_BUILD_LINUX_PERF EQUAL 1)
if (NOT WAMR_BUILD_JIT AND NOT WAMR_BUILD_AOT)
message(WARNING "only support perf in aot and llvm-jit")
set(WAMR_BUILD_LINUX_PERF 0)
endif ()
endif ()
########################################
message ("-- Build Configurations:")
@ -440,3 +447,24 @@ if (WAMR_CONFIGUABLE_BOUNDS_CHECKS EQUAL 1)
add_definitions (-DWASM_CONFIGURABLE_BOUNDS_CHECKS=1)
message (" Configurable bounds checks enabled")
endif ()
if (WAMR_BUILD_LINUX_PERF EQUAL 1)
add_definitions (-DWASM_ENABLE_LINUX_PERF=1)
message (" Linux perf support enabled")
endif ()
if (NOT DEFINED WAMR_BUILD_QUICK_AOT_ENTRY)
# Enable quick aot/jit entries by default
set (WAMR_BUILD_QUICK_AOT_ENTRY 1)
endif ()
if (WAMR_BUILD_QUICK_AOT_ENTRY EQUAL 1)
add_definitions (-DWASM_ENABLE_QUICK_AOT_ENTRY=1)
message (" Quick AOT/JIT entries enabled")
else ()
add_definitions (-DWASM_ENABLE_QUICK_AOT_ENTRY=0)
message (" Quick AOT/JIT entries disabled")
endif ()
if (APPLE)
# On recent macOS versions, by default, the size of page zero is 4GB.
# Shrink it to make MAP_32BIT mmap can work.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-pagezero_size,0x4000")
endif ()

View File

@ -490,4 +490,16 @@
#define WASM_MAX_INSTANCE_CONTEXTS 8
#endif
/* linux perf support */
#ifndef WASM_ENABLE_LINUX_PERF
#define WASM_ENABLE_LINUX_PERF 0
#endif
/* Support registering quick AOT/JIT function entries of some func types
to speedup the calling process of invoking the AOT/JIT functions of
these types from the host embedder */
#ifndef WASM_ENABLE_QUICK_AOT_ENTRY
#define WASM_ENABLE_QUICK_AOT_ENTRY 1
#endif
#endif /* end of _CONFIG_H_ */

View File

@ -822,7 +822,9 @@ load_custom_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
case AOT_CUSTOM_SECTION_NAME:
if (!load_name_section(buf, buf_end, module, is_load_from_file_buf,
error_buf, error_buf_size))
goto fail;
LOG_VERBOSE("Load name section failed.");
else
LOG_VERBOSE("Load name section success.");
break;
#if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0
case AOT_CUSTOM_SECTION_RAW:
@ -1202,6 +1204,11 @@ load_func_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
func_types[i]->param_cell_num = (uint16)param_cell_num;
func_types[i]->ret_cell_num = (uint16)ret_cell_num;
#if WASM_ENABLE_QUICK_AOT_ENTRY != 0
func_types[i]->quick_aot_entry =
wasm_native_lookup_quick_aot_entry(func_types[i]);
#endif
}
*p_buf = buf;
@ -2764,6 +2771,104 @@ fail:
return ret;
}
#if WASM_ENABLE_LINUX_PERF != 0
struct func_info {
uint32 idx;
void *ptr;
};
static uint32
get_func_size(const AOTModule *module, struct func_info *sorted_func_ptrs,
uint32 idx)
{
uint32 func_sz;
if (idx == module->func_count - 1)
func_sz = (uintptr_t)module->code + module->code_size
- (uintptr_t)(sorted_func_ptrs[idx].ptr);
else
func_sz = (uintptr_t)(sorted_func_ptrs[idx + 1].ptr)
- (uintptr_t)(sorted_func_ptrs[idx].ptr);
return func_sz;
}
static int
compare_func_ptrs(const void *f1, const void *f2)
{
return (intptr_t)((struct func_info *)f1)->ptr
- (intptr_t)((struct func_info *)f2)->ptr;
}
static struct func_info *
sort_func_ptrs(const AOTModule *module, char *error_buf, uint32 error_buf_size)
{
uint64 content_len;
struct func_info *sorted_func_ptrs;
unsigned i;
content_len = (uint64)sizeof(struct func_info) * module->func_count;
sorted_func_ptrs = loader_malloc(content_len, error_buf, error_buf_size);
if (!sorted_func_ptrs)
return NULL;
for (i = 0; i < module->func_count; i++) {
sorted_func_ptrs[i].idx = i;
sorted_func_ptrs[i].ptr = module->func_ptrs[i];
}
qsort(sorted_func_ptrs, module->func_count, sizeof(struct func_info),
compare_func_ptrs);
return sorted_func_ptrs;
}
static bool
create_perf_map(const AOTModule *module, char *error_buf, uint32 error_buf_size)
{
struct func_info *sorted_func_ptrs = NULL;
char perf_map_info[128] = { 0 };
FILE *perf_map = NULL;
uint32 i;
pid_t pid = getpid();
bool ret = false;
sorted_func_ptrs = sort_func_ptrs(module, error_buf, error_buf_size);
if (!sorted_func_ptrs)
goto quit;
snprintf(perf_map_info, 128, "/tmp/perf-%d.map", pid);
perf_map = fopen(perf_map_info, "w");
if (!perf_map) {
LOG_WARNING("warning: can't create /tmp/perf-%d.map, because %s", pid,
strerror(errno));
goto quit;
}
for (i = 0; i < module->func_count; i++) {
memset(perf_map_info, 0, 128);
snprintf(perf_map_info, 128, "%lx %x aot_func#%u\n",
(uintptr_t)sorted_func_ptrs[i].ptr,
get_func_size(module, sorted_func_ptrs, i),
sorted_func_ptrs[i].idx);
fwrite(perf_map_info, 1, strlen(perf_map_info), perf_map);
}
LOG_VERBOSE("generate /tmp/perf-%d.map", pid);
ret = true;
quit:
if (sorted_func_ptrs)
free(sorted_func_ptrs);
if (perf_map)
fclose(perf_map);
return ret;
}
#endif /* WASM_ENABLE_LINUX_PERF != 0*/
static bool
load_from_sections(AOTModule *module, AOTSection *sections,
bool is_load_from_file_buf, char *error_buf,
@ -3224,6 +3329,12 @@ load(const uint8 *buf, uint32 size, AOTModule *module, char *error_buf,
}
#endif
#if WASM_ENABLE_LINUX_PERF != 0
if (wasm_runtime_get_linux_perf())
if (!create_perf_map(module, error_buf, error_buf_size))
goto fail;
#endif
return ret;
fail:
return false;

View File

@ -136,6 +136,7 @@ typedef struct {
REG_SYM(aot_enlarge_memory), \
REG_SYM(aot_set_exception), \
REG_SYM(aot_check_app_addr_and_convert),\
REG_SYM(wasm_runtime_quick_invoke_c_api_native),\
{ "memset", (void*)aot_memset }, \
{ "memmove", (void*)aot_memmove }, \
{ "memcpy", (void*)aot_memmove }, \

View File

@ -47,6 +47,13 @@ bh_static_assert(sizeof(AOTMemoryInstance) == 104);
bh_static_assert(offsetof(AOTTableInstance, elems) == 8);
bh_static_assert(offsetof(AOTModuleInstanceExtra, stack_sizes) == 0);
bh_static_assert(offsetof(AOTModuleInstanceExtra, common.c_api_func_imports)
== sizeof(uint64));
bh_static_assert(sizeof(CApiFuncImport) == sizeof(uintptr_t) * 3);
bh_static_assert(sizeof(wasm_val_t) == 16);
bh_static_assert(offsetof(wasm_val_t, of) == 8);
static void
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
@ -1374,7 +1381,6 @@ aot_lookup_function(const AOTModuleInstance *module_inst, const char *name,
}
#ifdef OS_ENABLE_HW_BOUND_CHECK
static bool
invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
const WASMType *func_type,
@ -1386,9 +1392,6 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop;
uint32 page_size = os_getpagesize();
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
uint16 param_count = func_type->param_count;
uint16 result_count = func_type->result_count;
const uint8 *types = func_type->types;
#ifdef BH_PLATFORM_WINDOWS
int result;
bool has_exception;
@ -1406,42 +1409,43 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
return false;
}
if (exec_env_tls && (exec_env_tls != exec_env)) {
aot_set_exception(module_inst, "invalid exec env");
return false;
}
if (!exec_env_tls) {
if (!os_thread_signal_inited()) {
aot_set_exception(module_inst, "thread signal env not inited");
return false;
}
if (!os_thread_signal_inited()) {
aot_set_exception(module_inst, "thread signal env not inited");
return false;
/* Set thread handle and stack boundary if they haven't been set */
wasm_exec_env_set_thread_info(exec_env);
wasm_runtime_set_exec_env_tls(exec_env);
}
else {
if (exec_env_tls != exec_env) {
aot_set_exception(module_inst, "invalid exec env");
return false;
}
}
wasm_exec_env_push_jmpbuf(exec_env, &jmpbuf_node);
wasm_runtime_set_exec_env_tls(exec_env);
if (os_setjmp(jmpbuf_node.jmpbuf) == 0) {
/* Quick call with func_ptr if the function signature is simple */
if (!signature && param_count == 1 && types[0] == VALUE_TYPE_I32) {
if (result_count == 0) {
void (*NativeFunc)(WASMExecEnv *, uint32) =
(void (*)(WASMExecEnv *, uint32))func_ptr;
NativeFunc(exec_env, argv[0]);
ret = aot_copy_exception(module_inst, NULL) ? false : true;
}
else if (result_count == 1
&& types[param_count] == VALUE_TYPE_I32) {
uint32 (*NativeFunc)(WASMExecEnv *, uint32) =
(uint32(*)(WASMExecEnv *, uint32))func_ptr;
argv_ret[0] = NativeFunc(exec_env, argv[0]);
ret = aot_copy_exception(module_inst, NULL) ? false : true;
}
else {
ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type,
signature, attachment, argv,
argc, argv_ret);
}
#if WASM_ENABLE_QUICK_AOT_ENTRY != 0
/* Quick call if the quick aot entry is registered */
if (!signature && func_type->quick_aot_entry) {
void (*invoke_native)(
void *func_ptr, uint8 ret_type, void *exec_env, uint32 *argv,
uint32 *argv_ret) = func_type->quick_aot_entry;
invoke_native(func_ptr,
func_type->result_count > 0
? func_type->types[func_type->param_count]
: VALUE_TYPE_VOID,
exec_env, argv, argv_ret);
ret = !aot_copy_exception(module_inst, NULL);
}
else {
else
#endif
{
ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type,
signature, attachment, argv, argc,
argv_ret);
@ -1473,7 +1477,6 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
(void)jmpbuf_node_pop;
return ret;
}
#define invoke_native_internal invoke_native_with_hw_bound_check
#else /* else of OS_ENABLE_HW_BOUND_CHECK */
#define invoke_native_internal wasm_runtime_invoke_native
@ -1543,10 +1546,16 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
/* func pointer was looked up previously */
bh_assert(func_ptr != NULL);
/* set thread handle and stack boundary */
wasm_exec_env_set_thread_info(exec_env);
/* set exec env so it can be later retrieved from instance */
#ifndef OS_ENABLE_HW_BOUND_CHECK
/* Set thread handle and stack boundary */
wasm_exec_env_set_thread_info(exec_env);
#else
/* Set thread info in invoke_native_with_hw_bound_check when
hw bound check is enabled */
#endif
/* Set exec env so it can be later retrieved from instance */
((AOTModuleInstanceExtra *)module_inst->e)->common.cur_exec_env = exec_env;
if (ext_ret_count > 0) {

View File

@ -23,7 +23,6 @@
#include <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

View File

@ -299,6 +299,7 @@ wasm_config_new(void)
memset(config, 0, sizeof(wasm_config_t));
config->mem_alloc_type = Alloc_With_System_Allocator;
return config;
}
@ -330,7 +331,17 @@ wasm_config_set_linux_perf_opt(wasm_config_t *config, bool enable)
if (!config)
return NULL;
config->linux_perf_support = enable;
config->enable_linux_perf = enable;
return config;
}
wasm_config_t *
wasm_config_set_segue_flags(wasm_config_t *config, uint32 segue_flags)
{
if (!config)
return NULL;
config->segue_flags = segue_flags;
return config;
}
@ -367,6 +378,9 @@ wasm_engine_new_internal(wasm_config_t *config)
wasm_engine_t *engine = NULL;
/* init runtime */
RuntimeInitArgs init_args = { 0 };
#if WASM_ENABLE_JIT != 0
LLVMJITOptions *jit_options = wasm_runtime_get_llvm_jit_options();
#endif
#ifndef NDEBUG
bh_log_set_verbose_level(BH_LOG_LEVEL_VERBOSE);
@ -380,7 +394,12 @@ wasm_engine_new_internal(wasm_config_t *config)
init_args.mem_alloc_type = config->mem_alloc_type;
memcpy(&init_args.mem_alloc_option, &config->mem_alloc_option,
sizeof(MemAllocOption));
init_args.linux_perf_support = config->linux_perf_support;
init_args.enable_linux_perf = config->enable_linux_perf;
init_args.segue_flags = config->segue_flags;
#if WASM_ENABLE_JIT != 0
jit_options->quick_invoke_c_api_import = true;
#endif
if (!wasm_runtime_full_init(&init_args)) {
LOG_DEBUG("wasm_runtime_full_init failed");
@ -1902,10 +1921,26 @@ wasm_frame_func_offset(const wasm_frame_t *frame)
return frame ? frame->func_offset : 0;
}
void
wasm_frame_vec_clone_internal(Vector *src, Vector *out)
{
bh_assert(src->num_elems != 0 && src->data);
bh_vector_destroy(out);
if (!bh_vector_init(out, src->num_elems, sizeof(WASMCApiFrame), false)) {
bh_vector_destroy(out);
return;
}
bh_memcpy_s(out->data, src->num_elems * sizeof(WASMCApiFrame), src->data,
src->num_elems * sizeof(WASMCApiFrame));
out->num_elems = src->num_elems;
}
static wasm_trap_t *
wasm_trap_new_internal(wasm_store_t *store,
WASMModuleInstanceCommon *inst_comm_rt,
const char *error_info)
const char *error_info, Vector *cluster_frames)
{
wasm_trap_t *trap;
#if WASM_ENABLE_DUMP_CALL_STACK != 0
@ -1935,7 +1970,9 @@ wasm_trap_new_internal(wasm_store_t *store,
/* fill in frames */
#if WASM_ENABLE_DUMP_CALL_STACK != 0
trap->frames = ((WASMModuleInstance *)inst_comm_rt)->frames;
trap->frames = cluster_frames
? cluster_frames
: ((WASMModuleInstance *)inst_comm_rt)->frames;
if (trap->frames) {
/* fill in instances */
@ -2046,10 +2083,7 @@ wasm_trap_trace(const wasm_trap_t *trap, own wasm_frame_vec_t *out)
}
for (i = 0; i < trap->frames->num_elems; i++) {
wasm_frame_t *frame;
frame = ((wasm_frame_t *)trap->frames->data) + i;
wasm_frame_t *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))) {
@ -2926,6 +2960,8 @@ wasm_func_new_basic(wasm_store_t *store, const wasm_functype_t *type,
if (!(func->type = wasm_functype_copy(type))) {
goto failed;
}
func->param_count = func->type->params->num_elems;
func->result_count = func->type->results->num_elems;
RETURN_OBJ(func, wasm_func_delete)
}
@ -2956,6 +2992,8 @@ wasm_func_new_with_env_basic(wasm_store_t *store, const wasm_functype_t *type,
if (!(func->type = wasm_functype_copy(type))) {
goto failed;
}
func->param_count = func->type->params->num_elems;
func->result_count = func->type->results->num_elems;
RETURN_OBJ(func, wasm_func_delete)
}
@ -3045,6 +3083,8 @@ wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt,
if (!func->type) {
goto failed;
}
func->param_count = func->type->params->num_elems;
func->result_count = func->type->results->num_elems;
/* will add name information when processing "exports" */
func->store = store;
@ -3136,48 +3176,31 @@ params_to_argv(const wasm_val_vec_t *params,
const wasm_valtype_vec_t *param_defs, uint32 *argv,
uint32 *ptr_argc)
{
size_t i = 0;
uint32 *argv_org = argv;
const wasm_val_t *param, *param_end;
if (!param_defs->num_elems) {
return true;
}
bh_assert(params && params->num_elems && params->size && params->data);
if (!params || !params->num_elems || !params->size || !params->data) {
LOG_ERROR("the parameter params is invalid");
return false;
}
*ptr_argc = 0;
for (i = 0; i < param_defs->num_elems; ++i) {
const wasm_val_t *param = params->data + i;
bh_assert((*(param_defs->data + i))->kind == param->kind);
param = params->data;
param_end = param + param_defs->num_elems;
for (; param < param_end; param++) {
switch (param->kind) {
case WASM_I32:
case WASM_F32:
*(int32 *)argv = param->of.i32;
argv += 1;
*ptr_argc += 1;
break;
case WASM_I64:
case WASM_F64:
*(int64 *)argv = param->of.i64;
argv += 2;
*ptr_argc += 2;
break;
case WASM_F32:
*(float32 *)argv = param->of.f32;
argv += 1;
*ptr_argc += 1;
break;
case WASM_F64:
*(float64 *)argv = param->of.f64;
argv += 2;
*ptr_argc += 2;
break;
#if WASM_ENABLE_REF_TYPES != 0
case WASM_ANYREF:
*(uintptr_t *)argv = (uintptr_t)param->of.ref;
argv += sizeof(uintptr_t) / sizeof(uint32);
*ptr_argc += 1;
break;
#endif
default:
@ -3186,6 +3209,7 @@ params_to_argv(const wasm_val_vec_t *params,
}
}
*ptr_argc = (uint32)(argv - argv_org);
return true;
}
@ -3193,62 +3217,37 @@ static bool
argv_to_results(const uint32 *argv, const wasm_valtype_vec_t *result_defs,
wasm_val_vec_t *results)
{
size_t i = 0, argv_i = 0;
wasm_valtype_t **result_def, **result_def_end;
wasm_val_t *result;
if (!result_defs->num_elems) {
return true;
}
bh_assert(results && results->size && results->data);
if (!results || !results->size || !results->data) {
LOG_ERROR("the parameter results is invalid");
return false;
}
result_def = result_defs->data;
result_def_end = result_def + result_defs->num_elems;
result = results->data;
for (i = 0, result = results->data, argv_i = 0; i < result_defs->num_elems;
i++, result++) {
switch (result_defs->data[i]->kind) {
for (; result_def < result_def_end; result_def++, result++) {
result->kind = result_def[0]->kind;
switch (result->kind) {
case WASM_I32:
{
result->kind = WASM_I32;
result->of.i32 = *(int32 *)(argv + argv_i);
argv_i += 1;
break;
}
case WASM_I64:
{
result->kind = WASM_I64;
result->of.i64 = *(int64 *)(argv + argv_i);
argv_i += 2;
break;
}
case WASM_F32:
{
result->kind = WASM_F32;
result->of.f32 = *(float32 *)(argv + argv_i);
argv_i += 1;
result->of.i32 = *(int32 *)argv;
argv += 1;
break;
}
case WASM_I64:
case WASM_F64:
{
result->kind = WASM_F64;
result->of.f64 = *(float64 *)(argv + argv_i);
argv_i += 2;
result->of.i64 = *(int64 *)argv;
argv += 2;
break;
}
#if WASM_ENABLE_REF_TYPES != 0
case WASM_ANYREF:
{
result->kind = WASM_ANYREF;
result->of.ref =
(struct wasm_ref_t *)(*(uintptr_t *)(argv + argv_i));
argv_i += sizeof(uintptr_t) / sizeof(uint32);
result->of.ref = (struct wasm_ref_t *)(*(uintptr_t *)argv);
argv += sizeof(uintptr_t) / sizeof(uint32);
break;
}
#endif
default:
LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__,
result_defs->data[i]->kind);
result->kind);
return false;
}
}
@ -3268,10 +3267,9 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
WASMFunctionInstanceCommon *func_comm_rt = NULL;
WASMExecEnv *exec_env = NULL;
size_t param_count, result_count, alloc_count;
Vector *cluster_frames = NULL;
if (!func) {
return NULL;
}
bh_assert(func && func->type);
if (!func->inst_comm_rt) {
wasm_name_t message = { 0 };
@ -3285,17 +3283,14 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
return trap;
}
bh_assert(func->type);
#if WASM_ENABLE_INTERP != 0
if (func->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
#if WASM_ENABLE_INTERP != 0
func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->e->functions
+ func->func_idx_rt;
}
#endif
}
else if (func->inst_comm_rt->module_type == Wasm_Module_AoT) {
#if WASM_ENABLE_AOT != 0
if (func->inst_comm_rt->module_type == Wasm_Module_AoT) {
if (!(func_comm_rt = func->func_comm_rt)) {
AOTModuleInstance *inst_aot =
(AOTModuleInstance *)func->inst_comm_rt;
@ -3316,8 +3311,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
}
}
}
}
#endif
}
/*
* a wrong combination of module filetype and compilation flags
@ -3385,27 +3380,32 @@ failed:
if (argv != argv_buf)
wasm_runtime_free(argv);
return wasm_trap_new_internal(
#if WASM_ENABLE_DUMP_CALL_STACK != 0 && WASM_ENABLE_THREAD_MGR != 0
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
cluster_frames = &cluster->exception_frames;
wasm_cluster_traverse_lock(exec_env);
#endif
wasm_trap_t *trap = wasm_trap_new_internal(
func->store, func->inst_comm_rt,
wasm_runtime_get_exception(func->inst_comm_rt));
wasm_runtime_get_exception(func->inst_comm_rt), cluster_frames);
#if WASM_ENABLE_DUMP_CALL_STACK != 0 && WASM_ENABLE_THREAD_MGR != 0
wasm_cluster_traverse_unlock(exec_env);
#endif
return trap;
}
size_t
wasm_func_param_arity(const wasm_func_t *func)
{
if (!func || !func->type || !func->type->params) {
return 0;
}
return func->type->params->num_elems;
return func->param_count;
}
size_t
wasm_func_result_arity(const wasm_func_t *func)
{
if (!func || !func->type || !func->type->results) {
return 0;
}
return func->type->results->num_elems;
return func->result_count;
}
wasm_global_t *

View File

@ -130,6 +130,8 @@ struct wasm_func_t {
struct wasm_host_info host_info;
wasm_functype_t *type;
uint16 param_count;
uint16 result_count;
bool with_env;
union {
@ -238,4 +240,7 @@ wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt,
wasm_table_t *
wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt,
WASMModuleInstanceCommon *inst_comm_rt);
void
wasm_frame_vec_clone_internal(Vector *src, Vector *out);
#endif /* _WASM_C_API_INTERNAL_H */

File diff suppressed because it is too large Load Diff

View File

@ -104,6 +104,11 @@ wasm_native_init();
void
wasm_native_destroy();
#if WASM_ENABLE_QUICK_AOT_ENTRY != 0
void *
wasm_native_lookup_quick_aot_entry(const WASMType *func_type);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -158,6 +158,8 @@ static JitCompOptions jit_options = { 0 };
#endif
#if WASM_ENABLE_JIT != 0
/* opt_level: 3, size_level: 3, segue-flags: 0,
quick_invoke_c_api_import: false */
static LLVMJITOptions llvm_jit_options = { 3, 3, 0, false };
#endif
@ -638,10 +640,10 @@ wasm_runtime_get_default_running_mode(void)
}
#if WASM_ENABLE_JIT != 0
LLVMJITOptions
LLVMJITOptions *
wasm_runtime_get_llvm_jit_options(void)
{
return llvm_jit_options;
return &llvm_jit_options;
}
#endif
@ -662,14 +664,17 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args)
#endif
#if WASM_ENABLE_JIT != 0
LOG_DEBUG("Start LLVM_JIT, opt_sz=%u, opt_lvl=%u, segue=%s, linux_perf=%s",
init_args->llvm_jit_size_level, init_args->llvm_jit_opt_level,
init_args->segue_flags ? "Yes" : "No",
init_args->linux_perf_support ? "Yes" : "No");
llvm_jit_options.size_level = init_args->llvm_jit_size_level;
llvm_jit_options.opt_level = init_args->llvm_jit_opt_level;
llvm_jit_options.segue_flags = init_args->segue_flags;
llvm_jit_options.linux_perf_support = init_args->linux_perf_support;
#endif
#if WASM_ENABLE_LINUX_PERF != 0
wasm_runtime_set_linux_perf(init_args->enable_linux_perf);
#else
if (init_args->enable_linux_perf)
LOG_WARNING("warning: to enable linux perf support, please recompile "
"with -DWAMR_BUILD_LINUX_PERF=1");
#endif
if (!wasm_runtime_env_init()) {
@ -701,6 +706,12 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args)
return true;
}
void
wasm_runtime_set_log_level(log_level_t level)
{
bh_log_set_verbose_level(level);
}
bool
wasm_runtime_is_running_mode_supported(RunningMode running_mode)
{
@ -2577,7 +2588,6 @@ wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst_comm)
wasm_runtime_set_exception(module_inst_comm, NULL);
}
#if WASM_ENABLE_THREAD_MGR != 0
void
wasm_runtime_terminate(WASMModuleInstanceCommon *module_inst_comm)
{
@ -2587,7 +2597,6 @@ wasm_runtime_terminate(WASMModuleInstanceCommon *module_inst_comm)
|| module_inst_comm->module_type == Wasm_Module_AoT);
wasm_set_exception(module_inst, "terminated by user");
}
#endif
void
wasm_runtime_set_custom_data_internal(
@ -5703,7 +5712,7 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
wasm_val_t *params = params_buf, *results = results_buf;
wasm_trap_t *trap = NULL;
bool ret = false;
wasm_val_vec_t params_vec, results_vec;
wasm_val_vec_t params_vec = { 0 }, results_vec = { 0 };
if (func_type->param_count > 16) {
if (!(params =
@ -5731,12 +5740,10 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
params_vec.data = params;
params_vec.num_elems = func_type->param_count;
params_vec.size = func_type->param_count;
params_vec.size_of_elem = sizeof(wasm_val_t);
results_vec.data = results;
results_vec.num_elems = 0;
results_vec.size = func_type->result_count;
results_vec.size_of_elem = sizeof(wasm_val_t);
if (!with_env) {
wasm_func_callback_t callback = (wasm_func_callback_t)func_ptr;
@ -5772,7 +5779,6 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
wasm_runtime_set_exception(module_inst, "unsupported result type");
goto fail;
}
results_vec.num_elems = func_type->result_count;
ret = true;
fail:
@ -5783,6 +5789,71 @@ fail:
return ret;
}
bool
wasm_runtime_quick_invoke_c_api_native(WASMModuleInstanceCommon *inst_comm,
CApiFuncImport *c_api_import,
wasm_val_t *params, uint32 param_count,
wasm_val_t *results, uint32 result_count)
{
WASMModuleInstance *module_inst = (WASMModuleInstance *)inst_comm;
void *func_ptr = c_api_import->func_ptr_linked;
bool with_env_arg = c_api_import->with_env_arg, ret = true;
wasm_val_vec_t params_vec = { 0 }, results_vec = { 0 };
wasm_trap_t *trap = NULL;
params_vec.data = params;
params_vec.num_elems = param_count;
params_vec.size = param_count;
results_vec.data = results;
results_vec.num_elems = 0;
results_vec.size = result_count;
if (!func_ptr) {
wasm_set_exception_with_id(module_inst, EXCE_CALL_UNLINKED_IMPORT_FUNC);
ret = false;
goto fail;
}
if (!with_env_arg) {
wasm_func_callback_t callback = (wasm_func_callback_t)func_ptr;
trap = callback(&params_vec, &results_vec);
}
else {
void *wasm_c_api_env = c_api_import->env_arg;
wasm_func_callback_with_env_t callback =
(wasm_func_callback_with_env_t)func_ptr;
trap = callback(wasm_c_api_env, &params_vec, &results_vec);
}
if (trap) {
if (trap->message->data) {
/* since trap->message->data does not end with '\0' */
char trap_message[108] = { 0 };
uint32 max_size_to_copy = (uint32)sizeof(trap_message) - 1;
uint32 size_to_copy = (trap->message->size < max_size_to_copy)
? (uint32)trap->message->size
: max_size_to_copy;
bh_memcpy_s(trap_message, (uint32)sizeof(trap_message),
trap->message->data, size_to_copy);
wasm_set_exception(module_inst, trap_message);
}
else {
wasm_set_exception(module_inst,
"native function throw unknown exception");
}
wasm_trap_delete(trap);
ret = false;
}
fail:
#ifdef OS_ENABLE_HW_BOUND_CHECK
if (!ret)
wasm_runtime_access_exce_check_guard_page();
#endif
return ret;
}
void
wasm_runtime_show_app_heap_corrupted_prompt()
{
@ -6177,3 +6248,19 @@ wasm_runtime_get_context(WASMModuleInstanceCommon *inst, void *key)
return wasm_native_get_context(inst, key);
}
#endif /* WASM_ENABLE_MODULE_INST_CONTEXT != 0 */
#if WASM_ENABLE_LINUX_PERF != 0
static bool enable_linux_perf = false;
bool
wasm_runtime_get_linux_perf(void)
{
return enable_linux_perf;
}
void
wasm_runtime_set_linux_perf(bool flag)
{
enable_linux_perf = flag;
}
#endif

View File

@ -438,12 +438,12 @@ typedef struct wasm_frame_t {
const char *func_name_wp;
} WASMCApiFrame;
#ifdef WASM_ENABLE_JIT
#if WASM_ENABLE_JIT != 0
typedef struct LLVMJITOptions {
uint32 opt_level;
uint32 size_level;
uint32 segue_flags;
bool linux_perf_support;
bool quick_invoke_c_api_import;
} LLVMJITOptions;
#endif
@ -477,7 +477,7 @@ wasm_runtime_get_default_running_mode(void);
#if WASM_ENABLE_JIT != 0
/* Internal API */
LLVMJITOptions
LLVMJITOptions *
wasm_runtime_get_llvm_jit_options(void);
#endif
@ -1090,6 +1090,16 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
uint32 argc, uint32 *argv, bool with_env,
void *wasm_c_api_env);
struct CApiFuncImport;
/* A quick version of wasm_runtime_invoke_c_api_native to directly invoke
wasm-c-api import function from jitted code to improve performance */
bool
wasm_runtime_quick_invoke_c_api_native(WASMModuleInstanceCommon *module_inst,
struct CApiFuncImport *c_api_import,
wasm_val_t *params, uint32 param_count,
wasm_val_t *results,
uint32 result_count);
void
wasm_runtime_show_app_heap_corrupted_prompt();
@ -1115,6 +1125,14 @@ wasm_runtime_end_blocking_op(WASMExecEnv *exec_env);
void
wasm_runtime_interrupt_blocking_op(WASMExecEnv *exec_env);
#if WASM_ENABLE_LINUX_PERF != 0
bool
wasm_runtime_get_linux_perf(void);
void
wasm_runtime_set_linux_perf(bool flag);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -912,9 +912,6 @@ get_native_symbol_list_size(AOTCompContext *comp_ctx)
return len;
}
static uint32
get_name_section_size(AOTCompData *comp_data);
static uint32
get_custom_sections_size(AOTCompContext *comp_ctx, AOTCompData *comp_data);
@ -972,15 +969,6 @@ get_aot_file_size(AOTCompContext *comp_ctx, AOTCompData *comp_data,
size += get_native_symbol_list_size(comp_ctx);
}
if (comp_ctx->enable_aux_stack_frame) {
/* custom name section */
size = align_uint(size, 4);
/* section id + section size + sub section id */
size += (uint32)sizeof(uint32) * 3;
size += (comp_data->aot_name_section_size =
get_name_section_size(comp_data));
}
size_custom_section = get_custom_sections_size(comp_ctx, comp_data);
if (size_custom_section > 0) {
size = align_uint(size, 4);
@ -1333,6 +1321,21 @@ get_custom_sections_size(AOTCompContext *comp_ctx, AOTCompData *comp_data)
const uint8 *content = NULL;
uint32 length = 0;
if (strcmp(section_name, "name") == 0) {
/* custom name section */
comp_data->aot_name_section_size = get_name_section_size(comp_data);
if (comp_data->aot_name_section_size == 0) {
LOG_WARNING("Can't find custom section [name], ignore it");
continue;
}
size = align_uint(size, 4);
/* section id + section size + sub section id */
size += (uint32)sizeof(uint32) * 3;
size += comp_data->aot_name_section_size;
continue;
}
content = wasm_loader_get_custom_section(comp_data->wasm_module,
section_name, &length);
if (!content) {
@ -2066,23 +2069,25 @@ static bool
aot_emit_name_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
AOTCompData *comp_data, AOTCompContext *comp_ctx)
{
if (comp_ctx->enable_aux_stack_frame) {
uint32 offset = *p_offset;
uint32 offset = *p_offset;
*p_offset = offset = align_uint(offset, 4);
if (comp_data->aot_name_section_size == 0)
return true;
EMIT_U32(AOT_SECTION_TYPE_CUSTOM);
/* sub section id + name section size */
EMIT_U32(sizeof(uint32) * 1 + comp_data->aot_name_section_size);
EMIT_U32(AOT_CUSTOM_SECTION_NAME);
bh_memcpy_s((uint8 *)(buf + offset), (uint32)(buf_end - buf),
comp_data->aot_name_section_buf,
(uint32)comp_data->aot_name_section_size);
offset += comp_data->aot_name_section_size;
offset = align_uint(offset, 4);
*p_offset = offset;
}
EMIT_U32(AOT_SECTION_TYPE_CUSTOM);
/* sub section id + name section size */
EMIT_U32(sizeof(uint32) * 1 + comp_data->aot_name_section_size);
EMIT_U32(AOT_CUSTOM_SECTION_NAME);
bh_memcpy_s((uint8 *)(buf + offset), (uint32)(buf_end - buf),
comp_data->aot_name_section_buf,
(uint32)comp_data->aot_name_section_size);
offset += comp_data->aot_name_section_size;
*p_offset = offset;
LOG_DEBUG("emit name section");
return true;
}
@ -2098,6 +2103,16 @@ aot_emit_custom_sections(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
const uint8 *content = NULL;
uint32 length = 0;
if (strcmp(section_name, "name") == 0) {
*p_offset = offset;
if (!aot_emit_name_section(buf, buf_end, p_offset, comp_data,
comp_ctx))
return false;
offset = *p_offset;
continue;
}
content = wasm_loader_get_custom_section(comp_data->wasm_module,
section_name, &length);
if (!content) {
@ -3589,6 +3604,10 @@ aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data,
return NULL;
aot_file_size = get_aot_file_size(comp_ctx, comp_data, obj_data);
if (aot_file_size == 0) {
aot_set_last_error("get aot file size failed");
goto fail1;
}
if (!(buf = aot_file_buf = wasm_runtime_malloc(aot_file_size))) {
aot_set_last_error("allocate memory failed.");
@ -3610,7 +3629,6 @@ aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data,
|| !aot_emit_relocation_section(buf, buf_end, &offset, comp_ctx,
comp_data, obj_data)
|| !aot_emit_native_symbol(buf, buf_end, &offset, comp_ctx)
|| !aot_emit_name_section(buf, buf_end, &offset, comp_data, comp_ctx)
|| !aot_emit_custom_sections(buf, buf_end, &offset, comp_data,
comp_ctx))
goto fail2;

View File

@ -288,6 +288,213 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return true;
}
static bool
call_aot_invoke_c_api_native(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 import_func_idx, AOTFuncType *aot_func_type,
LLVMValueRef *params)
{
LLVMTypeRef int8_ptr_type, param_types[6], ret_type;
LLVMTypeRef value_ptr_type = NULL, value_type = NULL;
LLVMTypeRef func_type, func_ptr_type;
LLVMValueRef param_values[6], res, func, value = NULL, offset;
LLVMValueRef c_api_func_imports, c_api_func_import;
LLVMValueRef c_api_params, c_api_results, value_ret;
LLVMValueRef c_api_param_kind, c_api_param_value;
LLVMValueRef c_api_result_value;
uint32 offset_c_api_func_imports, i;
uint32 offset_param_kind, offset_param_value;
char buf[16];
/* `int8 **` type */
int8_ptr_type = LLVMPointerType(INT8_PTR_TYPE, 0);
if (!int8_ptr_type) {
aot_set_last_error("create llvm pointer type failed");
return false;
}
param_types[0] = INT8_PTR_TYPE; /* module_inst */
param_types[1] = INT8_PTR_TYPE; /* CApiFuncImport *c_api_import */
param_types[2] = INT8_PTR_TYPE; /* wasm_val_t *params */
param_types[3] = I32_TYPE; /* uint32 param_count */
param_types[4] = INT8_PTR_TYPE; /* wasm_val_t *results */
param_types[5] = I32_TYPE; /* uint32 result_count */
ret_type = INT8_TYPE;
GET_AOT_FUNCTION(wasm_runtime_quick_invoke_c_api_native, 6);
param_values[0] = func_ctx->aot_inst;
/* Get module_inst->e->common.c_api_func_imports */
offset_c_api_func_imports =
get_module_inst_extra_offset(comp_ctx)
+ (comp_ctx->is_jit_mode
? offsetof(WASMModuleInstanceExtra, common.c_api_func_imports)
/* offsetof(AOTModuleInstanceExtra, common.c_api_func_imports) */
: sizeof(uint64));
offset = I32_CONST(offset_c_api_func_imports);
CHECK_LLVM_CONST(offset);
c_api_func_imports =
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst,
&offset, 1, "c_api_func_imports_addr");
c_api_func_imports =
LLVMBuildBitCast(comp_ctx->builder, c_api_func_imports, int8_ptr_type,
"c_api_func_imports_ptr");
c_api_func_imports =
LLVMBuildLoad2(comp_ctx->builder, INT8_PTR_TYPE, c_api_func_imports,
"c_api_func_imports");
/* Get &c_api_func_imports[func_idx], note size of CApiFuncImport
is pointer_size * 3 */
offset = I32_CONST((comp_ctx->pointer_size * 3) * import_func_idx);
CHECK_LLVM_CONST(offset);
c_api_func_import =
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, c_api_func_imports,
&offset, 1, "c_api_func_import");
param_values[1] = c_api_func_import;
param_values[2] = c_api_params = func_ctx->argv_buf;
param_values[3] = I32_CONST(aot_func_type->param_count);
CHECK_LLVM_CONST(param_values[3]);
/* Ensure sizeof(wasm_val_t) is 16 bytes */
offset = I32_CONST(sizeof(wasm_val_t) * aot_func_type->param_count);
c_api_results =
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, func_ctx->argv_buf,
&offset, 1, "results");
param_values[4] = c_api_results;
param_values[5] = I32_CONST(aot_func_type->result_count);
CHECK_LLVM_CONST(param_values[5]);
/* Set each c api param */
for (i = 0; i < aot_func_type->param_count; i++) {
/* Ensure sizeof(wasm_val_t) is 16 bytes */
offset_param_kind = sizeof(wasm_val_t) * i;
offset = I32_CONST(offset_param_kind);
CHECK_LLVM_CONST(offset);
c_api_param_kind =
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, c_api_params,
&offset, 1, "c_api_param_kind_addr");
c_api_param_kind =
LLVMBuildBitCast(comp_ctx->builder, c_api_param_kind, INT8_PTR_TYPE,
"c_api_param_kind_ptr");
switch (aot_func_type->types[i]) {
case VALUE_TYPE_I32:
value = I8_CONST(WASM_I32);
break;
case VALUE_TYPE_F32:
value = I8_CONST(WASM_F32);
break;
case VALUE_TYPE_I64:
value = I8_CONST(WASM_I64);
break;
case VALUE_TYPE_F64:
value = I8_CONST(WASM_F64);
break;
default:
bh_assert(0);
break;
}
CHECK_LLVM_CONST(value);
LLVMBuildStore(comp_ctx->builder, value, c_api_param_kind);
/* Ensure offsetof(wasm_val_t, of) is 8 bytes */
offset_param_value = offset_param_kind + offsetof(wasm_val_t, of);
offset = I32_CONST(offset_param_value);
CHECK_LLVM_CONST(offset);
c_api_param_value =
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, c_api_params,
&offset, 1, "c_api_param_value_addr");
switch (aot_func_type->types[i]) {
case VALUE_TYPE_I32:
value_ptr_type = INT32_PTR_TYPE;
break;
case VALUE_TYPE_F32:
value_ptr_type = F32_PTR_TYPE;
break;
case VALUE_TYPE_I64:
value_ptr_type = INT64_PTR_TYPE;
break;
case VALUE_TYPE_F64:
value_ptr_type = F64_PTR_TYPE;
break;
default:
bh_assert(0);
break;
}
c_api_param_value =
LLVMBuildBitCast(comp_ctx->builder, c_api_param_value,
value_ptr_type, "c_api_param_value_ptr");
LLVMBuildStore(comp_ctx->builder, params[i], c_api_param_value);
}
/* Call the function */
if (!(res = LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values,
6, "call"))) {
aot_set_last_error("LLVM build call failed.");
goto fail;
}
/* Check whether exception was thrown when executing the function */
if (comp_ctx->enable_bound_check
&& !check_call_return(comp_ctx, func_ctx, res)) {
goto fail;
}
for (i = 0; i < aot_func_type->result_count; i++) {
/* Ensure sizeof(wasm_val_t) is 16 bytes and
offsetof(wasm_val_t, of) is 8 bytes */
uint32 offset_result_value =
sizeof(wasm_val_t) * i + offsetof(wasm_val_t, of);
offset = I32_CONST(offset_result_value);
CHECK_LLVM_CONST(offset);
c_api_result_value =
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, c_api_results,
&offset, 1, "c_api_result_value_addr");
switch (aot_func_type->types[aot_func_type->param_count + i]) {
case VALUE_TYPE_I32:
value_type = I32_TYPE;
value_ptr_type = INT32_PTR_TYPE;
break;
case VALUE_TYPE_F32:
value_type = F32_TYPE;
value_ptr_type = F32_PTR_TYPE;
break;
case VALUE_TYPE_I64:
value_type = I64_TYPE;
value_ptr_type = INT64_PTR_TYPE;
break;
case VALUE_TYPE_F64:
value_type = F64_TYPE;
value_ptr_type = F64_PTR_TYPE;
break;
default:
bh_assert(0);
break;
}
c_api_result_value =
LLVMBuildBitCast(comp_ctx->builder, c_api_result_value,
value_ptr_type, "c_api_result_value_ptr");
snprintf(buf, sizeof(buf), "%s%u", "ret", i);
value_ret = LLVMBuildLoad2(comp_ctx->builder, value_type,
c_api_result_value, buf);
PUSH(value_ret, aot_func_type->types[aot_func_type->param_count + i]);
}
return true;
fail:
return false;
}
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
static bool
call_aot_alloc_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
@ -533,6 +740,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
const char *signature = NULL;
bool ret = false;
char buf[32];
bool quick_invoke_c_api_import = false;
#if WASM_ENABLE_THREAD_MGR != 0
/* Insert suspend check point */
@ -702,17 +910,43 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
if (!signature) {
/* call aot_invoke_native() */
if (!call_aot_invoke_native_func(
comp_ctx, func_ctx, import_func_idx, func_type,
param_types + 1, param_values + 1, param_count,
param_cell_num, ret_type, wasm_ret_type, &value_ret, &res))
goto fail;
/* Check whether there was exception thrown when executing
the function */
if ((comp_ctx->enable_bound_check || is_win_platform(comp_ctx))
&& !check_call_return(comp_ctx, func_ctx, res))
goto fail;
if (comp_ctx->quick_invoke_c_api_import) {
uint32 buf_size_needed =
sizeof(wasm_val_t) * (param_count + result_count);
/* length of exec_env->argv_buf is 64 */
if (buf_size_needed < sizeof(uint32) * 64) {
for (i = 0; i < param_count + result_count; i++) {
/* Only support i32/i64/f32/f64 now */
if (!(func_type->types[i] == VALUE_TYPE_I32
|| func_type->types[i] == VALUE_TYPE_I64
|| func_type->types[i] == VALUE_TYPE_F32
|| func_type->types[i] == VALUE_TYPE_F64))
break;
}
if (i == param_count + result_count)
quick_invoke_c_api_import = true;
}
}
if (quick_invoke_c_api_import) {
if (!call_aot_invoke_c_api_native(comp_ctx, func_ctx, func_idx,
func_type, param_values + 1))
goto fail;
}
else {
/* call aot_invoke_native() */
if (!call_aot_invoke_native_func(
comp_ctx, func_ctx, import_func_idx, func_type,
param_types + 1, param_values + 1, param_count,
param_cell_num, ret_type, wasm_ret_type, &value_ret,
&res))
goto fail;
/* Check whether there was exception thrown when executing
the function */
if ((comp_ctx->enable_bound_check || is_win_platform(comp_ctx))
&& !check_call_return(comp_ctx, func_ctx, res))
goto fail;
}
}
else { /* call native func directly */
LLVMTypeRef native_func_type, func_ptr_type;
@ -869,7 +1103,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
goto fail;
}
if (func_type->result_count > 0) {
if (func_type->result_count > 0 && !quick_invoke_c_api_import) {
/* Push the first result to stack */
PUSH(value_ret, func_type->types[func_type->param_count]);
/* Load extra result from its address and push to stack */

View File

@ -46,6 +46,18 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx,
return offset;
}
uint32
get_module_inst_extra_offset(AOTCompContext *comp_ctx)
{
const AOTCompData *comp_data = comp_ctx->comp_data;
uint32 table_count = comp_data->import_table_count + comp_data->table_count;
uint64 offset = get_tbl_inst_offset(comp_ctx, NULL, table_count);
uint32 offset_32 = (uint32)offset;
bh_assert(offset <= UINT32_MAX);
offset_32 = align_uint(offset_32, 8);
return offset_32;
}
#if WASM_ENABLE_REF_TYPES != 0
LLVMValueRef

View File

@ -49,6 +49,9 @@ uint64
get_tbl_inst_offset(const AOTCompContext *comp_ctx,
const AOTFuncContext *func_ctx, uint32 tbl_idx);
uint32
get_module_inst_extra_offset(AOTCompContext *comp_ctx);
LLVMValueRef
aot_compile_get_tbl_inst(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 tbl_idx);
@ -56,4 +59,4 @@ aot_compile_get_tbl_inst(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif
#endif

View File

@ -2174,7 +2174,7 @@ jit_stack_size_callback(void *user_data, const char *name, size_t namelen,
}
static bool
orc_jit_create(AOTCompContext *comp_ctx, bool linux_perf_support)
orc_jit_create(AOTCompContext *comp_ctx)
{
LLVMErrorRef err;
LLVMOrcLLLazyJITRef orc_jit = NULL;
@ -2214,13 +2214,15 @@ orc_jit_create(AOTCompContext *comp_ctx, bool linux_perf_support)
/* Ownership transfer: LLVMOrcLLJITBuilderRef -> LLVMOrcLLJITRef */
builder = NULL;
if (linux_perf_support) {
LOG_DEBUG("Enable linux perf support");
#if WASM_ENABLE_LINUX_PERF != 0
if (wasm_runtime_get_linux_perf()) {
LOG_DEBUG("Enable linux perf support in JIT");
LLVMOrcObjectLayerRef obj_linking_layer =
(LLVMOrcObjectLayerRef)LLVMOrcLLLazyJITGetObjLinkingLayer(orc_jit);
LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(
obj_linking_layer, LLVMCreatePerfJITEventListener());
}
#endif
/* Ownership transfer: local -> AOTCompContext */
comp_ctx->orc_jit = orc_jit;
@ -2320,7 +2322,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
goto fail;
}
if (option->linux_perf_support) {
#if WASM_ENABLE_LINUX_PERF != 0
if (wasm_runtime_get_linux_perf()) {
/* FramePointerKind.All */
LLVMMetadataRef val =
LLVMValueAsMetadata(LLVMConstInt(LLVMInt32Type(), 2, false));
@ -2330,6 +2333,7 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
comp_ctx->emit_frame_pointer = true;
}
#endif
if (BH_LIST_ERROR == bh_list_init(&comp_ctx->native_symbols)) {
goto fail;
@ -2394,6 +2398,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
if (option->enable_stack_estimation)
comp_ctx->enable_stack_estimation = true;
if (option->quick_invoke_c_api_import)
comp_ctx->quick_invoke_c_api_import = true;
if (option->llvm_passes)
comp_ctx->llvm_passes = option->llvm_passes;
@ -2434,7 +2441,7 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
goto fail;
/* Create LLJIT Instance */
if (!orc_jit_create(comp_ctx, option->linux_perf_support))
if (!orc_jit_create(comp_ctx))
goto fail;
}
else {

View File

@ -321,10 +321,10 @@ typedef struct AOTCompContext {
/* Bulk memory feature */
bool enable_bulk_memory;
/* Bounday Check */
/* Boundary Check */
bool enable_bound_check;
/* Native stack bounday Check */
/* Native stack boundary Check */
bool enable_stack_bound_check;
/* Native stack usage estimation */
@ -357,6 +357,10 @@ typedef struct AOTCompContext {
/* Enable LLVM PGO (Profile-Guided Optimization) */
bool enable_llvm_pgo;
/* Treat unknown import function as wasm-c-api import function
and allow to directly invoke it from AOT/JIT code */
bool quick_invoke_c_api_import;
/* Use profile file collected by LLVM PGO */
char *use_prof_file;
@ -454,6 +458,7 @@ typedef struct AOTCompOption {
bool disable_llvm_lto;
bool enable_llvm_pgo;
bool enable_stack_estimation;
bool quick_invoke_c_api_import;
char *use_prof_file;
uint32 opt_level;
uint32 size_level;
@ -461,7 +466,6 @@ typedef struct AOTCompOption {
uint32 bounds_checks;
uint32 stack_bounds_checks;
uint32 segue_flags;
bool linux_perf_support;
char **custom_sections;
uint32 custom_sections_count;
const char *stack_usage_file;

View File

@ -45,6 +45,7 @@
#include <llvm/Transforms/Vectorize/LoopVectorize.h>
#include <llvm/Transforms/Vectorize/LoadStoreVectorizer.h>
#include <llvm/Transforms/Vectorize/SLPVectorizer.h>
#include <llvm/Transforms/Vectorize/VectorCombine.h>
#include <llvm/Transforms/Scalar/LoopRotation.h>
#include <llvm/Transforms/Scalar/SimpleLoopUnswitch.h>
#include <llvm/Transforms/Scalar/LICM.h>
@ -315,8 +316,11 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module)
}
ModulePassManager MPM;
if (comp_ctx->is_jit_mode) {
const char *Passes =
"loop-vectorize,slp-vectorizer,"
"load-store-vectorizer,vector-combine,"
"mem2reg,instcombine,simplifycfg,jump-threading,indvars";
ExitOnErr(PB.parsePassPipeline(MPM, Passes));
}
@ -327,6 +331,7 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module)
FPM.addPass(LoopVectorizePass());
FPM.addPass(SLPVectorizerPass());
FPM.addPass(LoadStoreVectorizerPass());
FPM.addPass(VectorCombinePass());
if (comp_ctx->enable_llvm_pgo || comp_ctx->use_prof_file) {
/* LICM pass: loop invariant code motion, attempting to remove
@ -404,7 +409,10 @@ aot_compress_aot_func_names(AOTCompContext *comp_ctx, uint32 *p_size)
NameStrs.push_back(str);
}
if (collectPGOFuncNameStrings(NameStrs, true, Result)) {
#if LLVM_VERSION_MAJOR < 18
#define collectGlobalObjectNameStrings collectPGOFuncNameStrings
#endif
if (collectGlobalObjectNameStrings(NameStrs, true, Result)) {
aot_set_last_error("collect pgo func name strings failed");
return NULL;
}

View File

@ -58,6 +58,7 @@ convert(LLVMRelocMode reloc_mode)
#endif
}
#if LLVM_VERSION_MAJOR < 18
static llvm::CodeGenOpt::Level
convert(LLVMCodeGenOptLevel opt_level)
{
@ -74,6 +75,24 @@ convert(LLVMCodeGenOptLevel opt_level)
bh_assert(0);
return llvm::CodeGenOpt::None;
}
#else
static llvm::CodeGenOptLevel
convert(LLVMCodeGenOptLevel opt_level)
{
switch (opt_level) {
case LLVMCodeGenLevelNone:
return llvm::CodeGenOptLevel::None;
case LLVMCodeGenLevelLess:
return llvm::CodeGenOptLevel::Less;
case LLVMCodeGenLevelDefault:
return llvm::CodeGenOptLevel::Default;
case LLVMCodeGenLevelAggressive:
return llvm::CodeGenOptLevel::Aggressive;
}
bh_assert(0);
return llvm::CodeGenOptLevel::None;
}
#endif
static llvm::Optional<llvm::CodeModel::Model>
convert(LLVMCodeModel code_model, bool *jit)

View File

@ -3,6 +3,10 @@
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "llvm-c/LLJIT.h"
#include "llvm-c/Orc.h"
#include "llvm-c/OrcEE.h"
@ -44,6 +48,7 @@ class InProgressLookupState;
class OrcV2CAPIHelper
{
public:
#if LLVM_VERSION_MAJOR < 18
using PoolEntry = SymbolStringPtr::PoolEntry;
using PoolEntryPtr = SymbolStringPtr::PoolEntryPtr;
@ -86,6 +91,7 @@ class OrcV2CAPIHelper
S.S = P;
}
#endif
static InProgressLookupState *extractLookupState(LookupState &LS)
{
return LS.IPLS.release();
@ -101,6 +107,20 @@ class OrcV2CAPIHelper
} // namespace llvm
// ORC.h
#if LLVM_VERSION_MAJOR >= 18
inline LLVMOrcSymbolStringPoolEntryRef
wrap(SymbolStringPoolEntryUnsafe E)
{
return reinterpret_cast<LLVMOrcSymbolStringPoolEntryRef>(E.rawPtr());
}
inline SymbolStringPoolEntryUnsafe
unwrap(LLVMOrcSymbolStringPoolEntryRef E)
{
return reinterpret_cast<SymbolStringPoolEntryUnsafe::PoolEntry *>(E);
}
#endif
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ExecutionSession, LLVMOrcExecutionSessionRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(IRTransformLayer, LLVMOrcIRTransformLayerRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITDylib, LLVMOrcJITDylibRef)
@ -108,8 +128,10 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITTargetMachineBuilder,
LLVMOrcJITTargetMachineBuilderRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectTransformLayer,
LLVMOrcObjectTransformLayerRef)
#if LLVM_VERSION_MAJOR < 18
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcV2CAPIHelper::PoolEntry,
LLVMOrcSymbolStringPoolEntryRef)
#endif
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectLayer, LLVMOrcObjectLayerRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SymbolStringPool, LLVMOrcSymbolStringPoolRef)
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
@ -292,8 +314,13 @@ LLVMOrcSymbolStringPoolEntryRef
LLVMOrcLLLazyJITMangleAndIntern(LLVMOrcLLLazyJITRef J,
const char *UnmangledName)
{
#if LLVM_VERSION_MAJOR < 18
return wrap(OrcV2CAPIHelper::moveFromSymbolStringPtr(
unwrap(J)->mangleAndIntern(UnmangledName)));
#else
return wrap(SymbolStringPoolEntryUnsafe::take(
unwrap(J)->mangleAndIntern(UnmangledName)));
#endif
}
LLVMOrcJITDylibRef

View File

@ -152,7 +152,7 @@ dwarf_gen_mock_vm_info(AOTCompContext *comp_ctx)
comp_unit = LLVMDIBuilderCreateCompileUnit(
comp_ctx->debug_builder, LLVMDWARFSourceLanguageC, file_info,
"ant compiler", 12, 0, NULL, 0, 1, NULL, 0, LLVMDWARFEmissionFull, 0, 0,
"WAMR AoT compiler", 12, 0, NULL, 0, 1, NULL, 0, LLVMDWARFEmissionFull, 0, 0,
0, "/", 1, "", 0);
LLVMTypeRef ParamTys[] = {
@ -208,8 +208,8 @@ dwarf_gen_comp_unit_info(const AOTCompContext *comp_ctx)
comp_unit = LLVMDIBuilderCreateCompileUnit(
comp_ctx->debug_builder, LLDB_TO_LLVM_LANG_TYPE(lang_type),
comp_ctx->debug_file, "ant compiler", 12, 0, NULL, 0, 1, NULL, 0,
LLVMDWARFEmissionFull, 0, 0, 0, "/", 1, "", 0);
comp_ctx->debug_file, "WAMR AoT compiler", 12, 0, NULL, 0, 1, NULL,
0, LLVMDWARFEmissionFull, 0, 0, 0, "/", 1, "", 0);
}
return comp_unit;
}

View File

@ -158,11 +158,15 @@ simd_integer_narrow_common(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return false;
}
/* sat */
/* Refer to:
* https://github.com/WebAssembly/spec/blob/main/proposals/simd/SIMD.md#integer-to-integer-narrowing
* Regardless of the whether the operation is signed or unsigned, the input
* lanes are interpreted as signed integers.
*/
if (!(vec1 = simd_saturate(comp_ctx, func_ctx, e_sat_i16x8, vec1, min, max,
is_signed))
true))
|| !(vec2 = simd_saturate(comp_ctx, func_ctx, e_sat_i16x8, vec2, min,
max, is_signed))) {
max, true))) {
return false;
}
@ -740,4 +744,4 @@ aot_compile_simd_i64x2_extmul_i32x4(AOTCompContext *comp_ctx,
{
return simd_integer_extmul(comp_ctx, func_ctx, lower_half, is_signed,
e_i64x2_extmul_i32x4);
}
}

View File

@ -4379,13 +4379,18 @@ cmp_r_r_to_r_i32(x86::Assembler &a, int32 reg_no_dst, int32 reg_no1_src,
* @return true if success, false otherwise
*/
static bool
cmp_imm_imm_to_r_i64(x86::Assembler &a, int32 reg_no_dst, int32 data1_src,
int32 data2_src)
cmp_imm_imm_to_r_i64(x86::Assembler &a, int32 reg_no_dst, int64 data1_src,
int64 data2_src)
{
Imm imm(data1_src);
a.mov(regs_i64[REG_I64_FREE_IDX], imm);
imm.setValue(data2_src);
a.cmp(regs_i64[REG_I64_FREE_IDX], imm);
/* imm -> m64 */
const JitHardRegInfo *hreg_info = jit_codegen_get_hreg_info();
x86::Mem mem = x86::qword_ptr(regs_i64[hreg_info->exec_env_hreg_index],
offsetof(WASMExecEnv, jit_cache));
Imm imm(data2_src);
mov_imm_to_m(a, mem, imm, 8);
a.mov(regs_i64[REG_I64_FREE_IDX], data1_src);
a.cmp(regs_i64[REG_I64_FREE_IDX], mem);
(void)reg_no_dst;
return true;
}

View File

@ -1066,13 +1066,15 @@ DEF_UNI_INT_CONST_OPS(shru)
static int32
do_i32_const_shl(int32 lhs, int32 rhs)
{
rhs &= 31;
return (int32)((uint32)lhs << (uint32)rhs);
}
static int64
do_i64_const_shl(int64 lhs, int64 rhs)
{
return (int32)((uint64)lhs << (uint64)rhs);
rhs &= 63LL;
return (uint64)lhs << (uint64)rhs;
}
DEF_BI_INT_CONST_OPS(shrs, >>)
@ -1080,12 +1082,14 @@ DEF_BI_INT_CONST_OPS(shrs, >>)
static int32
do_i32_const_shru(int32 lhs, int32 rhs)
{
rhs &= 31;
return (uint32)lhs >> rhs;
}
static int64
do_i64_const_shru(int64 lhs, int64 rhs)
{
rhs &= 63LL;
return (uint64)lhs >> rhs;
}

View File

@ -70,7 +70,6 @@ typedef struct JitInterpSwitchInfo {
typedef struct JitCompOptions {
uint32 code_cache_size;
uint32 opt_level;
bool linux_perf_support;
} JitCompOptions;
bool

View File

@ -58,6 +58,7 @@ typedef struct AOTCompOption {
bool disable_llvm_lto;
bool enable_llvm_pgo;
bool enable_stack_estimation;
bool quick_invoke_c_api_import;
char *use_prof_file;
uint32_t opt_level;
uint32_t size_level;
@ -65,7 +66,6 @@ typedef struct AOTCompOption {
uint32_t bounds_checks;
uint32_t stack_bounds_checks;
uint32_t segue_flags;
bool linux_perf_support;
char **custom_sections;
uint32_t custom_sections_count;
const char *stack_usage_file;

View File

@ -181,7 +181,8 @@ typedef union MemAllocOption {
struct wasm_config_t {
mem_alloc_type_t mem_alloc_type;
MemAllocOption mem_alloc_option;
bool linux_perf_support;
uint32_t segue_flags;
bool enable_linux_perf;
/*TODO: wasi args*/
};
@ -189,7 +190,7 @@ struct wasm_config_t {
* by default:
* - mem_alloc_type is Alloc_With_System_Allocator
* - mem_alloc_option is all 0
* - linux_perf_support is false
* - enable_linux_perf is false
*/
WASM_API_EXTERN own wasm_config_t* wasm_config_new(void);
@ -200,6 +201,17 @@ wasm_config_set_mem_alloc_opt(wasm_config_t *, mem_alloc_type_t, MemAllocOption
WASM_API_EXTERN own wasm_config_t*
wasm_config_set_linux_perf_opt(wasm_config_t *, bool);
/**
* Enable using GS register as the base address of linear memory in linux x86_64,
* which may speedup the linear memory access for LLVM AOT/JIT:
* bit0 to bit4 denotes i32.load, i64.load, f32.load, f64.load, v128.load
* bit8 to bit12 denotes i32.store, i64.store, f32.store, f64.store, v128.store
* For example, 0x01 enables i32.load, 0x0100 enables i32.store.
* To enable all load/store operations, use 0x1F1F
*/
WASM_API_EXTERN wasm_config_t*
wasm_config_set_segue_flags(wasm_config_t *config, uint32_t segue_flags);
// Engine
WASM_DECLARE_OWN(engine)
@ -405,6 +417,7 @@ struct wasm_ref_t;
typedef struct wasm_val_t {
wasm_valkind_t kind;
uint8_t __paddings[7];
union {
int32_t i32;
int64_t i64;

View File

@ -172,12 +172,12 @@ typedef struct RuntimeInitArgs {
/**
* If enabled
* - llvm-jit will output a jitdump file for `perf inject`
* - aot. TBD
* - aot will output a perf-${pid}.map for `perf record`
* - fast-jit. TBD
* - multi-tier-jit. TBD
* - interpreter. TBD
*/
bool linux_perf_support;
bool enable_linux_perf;
} RuntimeInitArgs;
#ifndef WASM_VALKIND_T_DEFINED
@ -199,6 +199,7 @@ struct wasm_ref_t;
typedef struct wasm_val_t {
wasm_valkind_t kind;
uint8_t __paddings[7];
union {
/* also represent a function index */
int32_t i32;
@ -212,6 +213,14 @@ typedef struct wasm_val_t {
} wasm_val_t;
#endif
typedef enum {
WASM_LOG_LEVEL_FATAL = 0,
WASM_LOG_LEVEL_ERROR = 1,
WASM_LOG_LEVEL_WARNING = 2,
WASM_LOG_LEVEL_DEBUG = 3,
WASM_LOG_LEVEL_VERBOSE = 4
} log_level_t;
/**
* Initialize the WASM runtime environment, and also initialize
* the memory allocator with system allocator, which calls os_malloc
@ -234,6 +243,14 @@ wasm_runtime_init(void);
WASM_RUNTIME_API_EXTERN bool
wasm_runtime_full_init(RuntimeInitArgs *init_args);
/**
* Set the log level. To be called after the runtime is initialized.
*
* @param level the log level to set
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_log_level(log_level_t level);
/**
* Query whether a certain running mode is supported for the runtime
*
@ -924,9 +941,6 @@ wasm_runtime_clear_exception(wasm_module_inst_t module_inst);
* - Another thread has a copy of `wasm_module_inst_t` of
* the module instance and wants to terminate it asynchronously.
*
* This function is provided only when WAMR is built with threading enabled.
* (`WASM_ENABLE_THREAD_MGR=1`)
*
* @param module_inst the WASM module instance
*/
WASM_RUNTIME_API_EXTERN void

View File

@ -129,6 +129,10 @@ typedef struct WASMType {
/* Code block to call llvm jit functions of this
kind of function type from fast jit jitted code */
void *call_to_llvm_jit_from_fast_jit;
#endif
#if WASM_ENABLE_QUICK_AOT_ENTRY != 0
/* Quick AOT/JIT entry of this func type */
void *quick_aot_entry;
#endif
/* types of params and results */
uint8 types[1];

View File

@ -2146,11 +2146,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
#if WASM_ENABLE_THREAD_MGR == 0
linear_mem_size = memory->memory_data_size;
#else
linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory);
#endif
#endif
}
@ -4110,7 +4106,7 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
uint32 result_count = func_type->result_count;
uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0;
uint32 func_idx = (uint32)(function - module_inst->e->functions);
bool ret;
bool ret = false;
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
if (!llvm_jit_alloc_frame(exec_env, function - module_inst->e->functions)) {
@ -4138,7 +4134,8 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
if (size > UINT32_MAX
|| !(argv1 = wasm_runtime_malloc((uint32)size))) {
wasm_set_exception(module_inst, "allocate memory failed");
return false;
ret = false;
goto fail;
}
}
@ -4162,7 +4159,7 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
if (!ret) {
if (argv1 != argv1_buf)
wasm_runtime_free(argv1);
return ret;
goto fail;
}
/* Get extra result values */
@ -4196,15 +4193,41 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
if (argv1 != argv1_buf)
wasm_runtime_free(argv1);
return true;
ret = true;
}
else {
ret = wasm_runtime_invoke_native(
exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
argv, argc, argv);
#if WASM_ENABLE_QUICK_AOT_ENTRY != 0
/* Quick call if the quick jit entry is registered */
if (func_type->quick_aot_entry) {
void (*invoke_native)(
void *func_ptr, uint8 ret_type, void *exec_env, uint32 *argv,
uint32 *argv_ret) = func_type->quick_aot_entry;
invoke_native(module_inst->func_ptrs[func_idx],
func_type->result_count > 0
? func_type->types[func_type->param_count]
: VALUE_TYPE_VOID,
exec_env, argv, argv);
ret = !wasm_copy_exception(module_inst, NULL);
}
else
#endif
{
ret = wasm_runtime_invoke_native(
exec_env, module_inst->func_ptrs[func_idx], func_type, NULL,
NULL, argv, argc, argv);
return ret && !wasm_copy_exception(module_inst, NULL) ? true : false;
if (ret)
ret = !wasm_copy_exception(module_inst, NULL);
}
}
fail:
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
llvm_jit_free_frame(exec_env);
#endif
return ret;
}
#endif /* end of WASM_ENABLE_JIT != 0 */
@ -4213,16 +4236,11 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
WASMFunctionInstance *function, uint32 argc,
uint32 argv[])
{
WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env);
WASMInterpFrame *frame, *outs_area;
WASMRuntimeFrame *frame = NULL, *prev_frame, *outs_area;
RunningMode running_mode =
wasm_runtime_get_running_mode((WASMModuleInstanceCommon *)module_inst);
/* Allocate sufficient cells for all kinds of return values. */
unsigned all_cell_num =
function->ret_cell_num > 2 ? function->ret_cell_num : 2;
/* This frame won't be used by JITed code, so only allocate interp
frame here. */
unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
unsigned i;
bool copy_argv_from_frame = true;
bool alloc_frame = true;
if (argc < function->param_cell_num) {
char buf[128];
@ -4245,25 +4263,56 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
}
#endif
if (!(frame = ALLOC_FRAME(exec_env, frame_size, prev_frame)))
return;
outs_area = wasm_exec_env_wasm_stack_top(exec_env);
frame->function = NULL;
frame->ip = NULL;
/* There is no local variable. */
frame->sp = frame->lp + 0;
if ((uint8 *)(outs_area->lp + function->param_cell_num)
> exec_env->wasm_stack.s.top_boundary) {
wasm_set_exception(module_inst, "wasm operand stack overflow");
return;
if (!function->is_import_func) {
/* No need to alloc frame when calling LLVM JIT function */
#if WASM_ENABLE_JIT != 0
if (running_mode == Mode_LLVM_JIT) {
alloc_frame = false;
}
#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_FAST_JIT != 0
else if (running_mode == Mode_Multi_Tier_JIT) {
/* Tier-up from Fast JIT to LLVM JIT, call llvm jit function
if it is compiled, else call fast jit function */
uint32 func_idx = (uint32)(function - module_inst->e->functions);
if (module_inst->module->func_ptrs_compiled
[func_idx - module_inst->module->import_function_count]) {
alloc_frame = false;
}
}
#endif
#endif
}
if (argc > 0)
word_copy(outs_area->lp, argv, argc);
if (alloc_frame) {
unsigned all_cell_num =
function->ret_cell_num > 2 ? function->ret_cell_num : 2;
unsigned frame_size;
wasm_exec_env_set_cur_frame(exec_env, frame);
prev_frame = wasm_exec_env_get_cur_frame(exec_env);
/* This frame won't be used by JITed code, so only allocate interp
frame here. */
frame_size = wasm_interp_interp_frame_size(all_cell_num);
if (!(frame = ALLOC_FRAME(exec_env, frame_size, prev_frame)))
return;
outs_area = wasm_exec_env_wasm_stack_top(exec_env);
frame->function = NULL;
frame->ip = NULL;
/* There is no local variable. */
frame->sp = frame->lp + 0;
if ((uint8 *)(outs_area->lp + function->param_cell_num)
> exec_env->wasm_stack.s.top_boundary) {
wasm_set_exception(module_inst, "wasm operand stack overflow");
return;
}
if (argc > 0)
word_copy(outs_area->lp, argv, argc);
wasm_exec_env_set_cur_frame(exec_env, frame);
}
#if defined(os_writegsbase)
{
@ -4289,9 +4338,6 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
}
}
else {
RunningMode running_mode =
wasm_runtime_get_running_mode((wasm_module_inst_t)module_inst);
if (running_mode == Mode_Interp) {
wasm_interp_call_func_bytecode(module_inst, exec_env, function,
frame);
@ -4305,9 +4351,6 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
else if (running_mode == Mode_LLVM_JIT) {
llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc,
argv);
/* For llvm jit, the results have been stored in argv,
no need to copy them from stack frame again */
copy_argv_from_frame = false;
}
#endif
#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 \
@ -4320,9 +4363,6 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
[func_idx - module_inst->module->import_function_count]) {
llvm_jit_call_func_bytecode(module_inst, exec_env, function,
argc, argv);
/* For llvm jit, the results have been stored in argv,
no need to copy them from stack frame again */
copy_argv_from_frame = false;
}
else {
fast_jit_call_func_bytecode(module_inst, exec_env, function,
@ -4343,7 +4383,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
/* Output the return value to the caller */
if (!wasm_copy_exception(module_inst, NULL)) {
if (copy_argv_from_frame) {
if (alloc_frame) {
uint32 i;
for (i = 0; i < function->ret_cell_num; i++) {
argv[i] = *(frame->sp + i - function->ret_cell_num);
}
@ -4357,6 +4398,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
#endif
}
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
FREE_FRAME(exec_env, frame);
if (alloc_frame) {
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
FREE_FRAME(exec_env, frame);
}
}

View File

@ -1931,11 +1931,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
#if WASM_ENABLE_THREAD_MGR == 0
linear_mem_size = memory->memory_data_size;
#else
linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory);
#endif
#endif
}

View File

@ -641,6 +641,10 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
type->param_cell_num = (uint16)param_cell_num;
type->ret_cell_num = (uint16)ret_cell_num;
#if WASM_ENABLE_QUICK_AOT_ENTRY != 0
type->quick_aot_entry = wasm_native_lookup_quick_aot_entry(type);
#endif
/* If there is already a same type created, use it instead */
for (j = 0; j < i; j++) {
if (wasm_type_equal(type, module->types[j])) {
@ -2675,8 +2679,12 @@ handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
if (!(module->functions[func_index]->field_name =
const_str_list_insert(
p, func_name_len, module,
is_load_from_file_buf, error_buf,
error_buf_size))) {
#if WASM_ENABLE_WAMR_COMPILER != 0
false,
#else
is_load_from_file_buf,
#endif
error_buf, error_buf_size))) {
return false;
}
}
@ -2848,7 +2856,7 @@ static bool
init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
uint32 error_buf_size)
{
LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options();
LLVMJITOptions *llvm_jit_options = wasm_runtime_get_llvm_jit_options();
AOTCompOption option = { 0 };
char *aot_last_error;
uint64 size;
@ -2888,11 +2896,11 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
option.is_jit_mode = true;
llvm_jit_options = wasm_runtime_get_llvm_jit_options();
option.opt_level = llvm_jit_options.opt_level;
option.size_level = llvm_jit_options.size_level;
option.segue_flags = llvm_jit_options.segue_flags;
option.linux_perf_support = llvm_jit_options.linux_perf_support;
option.opt_level = llvm_jit_options->opt_level;
option.size_level = llvm_jit_options->size_level;
option.segue_flags = llvm_jit_options->segue_flags;
option.quick_invoke_c_api_import =
llvm_jit_options->quick_invoke_c_api_import;
#if WASM_ENABLE_BULK_MEMORY != 0
option.enable_bulk_memory = true;
@ -4941,6 +4949,9 @@ typedef struct BranchBlock {
BranchBlockPatch *patch_list;
/* This is used to save params frame_offset of of if block */
int16 *param_frame_offsets;
/* This is used to store available param num for if/else branch, so the else
* opcode can know how many parameters should be copied to the stack */
uint32 available_param_num;
#endif
/* Indicate the operand stack is in polymorphic state.
@ -6858,15 +6869,18 @@ fail:
* 1) POP original parameter out;
* 2) Push and copy original values to dynamic space.
* The copy instruction format:
* Part a: param count
* Part a: available param count
* Part b: all param total cell num
* Part c: each param's cell_num, src offset and dst offset
* Part d: each param's src offset
* Part e: each param's dst offset
* Note: if the stack is in polymorphic state, the actual copied parameters may
* be fewer than the defined number in block type
*/
static bool
copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
char *error_buf, uint32 error_buf_size)
uint32 *p_available_param_count, char *error_buf,
uint32 error_buf_size)
{
bool ret = false;
int16 *frame_offset = NULL;
@ -6878,35 +6892,47 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
BlockType *block_type = &block->block_type;
WASMType *wasm_type = block_type->u.type;
uint32 param_count = block_type->u.type->param_count;
uint32 available_param_count = 0;
int16 condition_offset = 0;
bool disable_emit = false;
int16 operand_offset = 0;
uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets));
/* For if block, we also need copy the condition operand offset. */
if (is_if_block)
size += sizeof(*cells) + sizeof(*src_offsets);
/* Allocate memory for the emit data */
if (!(emit_data = loader_malloc(size, error_buf, error_buf_size)))
return false;
cells = emit_data;
src_offsets = (int16 *)(cells + param_count);
uint64 size;
if (is_if_block)
condition_offset = *loader_ctx->frame_offset;
/* POP original parameter out */
for (i = 0; i < param_count; i++) {
int32 available_stack_cell =
(int32)(loader_ctx->stack_cell_num - block->stack_cell_num);
if (available_stack_cell <= 0 && block->is_stack_polymorphic)
break;
POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]);
wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
}
available_param_count = i;
size =
(uint64)available_param_count * (sizeof(*cells) + sizeof(*src_offsets));
/* For if block, we also need copy the condition operand offset. */
if (is_if_block)
size += sizeof(*cells) + sizeof(*src_offsets);
/* Allocate memory for the emit data */
if ((size > 0)
&& !(emit_data = loader_malloc(size, error_buf, error_buf_size)))
return false;
cells = emit_data;
src_offsets = (int16 *)(cells + param_count);
frame_offset = loader_ctx->frame_offset;
/* Get each param's cell num and src offset */
for (i = 0; i < param_count; i++) {
for (i = 0; i < available_param_count; i++) {
cell = (uint8)wasm_value_type_cell_num(wasm_type->types[i]);
cells[i] = cell;
src_offsets[i] = *frame_offset;
@ -6916,34 +6942,41 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
/* emit copy instruction */
emit_label(EXT_OP_COPY_STACK_VALUES);
/* Part a) */
emit_uint32(loader_ctx, is_if_block ? param_count + 1 : param_count);
emit_uint32(loader_ctx, is_if_block ? available_param_count + 1
: available_param_count);
/* Part b) */
emit_uint32(loader_ctx, is_if_block ? wasm_type->param_cell_num + 1
: wasm_type->param_cell_num);
/* Part c) */
for (i = 0; i < param_count; i++)
for (i = 0; i < available_param_count; i++)
emit_byte(loader_ctx, cells[i]);
if (is_if_block)
emit_byte(loader_ctx, 1);
/* Part d) */
for (i = 0; i < param_count; i++)
for (i = 0; i < available_param_count; i++)
emit_operand(loader_ctx, src_offsets[i]);
if (is_if_block)
emit_operand(loader_ctx, condition_offset);
/* Part e) */
/* Push to dynamic space. The push will emit the dst offset. */
for (i = 0; i < param_count; i++)
for (i = 0; i < available_param_count; i++)
PUSH_OFFSET_TYPE(wasm_type->types[i]);
if (is_if_block)
PUSH_OFFSET_TYPE(VALUE_TYPE_I32);
if (p_available_param_count) {
*p_available_param_count = available_param_count;
}
ret = true;
fail:
/* Free the emit data */
wasm_runtime_free(emit_data);
if (emit_data) {
wasm_runtime_free(emit_data);
}
return ret;
}
@ -7071,7 +7104,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
uint8 *func_const_end, *func_const = NULL;
int16 operand_offset = 0;
uint8 last_op = 0;
bool disable_emit, preserve_local = false;
bool disable_emit, preserve_local = false, if_condition_available = true;
float32 f32_const;
float64 f64_const;
@ -7141,11 +7174,24 @@ re_scan:
break;
case WASM_OP_IF:
{
#if WASM_ENABLE_FAST_INTERP != 0
BranchBlock *parent_block = loader_ctx->frame_csp - 1;
int32 available_stack_cell =
(int32)(loader_ctx->stack_cell_num
- parent_block->stack_cell_num);
if (available_stack_cell <= 0
&& parent_block->is_stack_polymorphic)
if_condition_available = false;
else
if_condition_available = true;
PRESERVE_LOCAL_FOR_BLOCK();
#endif
POP_I32();
goto handle_op_block_and_loop;
}
case WASM_OP_BLOCK:
case WASM_OP_LOOP:
#if WASM_ENABLE_FAST_INTERP != 0
@ -7155,6 +7201,9 @@ re_scan:
{
uint8 value_type;
BlockType block_type;
#if WASM_ENABLE_FAST_INTERP != 0
uint32 available_params = 0;
#endif
p_org = p - 1;
CHECK_BUF(p, p_end, 1);
@ -7196,9 +7245,27 @@ re_scan:
/* Pop block parameters from stack */
if (BLOCK_HAS_PARAM(block_type)) {
WASMType *wasm_type = block_type.u.type;
for (i = 0; i < block_type.u.type->param_count; i++)
BranchBlock *cur_block = loader_ctx->frame_csp - 1;
#if WASM_ENABLE_FAST_INTERP != 0
available_params = block_type.u.type->param_count;
#endif
for (i = 0; i < block_type.u.type->param_count; i++) {
int32 available_stack_cell =
(int32)(loader_ctx->stack_cell_num
- cur_block->stack_cell_num);
if (available_stack_cell <= 0
&& cur_block->is_stack_polymorphic) {
#if WASM_ENABLE_FAST_INTERP != 0
available_params = i;
#endif
break;
}
POP_TYPE(
wasm_type->types[wasm_type->param_count - i - 1]);
}
}
PUSH_CSP(LABEL_TYPE_BLOCK + (opcode - WASM_OP_BLOCK),
@ -7206,25 +7273,35 @@ re_scan:
/* Pass parameters to block */
if (BLOCK_HAS_PARAM(block_type)) {
for (i = 0; i < block_type.u.type->param_count; i++)
for (i = 0; i < block_type.u.type->param_count; i++) {
PUSH_TYPE(block_type.u.type->types[i]);
#if WASM_ENABLE_FAST_INTERP != 0
if (i >= available_params) {
PUSH_OFFSET_TYPE(block_type.u.type->types[i]);
}
#endif
}
}
#if WASM_ENABLE_FAST_INTERP != 0
if (opcode == WASM_OP_BLOCK || opcode == WASM_OP_LOOP) {
skip_label();
if (BLOCK_HAS_PARAM(block_type)) {
/* Make sure params are in dynamic space */
if (!copy_params_to_dynamic_space(
loader_ctx, false, error_buf, error_buf_size))
if (!copy_params_to_dynamic_space(loader_ctx, false,
NULL, error_buf,
error_buf_size))
goto fail;
}
if (opcode == WASM_OP_LOOP) {
(loader_ctx->frame_csp - 1)->code_compiled =
loader_ctx->p_code_compiled;
}
}
else if (opcode == WASM_OP_IF) {
BranchBlock *block = loader_ctx->frame_csp - 1;
/* If block has parameters, we should make sure they are in
* dynamic space. Otherwise, when else branch is missing,
* the later opcode may consume incorrect operand offset.
@ -7242,8 +7319,7 @@ re_scan:
* recover them before entering else branch.
*
*/
if (BLOCK_HAS_PARAM(block_type)) {
BranchBlock *block = loader_ctx->frame_csp - 1;
if (if_condition_available && BLOCK_HAS_PARAM(block_type)) {
uint64 size;
/* skip the if condition operand offset */
@ -7252,7 +7328,8 @@ re_scan:
skip_label();
/* Emit a copy instruction */
if (!copy_params_to_dynamic_space(
loader_ctx, true, error_buf, error_buf_size))
loader_ctx, true, &block->available_param_num,
error_buf, error_buf_size))
goto fail;
/* Emit the if instruction */
@ -7273,6 +7350,9 @@ re_scan:
- size / sizeof(int16),
(uint32)size);
}
else {
block->available_param_num = 0;
}
emit_empty_label_addr_and_frame_ip(PATCH_ELSE);
emit_empty_label_addr_and_frame_ip(PATCH_END);
@ -7283,7 +7363,8 @@ re_scan:
case WASM_OP_ELSE:
{
BlockType block_type = (loader_ctx->frame_csp - 1)->block_type;
BranchBlock *block = NULL;
BlockType block_type;
if (loader_ctx->csp_num < 2
|| (loader_ctx->frame_csp - 1)->label_type
@ -7293,13 +7374,15 @@ re_scan:
"opcode else found without matched opcode if");
goto fail;
}
block = loader_ctx->frame_csp - 1;
/* check whether if branch's stack matches its result type */
if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1,
error_buf, error_buf_size))
if (!check_block_stack(loader_ctx, block, error_buf,
error_buf_size))
goto fail;
(loader_ctx->frame_csp - 1)->else_addr = p - 1;
block->else_addr = p - 1;
block_type = block->block_type;
#if WASM_ENABLE_FAST_INTERP != 0
/* if the result of if branch is in local or const area, add a
@ -7320,10 +7403,9 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
/* Recover top param_count values of frame_offset stack */
if (BLOCK_HAS_PARAM((block_type))) {
if (block->available_param_num) {
uint32 size;
BranchBlock *block = loader_ctx->frame_csp - 1;
size = sizeof(int16) * block_type.u.type->param_cell_num;
size = sizeof(int16) * block->available_param_num;
bh_memcpy_s(loader_ctx->frame_offset, size,
block->param_frame_offsets, size);
loader_ctx->frame_offset += (size / sizeof(int16));
@ -8062,13 +8144,33 @@ re_scan:
case WASM_OP_REF_IS_NULL:
{
#if WASM_ENABLE_FAST_INTERP != 0
if (!wasm_loader_pop_frame_ref_offset(loader_ctx,
VALUE_TYPE_FUNCREF,
error_buf, error_buf_size)
&& !wasm_loader_pop_frame_ref_offset(
loader_ctx, VALUE_TYPE_EXTERNREF, error_buf,
error_buf_size)) {
goto fail;
BranchBlock *cur_block = loader_ctx->frame_csp - 1;
int32 block_stack_cell_num =
(int32)(loader_ctx->stack_cell_num
- cur_block->stack_cell_num);
if (block_stack_cell_num <= 0) {
if (!cur_block->is_stack_polymorphic) {
set_error_buf(
error_buf, error_buf_size,
"type mismatch: expect data but stack was empty");
goto fail;
}
}
else {
if (*(loader_ctx->frame_ref - 1) == VALUE_TYPE_FUNCREF
|| *(loader_ctx->frame_ref - 1) == VALUE_TYPE_EXTERNREF
|| *(loader_ctx->frame_ref - 1) == VALUE_TYPE_ANY) {
if (!wasm_loader_pop_frame_ref_offset(
loader_ctx, *(loader_ctx->frame_ref - 1),
error_buf, error_buf_size)) {
goto fail;
}
}
else {
set_error_buf(error_buf, error_buf_size,
"type mismatch");
goto fail;
}
}
#else
if (!wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_FUNCREF,
@ -8097,10 +8199,11 @@ re_scan:
bool func_declared = false;
uint32 j;
/* Check whether the function is declared in table segs */
/* Check whether the function is declared in table segs,
note that it doesn't matter whether the table seg's mode
is passive, active or declarative. */
for (i = 0; i < module->table_seg_count; i++, table_seg++) {
if (table_seg->elem_type == VALUE_TYPE_FUNCREF
&& wasm_elem_is_declarative(table_seg->mode)) {
if (table_seg->elem_type == VALUE_TYPE_FUNCREF) {
for (j = 0; j < table_seg->function_count; j++) {
if (table_seg->func_indexes[j] == func_idx) {
func_declared = true;
@ -8365,8 +8468,6 @@ re_scan:
- module->import_global_count]
.type;
POP_TYPE(global_type);
#if WASM_ENABLE_FAST_INTERP == 0
if (global_type == VALUE_TYPE_I64
|| global_type == VALUE_TYPE_F64) {
@ -8405,6 +8506,9 @@ re_scan:
emit_uint32(loader_ctx, global_idx);
POP_OFFSET_TYPE(global_type);
#endif /* end of WASM_ENABLE_FAST_INTERP */
POP_TYPE(global_type);
break;
}

View File

@ -418,6 +418,10 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
type->param_cell_num = (uint16)param_cell_num;
type->ret_cell_num = (uint16)ret_cell_num;
#if WASM_ENABLE_QUICK_AOT_ENTRY != 0
type->quick_aot_entry = wasm_native_lookup_quick_aot_entry(type);
#endif
/* If there is already a same type created, use it instead */
for (j = 0; j < i; ++j) {
if (wasm_type_equal(type, module->types[j])) {
@ -1874,10 +1878,11 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
}
option.is_jit_mode = true;
option.opt_level = llvm_jit_options.opt_level;
option.size_level = llvm_jit_options.size_level;
option.segue_flags = llvm_jit_options.segue_flags;
option.linux_perf_support = llvm_jit_options.linux_perf_support;
option.opt_level = llvm_jit_options->opt_level;
option.size_level = llvm_jit_options->size_level;
option.segue_flags = llvm_jit_options->segue_flags;
option.quick_invoke_c_api_import =
llvm_jit_options->quick_invoke_c_api_import;
#if WASM_ENABLE_BULK_MEMORY != 0
option.enable_bulk_memory = true;
@ -3595,6 +3600,9 @@ typedef struct BranchBlock {
BranchBlockPatch *patch_list;
/* This is used to save params frame_offset of of if block */
int16 *param_frame_offsets;
/* This is used to store available param num for if/else branch, so the else
* opcode can know how many parameters should be copied to the stack */
uint32 available_param_num;
#endif
/* Indicate the operand stack is in polymorphic state.
@ -5344,16 +5352,20 @@ fail:
* 1) POP original parameter out;
* 2) Push and copy original values to dynamic space.
* The copy instruction format:
* Part a: param count
* Part a: available param count
* Part b: all param total cell num
* Part c: each param's cell_num, src offset and dst offset
* Part d: each param's src offset
* Part e: each param's dst offset
* Note: if the stack is in polymorphic state, the actual copied parameters may
* be fewer than the defined number in block type
*/
static bool
copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
char *error_buf, uint32 error_buf_size)
uint32 *p_available_param_count, char *error_buf,
uint32 error_buf_size)
{
bool ret = false;
int16 *frame_offset = NULL;
uint8 *cells = NULL, cell;
int16 *src_offsets = NULL;
@ -5363,35 +5375,47 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
BlockType *block_type = &block->block_type;
WASMType *wasm_type = block_type->u.type;
uint32 param_count = block_type->u.type->param_count;
uint32 available_param_count = 0;
int16 condition_offset = 0;
bool disable_emit = false;
int16 operand_offset = 0;
uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets));
/* For if block, we also need copy the condition operand offset. */
if (is_if_block)
size += sizeof(*cells) + sizeof(*src_offsets);
/* Allocate memory for the emit data */
if (!(emit_data = loader_malloc(size, error_buf, error_buf_size)))
return false;
cells = emit_data;
src_offsets = (int16 *)(cells + param_count);
uint64 size;
if (is_if_block)
condition_offset = *loader_ctx->frame_offset;
/* POP original parameter out */
for (i = 0; i < param_count; i++) {
int32 available_stack_cell =
(int32)(loader_ctx->stack_cell_num - block->stack_cell_num);
if (available_stack_cell <= 0 && block->is_stack_polymorphic)
break;
POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]);
wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
}
available_param_count = i;
size =
(uint64)available_param_count * (sizeof(*cells) + sizeof(*src_offsets));
/* For if block, we also need copy the condition operand offset. */
if (is_if_block)
size += sizeof(*cells) + sizeof(*src_offsets);
/* Allocate memory for the emit data */
if ((size > 0)
&& !(emit_data = loader_malloc(size, error_buf, error_buf_size)))
return false;
cells = emit_data;
src_offsets = (int16 *)(cells + param_count);
frame_offset = loader_ctx->frame_offset;
/* Get each param's cell num and src offset */
for (i = 0; i < param_count; i++) {
for (i = 0; i < available_param_count; i++) {
cell = (uint8)wasm_value_type_cell_num(wasm_type->types[i]);
cells[i] = cell;
src_offsets[i] = *frame_offset;
@ -5401,37 +5425,43 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
/* emit copy instruction */
emit_label(EXT_OP_COPY_STACK_VALUES);
/* Part a) */
emit_uint32(loader_ctx, is_if_block ? param_count + 1 : param_count);
emit_uint32(loader_ctx, is_if_block ? available_param_count + 1
: available_param_count);
/* Part b) */
emit_uint32(loader_ctx, is_if_block ? wasm_type->param_cell_num + 1
: wasm_type->param_cell_num);
/* Part c) */
for (i = 0; i < param_count; i++)
for (i = 0; i < available_param_count; i++)
emit_byte(loader_ctx, cells[i]);
if (is_if_block)
emit_byte(loader_ctx, 1);
/* Part d) */
for (i = 0; i < param_count; i++)
for (i = 0; i < available_param_count; i++)
emit_operand(loader_ctx, src_offsets[i]);
if (is_if_block)
emit_operand(loader_ctx, condition_offset);
/* Part e) */
/* Push to dynamic space. The push will emit the dst offset. */
for (i = 0; i < param_count; i++)
for (i = 0; i < available_param_count; i++)
PUSH_OFFSET_TYPE(wasm_type->types[i]);
if (is_if_block)
PUSH_OFFSET_TYPE(VALUE_TYPE_I32);
/* Free the emit data */
wasm_runtime_free(emit_data);
return true;
if (p_available_param_count) {
*p_available_param_count = available_param_count;
}
ret = true;
fail:
/* Free the emit data */
wasm_runtime_free(emit_data);
return false;
if (emit_data) {
wasm_runtime_free(emit_data);
}
return ret;
}
#endif
@ -5498,7 +5528,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
uint8 *func_const_end, *func_const = NULL;
int16 operand_offset = 0;
uint8 last_op = 0;
bool disable_emit, preserve_local = false;
bool disable_emit, preserve_local = false, if_condition_available = true;
;
float32 f32_const;
float64 f64_const;
@ -5568,11 +5599,23 @@ re_scan:
break;
case WASM_OP_IF:
{
#if WASM_ENABLE_FAST_INTERP != 0
BranchBlock *parent_block = loader_ctx->frame_csp - 1;
int32 available_stack_cell =
(int32)(loader_ctx->stack_cell_num
- parent_block->stack_cell_num);
if (available_stack_cell <= 0
&& parent_block->is_stack_polymorphic)
if_condition_available = false;
else
if_condition_available = true;
PRESERVE_LOCAL_FOR_BLOCK();
#endif
POP_I32();
goto handle_op_block_and_loop;
}
case WASM_OP_BLOCK:
case WASM_OP_LOOP:
#if WASM_ENABLE_FAST_INTERP != 0
@ -5582,6 +5625,9 @@ re_scan:
{
uint8 value_type;
BlockType block_type;
#if WASM_ENABLE_FAST_INTERP != 0
uint32 available_params = 0;
#endif
p_org = p - 1;
value_type = read_uint8(p);
@ -5612,9 +5658,27 @@ re_scan:
/* Pop block parameters from stack */
if (BLOCK_HAS_PARAM(block_type)) {
WASMType *wasm_type = block_type.u.type;
for (i = 0; i < block_type.u.type->param_count; i++)
BranchBlock *cur_block = loader_ctx->frame_csp - 1;
#if WASM_ENABLE_FAST_INTERP != 0
available_params = block_type.u.type->param_count;
#endif
for (i = 0; i < block_type.u.type->param_count; i++) {
int32 available_stack_cell =
(int32)(loader_ctx->stack_cell_num
- cur_block->stack_cell_num);
if (available_stack_cell <= 0
&& cur_block->is_stack_polymorphic) {
#if WASM_ENABLE_FAST_INTERP != 0
available_params = i;
#endif
break;
}
POP_TYPE(
wasm_type->types[wasm_type->param_count - i - 1]);
}
}
PUSH_CSP(LABEL_TYPE_BLOCK + (opcode - WASM_OP_BLOCK),
@ -5622,8 +5686,14 @@ re_scan:
/* Pass parameters to block */
if (BLOCK_HAS_PARAM(block_type)) {
for (i = 0; i < block_type.u.type->param_count; i++)
for (i = 0; i < block_type.u.type->param_count; i++) {
PUSH_TYPE(block_type.u.type->types[i]);
#if WASM_ENABLE_FAST_INTERP != 0
if (i >= available_params) {
PUSH_OFFSET_TYPE(block_type.u.type->types[i]);
}
#endif
}
}
#if WASM_ENABLE_FAST_INTERP != 0
@ -5631,8 +5701,9 @@ re_scan:
skip_label();
if (BLOCK_HAS_PARAM(block_type)) {
/* Make sure params are in dynamic space */
if (!copy_params_to_dynamic_space(
loader_ctx, false, error_buf, error_buf_size))
if (!copy_params_to_dynamic_space(loader_ctx, false,
NULL, error_buf,
error_buf_size))
goto fail;
}
if (opcode == WASM_OP_LOOP) {
@ -5641,6 +5712,7 @@ re_scan:
}
}
else if (opcode == WASM_OP_IF) {
BranchBlock *block = loader_ctx->frame_csp - 1;
/* If block has parameters, we should make sure they are in
* dynamic space. Otherwise, when else branch is missing,
* the later opcode may consume incorrect operand offset.
@ -5658,8 +5730,7 @@ re_scan:
* recover them before entering else branch.
*
*/
if (BLOCK_HAS_PARAM(block_type)) {
BranchBlock *block = loader_ctx->frame_csp - 1;
if (if_condition_available && BLOCK_HAS_PARAM(block_type)) {
uint64 size;
/* skip the if condition operand offset */
@ -5668,7 +5739,8 @@ re_scan:
skip_label();
/* Emit a copy instruction */
if (!copy_params_to_dynamic_space(
loader_ctx, true, error_buf, error_buf_size))
loader_ctx, true, &block->available_param_num,
error_buf, error_buf_size))
goto fail;
/* Emit the if instruction */
@ -5689,6 +5761,9 @@ re_scan:
- size / sizeof(int16),
(uint32)size);
}
else {
block->available_param_num = 0;
}
emit_empty_label_addr_and_frame_ip(PATCH_ELSE);
emit_empty_label_addr_and_frame_ip(PATCH_END);
@ -5699,17 +5774,19 @@ re_scan:
case WASM_OP_ELSE:
{
BranchBlock *block = NULL;
BlockType block_type = (loader_ctx->frame_csp - 1)->block_type;
bh_assert(loader_ctx->csp_num >= 2
&& (loader_ctx->frame_csp - 1)->label_type
== LABEL_TYPE_IF);
block = loader_ctx->frame_csp - 1;
/* check whether if branch's stack matches its result type */
if (!check_block_stack(loader_ctx, loader_ctx->frame_csp - 1,
error_buf, error_buf_size))
if (!check_block_stack(loader_ctx, block, error_buf,
error_buf_size))
goto fail;
(loader_ctx->frame_csp - 1)->else_addr = p - 1;
block->else_addr = p - 1;
#if WASM_ENABLE_FAST_INTERP != 0
/* if the result of if branch is in local or const area, add a
@ -5730,10 +5807,9 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
/* Recover top param_count values of frame_offset stack */
if (BLOCK_HAS_PARAM((block_type))) {
if (block->available_param_num) {
uint32 size;
BranchBlock *block = loader_ctx->frame_csp - 1;
size = sizeof(int16) * block_type.u.type->param_cell_num;
size = sizeof(int16) * block->available_param_num;
bh_memcpy_s(loader_ctx->frame_offset, size,
block->param_frame_offsets, size);
loader_ctx->frame_offset += (size / sizeof(int16));
@ -6356,13 +6432,33 @@ re_scan:
case WASM_OP_REF_IS_NULL:
{
#if WASM_ENABLE_FAST_INTERP != 0
if (!wasm_loader_pop_frame_ref_offset(loader_ctx,
VALUE_TYPE_FUNCREF,
error_buf, error_buf_size)
&& !wasm_loader_pop_frame_ref_offset(
loader_ctx, VALUE_TYPE_EXTERNREF, error_buf,
error_buf_size)) {
goto fail;
BranchBlock *cur_block = loader_ctx->frame_csp - 1;
int32 block_stack_cell_num =
(int32)(loader_ctx->stack_cell_num
- cur_block->stack_cell_num);
if (block_stack_cell_num <= 0) {
if (!cur_block->is_stack_polymorphic) {
set_error_buf(
error_buf, error_buf_size,
"type mismatch: expect data but stack was empty");
goto fail;
}
}
else {
if (*(loader_ctx->frame_ref - 1) == VALUE_TYPE_FUNCREF
|| *(loader_ctx->frame_ref - 1) == VALUE_TYPE_EXTERNREF
|| *(loader_ctx->frame_ref - 1) == VALUE_TYPE_ANY) {
if (!wasm_loader_pop_frame_ref_offset(
loader_ctx, *(loader_ctx->frame_ref - 1),
error_buf, error_buf_size)) {
goto fail;
}
}
else {
set_error_buf(error_buf, error_buf_size,
"type mismatch");
goto fail;
}
}
#else
if (!wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_FUNCREF,
@ -6392,10 +6488,11 @@ re_scan:
bool func_declared = false;
uint32 j;
/* Check whether the function is declared in table segs */
/* Check whether the function is declared in table segs,
note that it doesn't matter whether the table seg's mode
is passive, active or declarative. */
for (i = 0; i < module->table_seg_count; i++, table_seg++) {
if (table_seg->elem_type == VALUE_TYPE_FUNCREF
&& wasm_elem_is_declarative(table_seg->mode)) {
if (table_seg->elem_type == VALUE_TYPE_FUNCREF) {
for (j = 0; j < table_seg->function_count; j++) {
if (table_seg->func_indexes[j] == func_idx) {
func_declared = true;
@ -6630,8 +6727,6 @@ re_scan:
- module->import_global_count]
.type;
POP_TYPE(global_type);
#if WASM_ENABLE_FAST_INTERP == 0
if (is_64bit_type(global_type)) {
*p_org = WASM_OP_SET_GLOBAL_64;
@ -6657,6 +6752,8 @@ re_scan:
POP_OFFSET_TYPE(global_type);
#endif /* end of WASM_ENABLE_FAST_INTERP */
POP_TYPE(global_type);
(void)is_mutable;
break;
}

View File

@ -2271,7 +2271,6 @@ wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name)
#endif
#ifdef OS_ENABLE_HW_BOUND_CHECK
static void
call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
WASMExecEnv *exec_env,
@ -2301,19 +2300,26 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
return;
}
if (exec_env_tls && (exec_env_tls != exec_env)) {
wasm_set_exception(module_inst, "invalid exec env");
return;
}
if (!exec_env_tls) {
if (!os_thread_signal_inited()) {
wasm_set_exception(module_inst, "thread signal env not inited");
return;
}
if (!os_thread_signal_inited()) {
wasm_set_exception(module_inst, "thread signal env not inited");
return;
/* Set thread handle and stack boundary if they haven't been set */
wasm_exec_env_set_thread_info(exec_env);
wasm_runtime_set_exec_env_tls(exec_env);
}
else {
if (exec_env_tls != exec_env) {
wasm_set_exception(module_inst, "invalid exec env");
return;
}
}
wasm_exec_env_push_jmpbuf(exec_env, &jmpbuf_node);
wasm_runtime_set_exec_env_tls(exec_env);
if (os_setjmp(jmpbuf_node.jmpbuf) == 0) {
#ifndef BH_PLATFORM_WINDOWS
wasm_interp_call_wasm(module_inst, exec_env, function, argc, argv);
@ -2323,7 +2329,7 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
} __except (wasm_copy_exception(module_inst, NULL)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
/* exception was thrown in wasm_exception_handler */
/* Exception was thrown in wasm_exception_handler */
ret = false;
}
has_exception = wasm_copy_exception(module_inst, exception);
@ -2377,10 +2383,15 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
WASMModuleInstance *module_inst =
(WASMModuleInstance *)exec_env->module_inst;
/* set thread handle and stack boundary */
#ifndef OS_ENABLE_HW_BOUND_CHECK
/* Set thread handle and stack boundary */
wasm_exec_env_set_thread_info(exec_env);
#else
/* Set thread info in call_wasm_with_hw_bound_check when
hw bound check is enabled */
#endif
/* set exec env so it can be later retrieved from instance */
/* Set exec env so it can be later retrieved from instance */
module_inst->e->common.cur_exec_env = exec_env;
interp_call_wasm(module_inst, exec_env, function, argc, argv);

View File

@ -221,8 +221,8 @@ typedef struct CApiFuncImport {
/* The common part of WASMModuleInstanceExtra and AOTModuleInstanceExtra */
typedef struct WASMModuleInstanceExtraCommon {
void *contexts[WASM_MAX_INSTANCE_CONTEXTS];
CApiFuncImport *c_api_func_imports;
void *contexts[WASM_MAX_INSTANCE_CONTEXTS];
/* pointer to the exec env currently used */
WASMExecEnv *cur_exec_env;
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0

View File

@ -558,6 +558,7 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
ThreadRoutineArgs *routine_args = NULL;
uint32 thread_handle;
uint32 stack_size = 8192;
uint32 aux_stack_start = 0, aux_stack_size;
int32 ret = -1;
bh_assert(module);
@ -609,10 +610,22 @@ pthread_create_wrapper(wasm_exec_env_t exec_env,
routine_args->info_node = info_node;
routine_args->module_inst = new_module_inst;
/* Allocate aux stack previously since exec_env->wait_lock is acquired
below, and if the stack is allocated in wasm_cluster_create_thread,
runtime may call the exported malloc function to allocate the stack,
which acquires exec_env->wait again in wasm_exec_env_set_thread_info,
and recursive lock (or hang) occurs */
if (!wasm_cluster_allocate_aux_stack(exec_env, &aux_stack_start,
&aux_stack_size)) {
LOG_ERROR("thread manager error: "
"failed to allocate aux stack space for new thread");
goto fail;
}
os_mutex_lock(&exec_env->wait_lock);
ret =
wasm_cluster_create_thread(exec_env, new_module_inst, true,
pthread_start_routine, (void *)routine_args);
ret = wasm_cluster_create_thread(
exec_env, new_module_inst, true, aux_stack_start, aux_stack_size,
pthread_start_routine, (void *)routine_args);
if (ret != 0) {
os_mutex_unlock(&exec_env->wait_lock);
goto fail;
@ -636,6 +649,8 @@ fail:
wasm_runtime_free(info_node);
if (routine_args)
wasm_runtime_free(routine_args);
if (aux_stack_start)
wasm_cluster_free_aux_stack(exec_env, aux_stack_start);
return ret;
}

View File

@ -119,7 +119,7 @@ thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg)
thread_start_arg->arg = start_arg;
thread_start_arg->start_func = start_func;
ret = wasm_cluster_create_thread(exec_env, new_module_inst, false,
ret = wasm_cluster_create_thread(exec_env, new_module_inst, false, 0, 0,
thread_start, thread_start_arg);
if (ret != 0) {
LOG_ERROR("Failed to spawn a new thread");

View File

@ -1047,7 +1047,7 @@ execute_interruptible_poll_oneoff(
if (wasm_cluster_is_thread_terminated(exec_env)) {
wasm_runtime_free(in_copy);
return EINTR;
return __WASI_EINTR;
}
else if (*nevents > 0) {
all_outs_are_type_clock = true;

View File

@ -41,7 +41,8 @@
#endif
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__EMSCRIPTEN__) \
&& !defined(ESP_PLATFORM) && !defined(DISABLE_CLOCK_NANOSLEEP)
&& !defined(ESP_PLATFORM) && !defined(DISABLE_CLOCK_NANOSLEEP) \
&& !defined(BH_PLATFORM_FREERTOS)
#define CONFIG_HAS_CLOCK_NANOSLEEP 1
#else
#define CONFIG_HAS_CLOCK_NANOSLEEP 0
@ -54,7 +55,7 @@
#endif
#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) && !defined(_WIN32) \
&& !defined(__COSMOPOLITAN__)
&& !defined(__COSMOPOLITAN__) && !defined(BH_PLATFORM_FREERTOS)
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1
#else
#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0

View File

@ -4,6 +4,7 @@
*/
#include "thread_manager.h"
#include "../common/wasm_c_api_internal.h"
#if WASM_ENABLE_INTERP != 0
#include "../interpreter/wasm_runtime.h"
@ -513,6 +514,33 @@ free_aux_stack(WASMExecEnv *exec_env, uint32 start)
#endif
}
bool
wasm_cluster_allocate_aux_stack(WASMExecEnv *exec_env, uint32 *p_start,
uint32 *p_size)
{
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
bool ret;
cluster_lock_thread_list(cluster, exec_env);
ret = allocate_aux_stack(exec_env, p_start, p_size);
cluster_unlock_thread_list(cluster);
return ret;
}
bool
wasm_cluster_free_aux_stack(WASMExecEnv *exec_env, uint32 start)
{
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
bool ret;
cluster_lock_thread_list(cluster, exec_env);
ret = free_aux_stack(exec_env, start);
cluster_unlock_thread_list(cluster);
return ret;
}
WASMCluster *
wasm_cluster_create(WASMExecEnv *exec_env)
{
@ -683,6 +711,10 @@ wasm_cluster_destroy(WASMCluster *cluster)
wasm_debug_instance_destroy(cluster);
#endif
#if WASM_ENABLE_DUMP_CALL_STACK != 0
bh_vector_destroy(&cluster->exception_frames);
#endif
wasm_runtime_free(cluster);
}
@ -969,12 +1001,13 @@ thread_manager_start_routine(void *arg)
int32
wasm_cluster_create_thread(WASMExecEnv *exec_env,
wasm_module_inst_t module_inst, bool alloc_aux_stack,
wasm_module_inst_t module_inst,
bool is_aux_stack_allocated, uint32 aux_stack_start,
uint32 aux_stack_size,
void *(*thread_routine)(void *), void *arg)
{
WASMCluster *cluster;
WASMExecEnv *new_exec_env;
uint32 aux_stack_start = 0, aux_stack_size;
korp_tid tid;
cluster = wasm_exec_env_get_cluster(exec_env);
@ -991,17 +1024,11 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env,
if (!new_exec_env)
goto fail1;
if (alloc_aux_stack) {
if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) {
LOG_ERROR("thread manager error: "
"failed to allocate aux stack space for new thread");
goto fail2;
}
if (is_aux_stack_allocated) {
/* Set aux stack for current thread */
if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start,
aux_stack_size)) {
goto fail3;
goto fail2;
}
}
else {
@ -1015,7 +1042,7 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env,
new_exec_env->suspend_flags.flags = exec_env->suspend_flags.flags;
if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
goto fail3;
goto fail2;
new_exec_env->thread_start_routine = thread_routine;
new_exec_env->thread_arg = arg;
@ -1027,7 +1054,7 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env,
(void *)new_exec_env,
APP_THREAD_STACK_SIZE_DEFAULT)) {
os_mutex_unlock(&new_exec_env->wait_lock);
goto fail4;
goto fail3;
}
/* Wait until the new_exec_env->handle is set to avoid it is
@ -1039,12 +1066,8 @@ wasm_cluster_create_thread(WASMExecEnv *exec_env,
return 0;
fail4:
wasm_cluster_del_exec_env_internal(cluster, new_exec_env, false);
fail3:
/* Free the allocated aux stack space */
if (alloc_aux_stack)
free_aux_stack(exec_env, aux_stack_start);
wasm_cluster_del_exec_env_internal(cluster, new_exec_env, false);
fail2:
wasm_exec_env_destroy_internal(new_exec_env);
fail1:
@ -1675,6 +1698,29 @@ wasm_cluster_set_exception(WASMExecEnv *exec_env, const char *exception)
data.exception = exception;
cluster_lock_thread_list(cluster, exec_env);
#if WASM_ENABLE_DUMP_CALL_STACK != 0
if (has_exception) {
/* Save the stack frames of the crashed thread into the cluster */
WASMModuleInstance *module_inst =
(WASMModuleInstance *)get_module_inst(exec_env);
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode
&& wasm_interp_create_call_stack(exec_env)) {
wasm_frame_vec_clone_internal(module_inst->frames,
&cluster->exception_frames);
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT
&& aot_create_call_stack(exec_env)) {
wasm_frame_vec_clone_internal(module_inst->frames,
&cluster->exception_frames);
}
#endif
}
#endif /* WASM_ENABLE_DUMP_CALL_STACK != 0 */
cluster->has_exception = has_exception;
traverse_list(&cluster->exec_env_list, set_exception_visitor, &data);
cluster_unlock_thread_list(cluster);

View File

@ -79,6 +79,13 @@ struct WASMCluster {
#if WASM_ENABLE_DEBUG_INTERP != 0
WASMDebugInstance *debug_inst;
#endif
#if WASM_ENABLE_DUMP_CALL_STACK != 0
/* When an exception occurs in a thread, the stack frames of that thread are
* saved into the cluster
*/
Vector exception_frames;
#endif
};
void
@ -109,7 +116,9 @@ wasm_cluster_dup_c_api_imports(WASMModuleInstanceCommon *module_inst_dst,
int32
wasm_cluster_create_thread(WASMExecEnv *exec_env,
wasm_module_inst_t module_inst, bool alloc_aux_stack,
wasm_module_inst_t module_inst,
bool is_aux_stack_allocated, uint32 aux_stack_start,
uint32 aux_stack_size,
void *(*thread_routine)(void *), void *arg);
int32
@ -246,6 +255,13 @@ wasm_cluster_traverse_lock(WASMExecEnv *exec_env);
void
wasm_cluster_traverse_unlock(WASMExecEnv *exec_env);
bool
wasm_cluster_allocate_aux_stack(WASMExecEnv *exec_env, uint32 *p_start,
uint32 *p_size);
bool
wasm_cluster_free_aux_stack(WASMExecEnv *exec_env, uint32 start);
#ifdef __cplusplus
}
#endif

View File

@ -205,7 +205,6 @@ os_thread_wrapper(void *arg)
thread_data->start_routine(thread_data->arg);
os_thread_cleanup();
vTaskDelete(NULL);
}
int
@ -301,6 +300,22 @@ os_thread_join(korp_tid thread, void **value_ptr)
return BHT_OK;
}
int
os_thread_detach(korp_tid thread)
{
/* Do nothing */
(void)thread;
return BHT_OK;
}
void
os_thread_exit(void *retval)
{
(void)retval;
os_thread_cleanup();
vTaskDelete(NULL);
}
int
os_mutex_init(korp_mutex *mutex)
{
@ -459,3 +474,33 @@ os_cond_signal(korp_cond *cond)
return BHT_OK;
}
int
os_cond_broadcast(korp_cond *cond)
{
/* Signal all of the wait node of wait list */
xSemaphoreTake(cond->wait_list_lock, portMAX_DELAY);
if (cond->thread_wait_list) {
os_thread_wait_node *p = cond->thread_wait_list;
while (p) {
xSemaphoreGive(p->sem);
p = p->next;
}
}
xSemaphoreGive(cond->wait_list_lock);
return BHT_OK;
}
uint8 *
os_thread_get_stack_boundary()
{
/* TODO: get freertos stack boundary */
return NULL;
}
void
os_thread_jit_write_protect_np(bool enabled)
{
(void)enabled;
}

View File

@ -5,7 +5,7 @@
#include "platform_api_vmcore.h"
#if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__)
#if defined(__APPLE__) || defined(__MACH__)
#include <libkern/OSCacheControl.h>
#endif
@ -40,7 +40,8 @@ void *
os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
{
int map_prot = PROT_NONE;
#if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__)
#if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__) \
&& defined(TARGET_OS_OSX) && TARGET_OS_OSX != 0
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_JIT;
#else
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
@ -77,15 +78,19 @@ os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
map_prot |= PROT_EXEC;
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#ifndef __APPLE__
if (flags & MMAP_MAP_32BIT)
map_flags |= MAP_32BIT;
#endif
#endif
if (flags & MMAP_MAP_FIXED)
map_flags |= MAP_FIXED;
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#if defined(__APPLE__)
retry_without_map_32bit:
#endif
#endif
#if defined(BUILD_TARGET_RISCV64_LP64D) || defined(BUILD_TARGET_RISCV64_LP64)
/* As AOT relocation in RISCV64 may require that the code/data mapped
* is in range 0 to 2GB, we try to map the memory with hint address
@ -143,6 +148,14 @@ os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
}
if (addr == MAP_FAILED) {
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#if defined(__APPLE__)
if ((map_flags & MAP_32BIT) != 0) {
map_flags &= ~MAP_32BIT;
goto retry_without_map_32bit;
}
#endif
#endif
#if BH_ENABLE_TRACE_MMAP != 0
os_printf("mmap failed\n");
#endif
@ -263,7 +276,7 @@ os_dcache_flush(void)
void
os_icache_flush(void *start, size_t len)
{
#if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__)
#if defined(__APPLE__) || defined(__MACH__)
sys_icache_invalidate(start, len);
#endif
}

View File

@ -487,7 +487,8 @@ os_thread_get_stack_boundary()
void
os_thread_jit_write_protect_np(bool enabled)
{
#if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__)
#if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__) \
&& defined(TARGET_OS_OSX) && TARGET_OS_OSX != 0
pthread_jit_write_protect_np(enabled);
#endif
}

View File

@ -10,6 +10,9 @@ include_directories(${PLATFORM_SHARED_DIR}/../include)
file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c)
include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake)
set (source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE})
set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE})
# If enable PSRAM of ESP32-S3, it had better to put AOT into PSRAM, so that

View File

@ -119,6 +119,18 @@ strcpy(char *dest, const char *src)
return dest;
}
#if WASM_ENABLE_LIBC_WASI == 0
bool
os_is_handle_valid(os_file_handle *handle)
{
assert(handle != NULL);
return *handle > -1;
}
#else
/* implemented in posix_file.c */
#endif
void *
os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file)
{

View File

@ -5,10 +5,11 @@
#include "platform_api_vmcore.h"
#include "platform_api_extension.h"
#include "libc_errno.h"
#ifndef SGX_DISABLE_WASI
#include "libc_errno.h"
#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__)
/** OCALLs prototypes **/

View File

@ -43,7 +43,9 @@ bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...)
"%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ":%03" PRIu32, h, m, s,
mills);
#ifndef BH_VPRINTF
os_printf("[%s - %" PRIXPTR "]: ", buf, (uintptr_t)self);
#endif
if (file)
os_printf("%s, line %d, ", file, line);

View File

@ -7,5 +7,5 @@
#define _WAMR_VERSION_H_
#define WAMR_VERSION_MAJOR 1
#define WAMR_VERSION_MINOR 3
#define WAMR_VERSION_PATCH 0
#define WAMR_VERSION_PATCH 1
#endif

View File

@ -1,7 +1,7 @@
# Build WAMR vmcore
WAMR vmcore is a set of runtime libraries for loading and running Wasm modules. This document introduces how to build the WAMR vmcore.
WAMR vmcore is a set of runtime libraries for loading and running Wasm modules. This document introduces how to build the WAMR vmcore.
References:
- [how to build iwasm](../product-mini/README.md): building different target platforms such as Linux, Windows, Mac etc
@ -130,7 +130,7 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
> Note: if it is enabled, the call stack will be dumped when exception occurs.
> - For interpreter mode, the function names are firstly extracted from *custom name section*, if this section doesn't exist or the feature is not enabled, then the name will be extracted from the import/export sections
> - For AOT/JIT mode, the function names are extracted from import/export section, please export as many functions as possible (for `wasi-sdk` you can use `-Wl,--export-all`) when compiling wasm module, and add `--enable-dump-call-stack` option to wamrc during compiling AOT module.
> - For AOT/JIT mode, the function names are extracted from import/export section, please export as many functions as possible (for `wasi-sdk` you can use `-Wl,--export-all`) when compiling wasm module, and add `--enable-dump-call-stack --emit-custom-sections=name` option to wamrc during compiling AOT module.
#### **Enable memory profiling (Experiment)**
- **WAMR_BUILD_MEMORY_PROFILING**=1/0, default to disable if not set
@ -201,7 +201,7 @@ Currently we only profile the memory consumption of module, module_instance and
> Note: If `WAMR_BUILD_CUSTOM_NAME_SECTION` is enabled, then the `custom name section` will be treated as a special section and consumed by the runtime, not available to the embedder.
> For AoT file, must use `--emit-custom-sections` to specify which sections need to be emitted into AoT file, otherwise all custom sections (except custom name section) will be ignored.
> For AoT file, must use `--emit-custom-sections` to specify which sections need to be emitted into AoT file, otherwise all custom sections will be ignored.
### **Stack guard size**
- **WAMR_BUILD_STACK_GUARD_SIZE**=n, default to N/A if not set.

View File

@ -372,6 +372,20 @@ Examples: wamrc -o test.aot test.wasm
wamrc --target=i386 --format=object -o test.o test.wasm
```
## AoT-compiled module compatibility among WAMR versions
When making major ABI changes for AoT-compiled modules, we bump
`AOT_CURRENT_VERSION` constant in `core/config.h` header.
The runtime rejects to load a module AoT-compiled with wamrc with
a different `AOT_CURRENT_VERSION`.
We try our best to maintain our runtime ABI for AoT-compiled modules
compatible among WAMR versions with the same `AOT_CURRENT_VERSION`
so that combinations of older wamrc and newer runtime usually work.
However, there might be minor incompatibilities time to time.
For productions, we recommend to use the exactly same version of
wamrc and the runtime.
## AoT compilation with 3rd-party toolchains
`wamrc` uses LLVM to compile wasm bytecode to AoT file, this works for most of the architectures, but there may be circumstances where you want to use 3rd-party toolchains to take over some steps of the compilation pipeline, e.g.

View File

@ -134,7 +134,7 @@ $ perf report --input=perf.data
>
> For example, with EMCC, you can add `-g2`.
>
> If not able to get the context of the custom name section, WAMR will use `aot_func#N` to represent the function name. `N` is from 0. `aot_func#0` represents the first *not imported wasm function*.
> If not able to get the context of the custom name section, WAMR will use `aot_func#N` to represent the function name. `N` is from 0. `aot_func#0` represents the first _not imported wasm function_.
### 7.1 Flamegraph
@ -177,3 +177,16 @@ $ ./FlameGraph/flamegraph.pl out.folded > perf.foo.wasm.svg
> # only jitted functions
> $ grep "wasm_runtime_invoke_native" out.folded | ./FlameGraph/flamegraph.pl > perf.foo.wasm.only.svg
> ```
> [!TIP]
> use [trans_wasm_func_name.py](../test-tools/trans-jitted-func-name/trans_wasm_func_name.py) to translate jitted function
> names to its original wasm function names. It requires _wasm-objdump_ in _wabt_ and _name section_ in the .wasm file
>
> The input file is the output of `./FlameGraph/stackcollapse-perf.pl`.
>
> ```bash
> python trans_wasm_func_name.py --wabt_home <wabt-installation> --folded out.folded <.wasm>
> ```
>
> Then you will see a new file named _out.folded.translated_ which contains the translated folded stacks.
> All wasm functions are translated to its original names with a prefix like "[Wasm]"

View File

@ -1,13 +1,5 @@
# WAMR source debugging
References:
- [Blog: WAMR source debugging basic](https://bytecodealliance.github.io/wamr.dev/blog/wamr-source-debugging-basic/)
- [Blog: Debugging wasm with VSCode](https://bytecodealliance.github.io/wamr.dev/blog/debugging-wasm-with-vscode/)
WAMR supports source level debugging based on DWARF (normally used in C/C++/Rust), source map (normally used in AssemblyScript) is not supported.
**The lldb's ability to debug wasm application is based on the patch [Add class WasmProcess for WebAssembly debugging](https://reviews.llvm.org/D78801). Thanks very much to the author @paolosev for such a great work!**
## Build wasm application with debug information
To debug your application, you need to compile them with debug information. You can use `-g` option when compiling the source code if you are using wasi-sdk (also work for emcc and rustc):
``` bash
@ -20,205 +12,9 @@ llvm-dwarfdump-12 test.wasm
```
## Debugging with interpreter
1. Install dependent libraries
``` bash
apt update && apt install cmake make g++ libxml2-dev -y
```
2. Build iwasm with source debugging feature
``` bash
cd ${WAMR_ROOT}/product-mini/platforms/linux
mkdir build && cd build
cmake .. -DWAMR_BUILD_DEBUG_INTERP=1
make
```
> Note: On MacOS M1 environment, pass the additional `-DWAMR_DISABLE_HW_BOUND_CHECK=1` cmake configuration.
3. Execute iwasm with debug engine enabled
``` bash
iwasm -g=127.0.0.1:1234 test.wasm
# Use port = 0 to allow a random assigned debug port
```
4. Build customized lldb
``` bash
git clone --branch release/13.x --depth=1 https://github.com/llvm/llvm-project
cd llvm-project
git apply ${WAMR_ROOT}/build-scripts/lldb_wasm.patch
mkdir build-lldb
cmake -S ./llvm -B build-lldb \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;lldb" \
-DLLVM_TARGETS_TO_BUILD:STRING="X86;WebAssembly" \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DLLVM_BUILD_BENCHMARKS:BOOL=OFF \
-DLLVM_BUILD_DOCS:BOOL=OFF -DLLVM_BUILD_EXAMPLES:BOOL=OFF \
-DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF -DLLVM_BUILD_TESTS:BOOL=OFF \
-DLLVM_ENABLE_BINDINGS:BOOL=OFF -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \
-DLLVM_INCLUDE_DOCS:BOOL=OFF -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \
-DLLVM_INCLUDE_TESTS:BOOL=OFF -DLLVM_ENABLE_LIBXML2:BOOL=ON
cmake --build build-lldb --target lldb --parallel $(nproc)
# The lldb is generated under build-lldb/bin/lldb
```
> Note: If using `CommandLineTools` on MacOS, make sure only one SDK is present in `/Library/Developer/CommandLineTools/SDKs`.
> You can download pre-built `wamr-lldb` binaries from [here](https://github.com/bytecodealliance/wasm-micro-runtime/releases).
5. Launch customized lldb and connect to iwasm
``` bash
lldb
(lldb) process connect -p wasm connect://127.0.0.1:1234
```
Then you can use lldb commands to debug your applications. Please refer to [lldb document](https://lldb.llvm.org/use/tutorial.html) for command usage.
See [Debuggging with interpreter](source_debugging_interpreter.md).
## Debugging with AOT
> Note: AOT debugging is experimental and only a few debugging capabilities are supported.
1. Build lldb (assume you have already built llvm)
``` bash
cd ${WAMR_ROOT}/core/deps/llvm/build
cmake ../llvm -DLLVM_ENABLE_PROJECTS="clang;lldb" -DLLDB_INCLUDE_TESTS=OFF
make -j $(nproc)
```
2. Build wamrc with debugging feature
``` bash
cd ${WAMR_ROOT}/wamr-compiler
mkdir build && cd build
cmake .. -DWAMR_BUILD_DEBUG_AOT=1
make -j $(nproc)
```
3. Build iwasm with debugging feature
``` bash
cd ${WAMR_ROOT}/product-mini/platforms/linux
mkdir build && cd build
cmake .. -DWAMR_BUILD_DEBUG_AOT=1
make
```
4. Compile wasm module to AOT module
``` bash
wamrc -o test.aot test.wasm
```
5. Execute iwasm using lldb
Then you can use lldb commands to debug both wamr runtime and your wasm application in ***current terminal***.
``` bash
% lldb iwasm -- test.aot
(lldb) target create "iwasm"
Current executable set to 'iwasm' (x86_64).
(lldb) settings set -- target.run-args "test.aot"
(lldb) settings set plugin.jit-loader.gdb.enable on
(lldb) b main
Breakpoint 1: where = iwasm`main + 48 at main.c:294:11, address = 0x0000000100001020
(lldb) run
Process 27954 launched: '/tmp/bin/iwasm' (x86_64)
Process 27954 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100001020 iwasm`main(argc=2, argv=0x00007ff7bfeff678) at main.c:294:11
291 int
292 main(int argc, char *argv[])
293 {
-> 294 int32 ret = -1;
295 char *wasm_file = NULL;
296 const char *func_name = NULL;
297 uint8 *wasm_file_buf = NULL;
Target 0: (iwasm) stopped.
(lldb) c
Process 27954 resuming
1 location added to breakpoint 1
error: need to add support for DW_TAG_base_type 'void' encoded with DW_ATE = 0x0, bit_size = 0
Process 27954 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
frame #0: 0x00000001002980a0 JIT(0x100298004)`main(exenv=0x0000000301808200) at hello.c:6:9
3 int
4 main(void)
5 {
-> 6 printf("hello\n");
7
8 return 0;
9 }
Target 0: (iwasm) stopped.
(lldb) br l
Current breakpoints:
1: name = 'main', locations = 2, resolved = 2, hit count = 2
1.1: where = iwasm`main + 48 at main.c:294:11, address = 0x0000000100001020, resolved, hit count = 1
1.2: where = JIT(0x100298004)`main + 12 at hello.c:6:9, address = 0x00000001002980a0, resolved, hit count = 1
(lldb)
```
* In the above example,
* The first `main` function, which is in `main.c`, is the main
function of the iwasm command.
* The second `main` function, which is in `hello.c`, is the main
function of the AOT-compiled wasm module.
* WAMR AOT debugging uses the GDB JIT loader mechanism to load
the debug info of the debugee module.
On some platforms including macOS, you need to enable it explicitly.
(`settings set plugin.jit-loader.gdb.enable on`)
References:
* https://github.com/llvm/llvm-project/blob/main/llvm/docs/DebuggingJITedCode.rst
* https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html
## Enable debugging in embedders (for interpreter)
There are three steps to enable debugging in embedders
1. Set the debug parameters when initializing the runtime environment:
``` c
RuntimeInitArgs init_args;
memset(&init_args, 0, sizeof(RuntimeInitArgs));
/* ... */
strcpy(init_args.ip_addr, "127.0.0.1");
init_args.instance_port = 1234;
/*
* Or set port to 0 to use a port assigned by os
* init_args.instance_port = 0;
*/
if (!wasm_runtime_full_init(&init_args)) {
return false;
}
```
2. Use `wasm_runtime_start_debug_instance` to create the debug instance:
``` c
/*
initialization, loading and instantiating
...
*/
exec_env = wasm_runtime_create_exec_env(module_inst, stack_size);
uint32_t debug_port = wasm_runtime_start_debug_instance(exec_env);
```
3. Enable source debugging features during building
You can use `-DWAMR_BUILD_DEBUG_INTERP=1` during cmake configuration
Or you can set it directly in `cmake` files:
``` cmake
set (WAMR_BUILD_DEBUG_INTERP 1)
```
### Attentions
- Debugging `multi-thread wasm module` is not supported, if your wasm module use pthread APIs (see [pthread_library.md](./pthread_library.md)), or the embedder use `wasm_runtime_spawn_thread` to create new wasm threads, then there may be **unexpected behaviour** during debugging.
> Note: This attention is about "wasm thread" rather than native threads. Executing wasm functions in several different native threads will **not** affect the normal behaviour of debugging feature.
- When using source debugging features, **don't** create multiple `wasm_instance` from the same `wasm_module`, because the debugger may change the bytecode (set/unset breakpoints) of the `wasm_module`. If you do need several instance from the same bytecode, you need to copy the bytecode to a new butter, then load a new `wasm_module`, and then instantiate the new wasm module to get the new instance.
- If you are running `lldb` on non-linux platforms, please use `platform select remote-linux` command in lldb before connecting to the runtime:
```
(lldb) platform select remote-linux
(lldb) process connect -p wasm connect://127.0.0.1:1234
```
See [Debuggging with AOT](source_debugging_aot.md).

100
doc/source_debugging_aot.md Normal file
View File

@ -0,0 +1,100 @@
# WAMR source debugging (AOT)
## Debugging with AOT
> Note: AOT debugging is experimental and only a few debugging capabilities are supported.
1. Build lldb (assume you have already built llvm)
``` bash
cd ${WAMR_ROOT}/core/deps/llvm/build
cmake ../llvm -DLLVM_ENABLE_PROJECTS="clang;lldb" -DLLDB_INCLUDE_TESTS=OFF
make -j $(nproc)
```
2. Build wamrc with debugging feature
``` bash
cd ${WAMR_ROOT}/wamr-compiler
mkdir build && cd build
cmake .. -DWAMR_BUILD_DEBUG_AOT=1
make -j $(nproc)
```
3. Build iwasm with debugging feature
``` bash
cd ${WAMR_ROOT}/product-mini/platforms/linux
mkdir build && cd build
cmake .. -DWAMR_BUILD_DEBUG_AOT=1
make
```
4. Compile wasm module to AOT module
``` bash
wamrc -o test.aot test.wasm
```
5. Execute iwasm using lldb
Then you can use lldb commands to debug both wamr runtime and your wasm application in ***current terminal***.
``` bash
% lldb iwasm -- test.aot
(lldb) target create "iwasm"
Current executable set to 'iwasm' (x86_64).
(lldb) settings set -- target.run-args "test.aot"
(lldb) settings set plugin.jit-loader.gdb.enable on
(lldb) b main
Breakpoint 1: where = iwasm`main + 48 at main.c:294:11, address = 0x0000000100001020
(lldb) run
Process 27954 launched: '/tmp/bin/iwasm' (x86_64)
Process 27954 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100001020 iwasm`main(argc=2, argv=0x00007ff7bfeff678) at main.c:294:11
291 int
292 main(int argc, char *argv[])
293 {
-> 294 int32 ret = -1;
295 char *wasm_file = NULL;
296 const char *func_name = NULL;
297 uint8 *wasm_file_buf = NULL;
Target 0: (iwasm) stopped.
(lldb) c
Process 27954 resuming
1 location added to breakpoint 1
error: need to add support for DW_TAG_base_type 'void' encoded with DW_ATE = 0x0, bit_size = 0
Process 27954 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
frame #0: 0x00000001002980a0 JIT(0x100298004)`main(exenv=0x0000000301808200) at hello.c:6:9
3 int
4 main(void)
5 {
-> 6 printf("hello\n");
7
8 return 0;
9 }
Target 0: (iwasm) stopped.
(lldb) br l
Current breakpoints:
1: name = 'main', locations = 2, resolved = 2, hit count = 2
1.1: where = iwasm`main + 48 at main.c:294:11, address = 0x0000000100001020, resolved, hit count = 1
1.2: where = JIT(0x100298004)`main + 12 at hello.c:6:9, address = 0x00000001002980a0, resolved, hit count = 1
(lldb)
```
* In the above example,
* The first `main` function, which is in `main.c`, is the main
function of the iwasm command.
* The second `main` function, which is in `hello.c`, is the main
function of the AOT-compiled wasm module.
* WAMR AOT debugging uses the GDB JIT loader mechanism to load
the debug info of the debugee module.
On some platforms including macOS, you need to enable it explicitly.
(`settings set plugin.jit-loader.gdb.enable on`)
References:
* https://github.com/llvm/llvm-project/blob/main/llvm/docs/DebuggingJITedCode.rst
* https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html

View File

@ -0,0 +1,115 @@
# WAMR source debugging (interpreter)
References:
- [Blog: WAMR source debugging basic](https://bytecodealliance.github.io/wamr.dev/blog/wamr-source-debugging-basic/)
- [Blog: Debugging wasm with VSCode](https://bytecodealliance.github.io/wamr.dev/blog/debugging-wasm-with-vscode/)
WAMR supports source level debugging based on DWARF (normally used in C/C++/Rust), source map (normally used in AssemblyScript) is not supported.
**The lldb's ability to debug wasm application is based on the patch [Add class WasmProcess for WebAssembly debugging](https://reviews.llvm.org/D78801). Thanks very much to the author @paolosev for such a great work!**
## Debugging with interpreter
1. Install dependent libraries
``` bash
apt update && apt install cmake make g++ libxml2-dev -y
```
2. Build iwasm with source debugging feature
``` bash
cd ${WAMR_ROOT}/product-mini/platforms/linux
mkdir build && cd build
cmake .. -DWAMR_BUILD_DEBUG_INTERP=1
make
```
> Note: On MacOS M1 environment, pass the additional `-DWAMR_DISABLE_HW_BOUND_CHECK=1` cmake configuration.
3. Execute iwasm with debug engine enabled
``` bash
iwasm -g=127.0.0.1:1234 test.wasm
# Use port = 0 to allow a random assigned debug port
```
4. Build customized lldb
``` bash
git clone --branch release/13.x --depth=1 https://github.com/llvm/llvm-project
cd llvm-project
git apply ${WAMR_ROOT}/build-scripts/lldb_wasm.patch
mkdir build-lldb
cmake -S ./llvm -B build-lldb \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;lldb" \
-DLLVM_TARGETS_TO_BUILD:STRING="X86;WebAssembly" \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DLLVM_BUILD_BENCHMARKS:BOOL=OFF \
-DLLVM_BUILD_DOCS:BOOL=OFF -DLLVM_BUILD_EXAMPLES:BOOL=OFF \
-DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF -DLLVM_BUILD_TESTS:BOOL=OFF \
-DLLVM_ENABLE_BINDINGS:BOOL=OFF -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \
-DLLVM_INCLUDE_DOCS:BOOL=OFF -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \
-DLLVM_INCLUDE_TESTS:BOOL=OFF -DLLVM_ENABLE_LIBXML2:BOOL=ON
cmake --build build-lldb --target lldb --parallel $(nproc)
# The lldb is generated under build-lldb/bin/lldb
```
> Note: If using `CommandLineTools` on MacOS, make sure only one SDK is present in `/Library/Developer/CommandLineTools/SDKs`.
> You can download pre-built `wamr-lldb` binaries from [here](https://github.com/bytecodealliance/wasm-micro-runtime/releases).
5. Launch customized lldb and connect to iwasm
``` bash
lldb
(lldb) process connect -p wasm connect://127.0.0.1:1234
```
Then you can use lldb commands to debug your applications. Please refer to [lldb document](https://lldb.llvm.org/use/tutorial.html) for command usage.
## Enable debugging in embedders (for interpreter)
There are three steps to enable debugging in embedders
1. Set the debug parameters when initializing the runtime environment:
``` c
RuntimeInitArgs init_args;
memset(&init_args, 0, sizeof(RuntimeInitArgs));
/* ... */
strcpy(init_args.ip_addr, "127.0.0.1");
init_args.instance_port = 1234;
/*
* Or set port to 0 to use a port assigned by os
* init_args.instance_port = 0;
*/
if (!wasm_runtime_full_init(&init_args)) {
return false;
}
```
2. Use `wasm_runtime_start_debug_instance` to create the debug instance:
``` c
/*
initialization, loading and instantiating
...
*/
exec_env = wasm_runtime_create_exec_env(module_inst, stack_size);
uint32_t debug_port = wasm_runtime_start_debug_instance(exec_env);
```
3. Enable source debugging features during building
You can use `-DWAMR_BUILD_DEBUG_INTERP=1` during cmake configuration
Or you can set it directly in `cmake` files:
``` cmake
set (WAMR_BUILD_DEBUG_INTERP 1)
```
### Attentions
- Debugging `multi-thread wasm module` is not supported, if your wasm module use pthread APIs (see [pthread_library.md](./pthread_library.md)), or the embedder use `wasm_runtime_spawn_thread` to create new wasm threads, then there may be **unexpected behaviour** during debugging.
> Note: This attention is about "wasm thread" rather than native threads. Executing wasm functions in several different native threads will **not** affect the normal behaviour of debugging feature.
- When using source debugging features, **don't** create multiple `wasm_instance` from the same `wasm_module`, because the debugger may change the bytecode (set/unset breakpoints) of the `wasm_module`. If you do need several instance from the same bytecode, you need to copy the bytecode to a new butter, then load a new `wasm_module`, and then instantiate the new wasm module to get the new instance.
- If you are running `lldb` on non-linux platforms, please use `platform select remote-linux` command in lldb before connecting to the runtime:
```
(lldb) platform select remote-linux
(lldb) process connect -p wasm connect://127.0.0.1:1234
```

View File

@ -164,3 +164,15 @@ else()
OUTPUT_VARIABLE cmdOutput
)
endif()
if (WAMR_BUILD_LIBC_WASI EQUAL 1)
execute_process(
COMMAND bash -c "sed -i -E 's/^WAMR_BUILD_LIBC_WASI = 0/WAMR_BUILD_LIBC_WASI = 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile"
OUTPUT_VARIABLE cmdOutput
)
else()
execute_process(
COMMAND bash -c "sed -i -E 's/^WAMR_BUILD_LIBC_WASI = 1/WAMR_BUILD_LIBC_WASI = 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile"
OUTPUT_VARIABLE cmdOutput
)
endif()

View File

@ -510,7 +510,7 @@ handle_cmd_set_log_level(uint64 *args, uint32 argc)
#endif
}
#ifndef SGX_DISABLE_WASI
#if WASM_ENABLE_LIBC_WASI != 0
static void
handle_cmd_set_wasi_args(uint64 *args, int32 argc)
{
@ -637,7 +637,7 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
{
*args = true;
}
#endif /* end of SGX_DISABLE_WASI */
#endif /* end of WASM_ENABLE_LIBC_WASI != 0 */
static void
handle_cmd_get_version(uint64 *args, uint32 argc)

View File

@ -16,6 +16,7 @@ WAMR_BUILD_LIB_RATS = 0
WAMR_BUILD_GLOBAL_HEAP_POOL = 0
WAMR_BUILD_GLOBAL_HEAP_SIZE = 10485760
WAMR_BUILD_STATIC_PGO = 0
WAMR_BUILD_LIBC_WASI = 1
VMLIB_BUILD_DIR ?= $(CURDIR)/../build
LIB_RATS_SRC ?= $(VMLIB_BUILD_DIR)/_deps/librats-build
@ -66,7 +67,9 @@ ifeq ($(WAMR_BUILD_LIB_RATS), 1)
App_Include_Paths += -I$(LIB_RATS_INCLUDE_DIR)
endif
App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) -DWASM_ENABLE_STATIC_PGO=$(WAMR_BUILD_STATIC_PGO)
App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) \
-DWASM_ENABLE_STATIC_PGO=$(WAMR_BUILD_STATIC_PGO) \
-DWASM_ENABLE_LIBC_WASI=$(WAMR_BUILD_LIBC_WASI)
# Three configuration modes - Debug, prerelease, release
# Debug - Macro DEBUG enabled.
@ -135,7 +138,13 @@ ifeq ($(WAMR_BUILD_LIB_RATS), 1)
Enclave_Include_Paths += -I$(LIB_RATS_INCLUDE_DIR) -I$(SGX_SSL)/include
endif
Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) -DWASM_GLOBAL_HEAP_SIZE=$(WAMR_BUILD_GLOBAL_HEAP_SIZE) -DWASM_ENABLE_GLOBAL_HEAP_POOL=$(WAMR_BUILD_GLOBAL_HEAP_POOL) -DWASM_ENABLE_LIB_RATS=$(WAMR_BUILD_LIB_RATS) -DWASM_ENABLE_STATIC_PGO=$(WAMR_BUILD_STATIC_PGO)
Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden \
-fpie -fstack-protector $(Enclave_Include_Paths) \
-DWASM_GLOBAL_HEAP_SIZE=$(WAMR_BUILD_GLOBAL_HEAP_SIZE) \
-DWASM_ENABLE_GLOBAL_HEAP_POOL=$(WAMR_BUILD_GLOBAL_HEAP_POOL) \
-DWASM_ENABLE_LIB_RATS=$(WAMR_BUILD_LIB_RATS) \
-DWASM_ENABLE_STATIC_PGO=$(WAMR_BUILD_STATIC_PGO) \
-DWASM_ENABLE_LIBC_WASI=$(WAMR_BUILD_LIBC_WASI)
ifeq ($(SPEC_TEST), 1)
Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=1
else

View File

@ -102,7 +102,7 @@ Enclave_Include_Paths := -IEnclave -I$(WAMR_ROOT)/core/iwasm/include \
Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths)
# disable wasi
Enclave_C_Flags += -DSGX_DISABLE_WASI
Enclave_C_Flags += -DWASM_ENABLE_LIBC_WASI=0
ifeq ($(SPEC_TEST), 1)
Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=1

View File

@ -133,6 +133,11 @@ CSRCS += aot_loader.c \
$(AOT_RELOC) \
aot_intrinsic.c \
aot_runtime.c
ifeq ($(CONFIG_INTERPRETERS_WAMR_DEBUG_AOT),y)
CFLAGS += -DWASM_ENABLE_DEBUG_AOT=1
CSRCS += elf_parser.c \
jit_debug.c
endif
else
CFLAGS += -DWASM_ENABLE_AOT=0
endif
@ -412,3 +417,4 @@ VPATH += $(IWASM_ROOT)/libraries/lib-pthread
VPATH += $(IWASM_ROOT)/common/arch
VPATH += $(IWASM_ROOT)/aot
VPATH += $(IWASM_ROOT)/aot/arch
VPATH += $(IWASM_ROOT)/aot/debug

View File

@ -58,7 +58,6 @@ print_help()
#if WASM_ENABLE_JIT != 0
printf(" --llvm-jit-size-level=n Set LLVM JIT size level, default is 3\n");
printf(" --llvm-jit-opt-level=n Set LLVM JIT optimization level, default is 3\n");
printf(" --perf-profile Enable linux perf support. For now, it only works in llvm-jit.\n");
#if defined(os_writegsbase)
printf(" --enable-segue[=<flags>] Enable using segment register GS as the base address of\n");
printf(" linear memory, which may improve performance, flags can be:\n");
@ -67,6 +66,9 @@ print_help()
printf(" Use comma to separate, e.g. --enable-segue=i32.load,i64.store\n");
printf(" and --enable-segue means all flags are added.\n");
#endif
#endif /* WASM_ENABLE_JIT != 0*/
#if WASM_ENABLE_LINUX_PERF != 0
printf(" --enable-linux-perf Enable linux perf support. It works in aot and llvm-jit.\n");
#endif
printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n"
" that runs commands in the form of \"FUNC ARG...\"\n");
@ -561,7 +563,9 @@ main(int argc, char *argv[])
uint32 llvm_jit_size_level = 3;
uint32 llvm_jit_opt_level = 3;
uint32 segue_flags = 0;
bool enable_linux_perf_support = false;
#endif
#if WASM_ENABLE_LINUX_PERF != 0
bool enable_linux_perf = false;
#endif
wasm_module_t wasm_module = NULL;
wasm_module_inst_t wasm_module_inst = NULL;
@ -702,9 +706,6 @@ main(int argc, char *argv[])
if (segue_flags == (uint32)-1)
return print_help();
}
else if (!strncmp(argv[0], "--perf-profile", 14)) {
enable_linux_perf_support = true;
}
#endif /* end of WASM_ENABLE_JIT != 0 */
#if BH_HAS_DLFCN
else if (!strncmp(argv[0], "--native-lib=", 13)) {
@ -718,6 +719,11 @@ main(int argc, char *argv[])
native_lib_list[native_lib_count++] = argv[0] + 13;
}
#endif
#if WASM_ENABLE_LINUX_PERF != 0
else if (!strncmp(argv[0], "--enable-linux-perf", 19)) {
enable_linux_perf = true;
}
#endif
#if WASM_ENABLE_MULTI_MODULE != 0
else if (!strncmp(argv[0],
"--module-path=", strlen("--module-path="))) {
@ -761,7 +767,7 @@ main(int argc, char *argv[])
gen_prof_file = argv[0] + 16;
}
#endif
else if (!strncmp(argv[0], "--version", 9)) {
else if (!strcmp(argv[0], "--version")) {
uint32 major, minor, patch;
wasm_runtime_get_version(&major, &minor, &patch);
printf("iwasm %" PRIu32 ".%" PRIu32 ".%" PRIu32 "\n", major, minor,
@ -819,7 +825,9 @@ main(int argc, char *argv[])
init_args.llvm_jit_size_level = llvm_jit_size_level;
init_args.llvm_jit_opt_level = llvm_jit_opt_level;
init_args.segue_flags = segue_flags;
init_args.linux_perf_support = enable_linux_perf_support;
#endif
#if WASM_ENABLE_LINUX_PERF != 0
init_args.enable_linux_perf = enable_linux_perf;
#endif
#if WASM_ENABLE_DEBUG_INTERP != 0

View File

@ -406,7 +406,7 @@ main(int argc, char *argv[])
ip_addr = argv[0] + 3;
}
#endif
else if (!strncmp(argv[0], "--version", 9)) {
else if (!strcmp(argv[0], "--version")) {
uint32 major, minor, patch;
wasm_runtime_get_version(&major, &minor, &patch);
printf("iwasm %" PRIu32 ".%" PRIu32 ".%" PRIu32 "\n", major, minor,

View File

@ -69,6 +69,7 @@ execute_process (
add_custom_target (
iwasm ALL
DEPENDS vmlib_untrusted vmlib_untrusted vmlib
COMMAND make -C ${SGX_PLATFORM_DIR}/enclave-sample clean
COMMAND make -C ${SGX_PLATFORM_DIR}/enclave-sample SGX_MODE=HW SGX_DEBUG=1 VMLIB_BUILD_DIR=${CMAKE_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${SGX_PLATFORM_DIR}/enclave-sample/enclave.signed.so ${CMAKE_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${SGX_PLATFORM_DIR}/enclave-sample/iwasm ${CMAKE_BINARY_DIR}

View File

@ -31,7 +31,7 @@ target_link_options(send_recv PRIVATE
if(WASM_TO_AOT)
# wasm -> aot
add_custom_target(send_recv_aot ALL
COMMAND pwd && ${WAMRC_PATH} --enable-multi-thread -o ./send_recv.aot ./send_recv.wasm
COMMAND pwd && ${WAMRC_PATH} --invoke-c-api-import --enable-multi-thread -o ./send_recv.aot ./send_recv.wasm
DEPENDS send_recv
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)

View File

@ -0,0 +1,161 @@
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
"""
It is used to append a .aot to a .wasm as a custom section.
The custom section name is "aot".
e.g.
$ python3 append_aot_to_wasm.py --wasm quicksort.wasm --aot quicksort.aot --output quicksort.aot.wasm
"""
import argparse
from pathlib import Path
def leb128_encode_uint(value: int) -> bytes:
"""
encode unsigned int into a leb128 bytes
"""
binary = []
while value != 0:
lower_7_bits = value & 0x7F
value >>= 7
if value != 0:
current_byte = 0x80 | lower_7_bits
else:
current_byte = 0x00 | lower_7_bits
binary.append(current_byte)
return bytes(binary)
def leb128_decode_uint(binary: bytes) -> (int, int):
"""
decode binary unsigned from a leb128 bytes
"""
result = 0
shift = 0
for i, b in enumerate(binary):
lower_7_bits = b & 0x7F
result |= lower_7_bits << shift
highest_bit = b & 0x80
if not highest_bit:
break
shift += 7
return i + 1, result
def is_aligned(n: int, alignment: int):
return (n & (alignment - 1)) == 0
def align_up(n: int, alignment: int):
return n + (alignment - 1) & ~(alignment - 1)
def present_as_vector(content: bytes) -> bytes:
v_l = len(content)
v_bin = leb128_encode_uint(v_l) if v_l else b"\x00"
return v_bin + content
def calc_padding(
alignment: int, name_bin_len: int, content_len: int, start_pos: int
) -> bytes:
for padding in range(alignment * 2):
padding_bin = present_as_vector(b"\x00" * padding)
section_length = name_bin_len + len(padding_bin) + content_len
section_length_bin = leb128_encode_uint(section_length)
pos = start_pos + 1 + len(section_length_bin) + name_bin_len + len(padding_bin)
if is_aligned(pos, alignment):
return padding_bin
def build_content(content: bytes, pos: int, adding: bytes) -> (int, bytes):
return pos + len(adding), content + adding
def create_custom_section_aligned(
start_pos: int, name: str, content: bytes, alignment: int = 4
) -> bytes:
"""
be sure the section_content starts at a X alignment position
1B
| \x00 | length | name vec | padding vec | content |
^ ^
| |
start address aligned address
"""
name_bin = present_as_vector(name.encode("ascii"))
padding_bin = calc_padding(alignment, len(name_bin), len(content), start_pos)
full_content_bin = b""
pos = start_pos
# custome section id 0
pos, full_content_bin = build_content(full_content_bin, pos, b"\x00")
# custom section length
section_length = len(name_bin) + len(padding_bin) + len(content)
section_length_bin = leb128_encode_uint(section_length)
pos, full_content_bin = build_content(full_content_bin, pos, section_length_bin)
# custom section name
pos, full_content_bin = build_content(full_content_bin, pos, name_bin)
# padding
pos, full_content_bin = build_content(full_content_bin, pos, padding_bin)
assert is_aligned(pos, alignment), f"{pos} is not aligned to {alignment}"
print(f"append .aot @ offset {pos}(0x{pos:X})")
_, full_content_bin = build_content(full_content_bin, pos, content)
return full_content_bin
def main(wasm_file: str, aot_file: str, output: str) -> None:
cwd = Path.cwd()
wasm_file = cwd.joinpath(wasm_file).resolve()
aot_file = cwd.joinpath(aot_file).resolve()
output = cwd.joinpath(output).resolve()
assert wasm_file.exists()
assert aot_file.exists()
output.unlink(missing_ok=True)
# read aot content
with open(aot_file, "rb") as f:
aot_content = f.read()
# append to .wasm
with open(wasm_file, "rb") as f_in, open(output, "wb") as f_out:
wasm_content = f_in.read(1024)
while wasm_content:
f_out.write(wasm_content)
wasm_content = f_in.read(1024)
f_out.write(create_custom_section_aligned(f_out.tell(), "aot", aot_content, 4))
print(f"{wasm_file.name} + {aot_file.name} ==> {output}")
if __name__ == "__main__":
argparse = argparse.ArgumentParser()
argparse.add_argument("--wasm", help="a .wasm")
argparse.add_argument("--aot", help="a .aot")
argparse.add_argument("-o", "--output", help="the output, still be a .wasm")
args = argparse.parse_args()
main(args.wasm, args.aot, args.output)

View File

@ -0,0 +1,210 @@
#!/usr/bin/env python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
"""
It is used to translate jitted functions' names(in out.folded) to coorespond name in name section in .wasm
Usage:
After
```
$ perf script -i perf.data > out.perf
# fold call stacks
$ ./FlameGraph/stackcollapse-perf.pl out.perf > out.folded
```
Add a step:
```
# translate jitted functions' names
$ python translate_wasm_function_name.py --wabt_home <wabt-installation> --folded out.folded <.wasm>
# out.folded -> out.folded.translated
$ ls out.folded.translated
```
Then
```
# generate flamegraph
$ ./FlameGraph/flamegraph.pl out.folded.translated > perf.wasm.svg
```
"""
import argparse
import os
from pathlib import Path
import re
import shlex
import subprocess
def preflight_check(wabt_home: Path) -> Path:
"""
if wasm-objdump exists in wabt_home
"""
wasm_objdump_bin = wabt_home.joinpath("bin", "wasm-objdump")
if not wasm_objdump_bin.exists():
raise RuntimeError(f"wasm-objdump not found in {wabt_home}")
return wasm_objdump_bin
def collect_import_section_content(wasm_objdump_bin: Path, wasm_file: Path) -> dict:
"""
execute "wasm_objdump_bin -j Import -x <wasm_file>" and return a dict like {function: X, global: Y, memory: Z, table: N}
"""
assert wasm_objdump_bin.exists()
assert wasm_file.exists()
command = f"{wasm_objdump_bin} -j Import -x {wasm_file}"
p = subprocess.run(
shlex.split(command),
capture_output=True,
check=False,
text=True,
universal_newlines=True,
)
if p.stderr:
return {}
import_section = {}
for line in p.stdout.split(os.linesep):
line = line.strip()
if not line:
continue
if line.startswith(" - func"):
import_section.update("function", import_section.get("function", 0) + 1)
else:
pass
return import_section
def collect_name_section_content(wasm_objdump_bin: Path, wasm_file: Path) -> dict:
"""
execute "wasm_objdump_bin -j name -x wasm_file" and store the output in a list
"""
assert wasm_objdump_bin.exists()
assert wasm_file.exists()
command = f"{wasm_objdump_bin} -j name -x {wasm_file}"
p = subprocess.run(
shlex.split(command),
capture_output=True,
check=False,
text=True,
universal_newlines=True,
)
if p.stderr:
raise RuntimeError(f"not found name section in {wasm_file}")
name_section = {}
for line in p.stdout.split(os.linesep):
line = line.strip()
if not line:
continue
# - func[0] <__imported_wasi_snapshot_preview1_fd_close>
if line.startswith("- func"):
m = re.match(r"- func\[(\d+)\] <(.+)>", line)
assert m
func_index, func_name = m.groups()
name_section.update({func_index: func_name})
assert name_section
return name_section
def replace_function_name(
import_section: dict, name_section: dict, folded_in: str, folded_out: str
) -> None:
"""
read content in <folded_in>. each line will be like:
quiche::BalsaFrame::ProcessHeaders;non-virtual thunk to Envoy::Http::Http1::BalsaParser::MessageDone;Envoy::Http::Http1::ConnectionImpl::onMessageComplete;Envoy::Http::Http1::ConnectionImpl::onMessageCompleteImpl;Envoy::Http::Http1::ServerConnectionImpl::onMessageCompleteBase;Envoy::Http::ConnectionManagerImpl::ActiveStream::decodeHeaders;Envoy::Http::FilterManager::decodeHeaders;virtual thunk to Envoy::Extensions::Common::Wasm::Context::decodeHeaders;proxy_wasm::ContextBase::onRequestHeaders;proxy_wasm::wamr::Wamr::getModuleFunctionImpl<proxy_wasm::Word, proxy_wasm::Word, proxy_wasm::Word, proxy_wasm::Word>;wasm_func_call;wasm_runtime_call_wasm;wasm_call_function;call_wasm_with_hw_bound_check;wasm_interp_call_wasm;llvm_jit_call_func_bytecode;wasm_runtime_invoke_native;push_args_end;aot_func_internal#3302;aot_func_internal#3308;asm_sysvec_apic_timer_interrupt;sysvec_apic_timer_interrupt;__sysvec_apic_timer_interrupt;hrtimer_interrupt;__hrtimer_run_queues;__remove_hrtimer;rb_next 1110899
symbol names are spearated by ";"
if there is a symbol named like "aot_func#XXX" or "aot_func_internal#XXX", it will be replaced with the function name in name section by index
"""
folded_in = Path(folded_in)
assert folded_in.exists()
folded_out = Path(folded_out)
import_function_count = import_section.get("function", 0)
with folded_in.open("rt", encoding="utf-8") as f_in, folded_out.open(
"wt", encoding="utf-8"
) as f_out:
precheck_mode = False
for line in f_in:
line = line.strip()
if "aot_func_internal" in line:
precheck_mode = True
f_in.seek(0)
for line in f_in:
new_line = []
line = line.strip()
m = re.match(r"(.*) (\d+)", line)
syms, samples = m.groups()
for sym in syms.split(";"):
m = re.match(r"aot_func(_internal)?#(\d+)", sym)
if not m:
new_line.append(sym)
continue
func_idx = m.groups()[-1]
if func_idx in name_section:
wasm_func_name = f"[Wasm] {name_section[func_idx]}"
else:
wasm_func_name = (
f"[Wasm] function[{func_idx + import_function_count}]"
)
if precheck_mode:
# aot_func_internal -> xxx
# aot_func --> xxx_precheck
wasm_func_name += "_precheck" if not m.groups()[0] else ""
else:
# aot_func --> xxx
pass
new_line.append(wasm_func_name)
line = ";".join(new_line)
line += f" {samples}"
f_out.write(line + os.linesep)
print(f"⚙️ {folded_in} -> {folded_out}")
def main(wabt_home: str, wasm_file: str, folded: str) -> None:
wabt_home = Path(wabt_home)
wasm_file = Path(wasm_file)
wasm_objdump_bin = preflight_check(wabt_home)
import_section = collect_import_section_content(wasm_objdump_bin, wasm_file)
name_section = collect_name_section_content(wasm_objdump_bin, wasm_file)
replace_function_name(import_section, name_section, folded, folded + ".translated")
if __name__ == "__main__":
argparse = argparse.ArgumentParser()
argparse.add_argument(
"--folded", help="stackcollapse-perf.pl generated, like out.folded"
)
argparse.add_argument("wasm_file", help="wasm file")
argparse.add_argument("--wabt_home", help="wabt home, like /opt/wabt-1.0.33")
args = argparse.parse_args()
main(args.wabt_home, args.wasm_file, args.folded)

View File

@ -44,12 +44,15 @@ add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1)
add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1)
add_definitions(-DWASM_ENABLE_PERF_PROFILING=1)
add_definitions(-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1)
add_definitions(-DWASM_ENABLE_LIB_WASI_THREADS=1)
add_definitions(-DWASM_ENABLE_MODULE_INST_CONTEXT=1)
if (WAMR_BUILD_LLVM_LEGACY_PM EQUAL 1)
add_definitions(-DWASM_ENABLE_LLVM_LEGACY_PM=1)
endif()
endif ()
if (LINUX)
add_definitions(-DWASM_ENABLE_LINUX_PERF=1)
endif ()
if (DEFINED WAMR_BUILD_AOT_FUNC_PREFIX)
add_definitions(-DAOT_FUNC_PREFIX="${WAMR_BUILD_AOT_FUNC_PREFIX}")
@ -199,31 +202,97 @@ include_directories (${SHARED_DIR}/include
enable_language (ASM)
if (NOT MINGW AND NOT MSVC)
set(WAMR_BUILD_LIBC_WASI 1)
else()
set(WAMR_BUILD_LIBC_UVWASI 1)
endif()
if ((NOT DEFINED WAMR_BUILD_LIBC_WASI) AND (NOT DEFINED WAMR_BUILD_LIBC_UVWASI))
set (WAMR_BUILD_LIBC_WASI 1)
endif ()
if ((WAMR_BUILD_LIBC_WASI EQUAL 1) AND (WAMR_BUILD_LIBC_UVWASI EQUAL 1))
message (WARNING "-- pick WAMR_BULID_LIBC_UVWASI when both are enabled")
set (WAMR_BUILD_LIBC_WASI 0)
endif ()
else ()
if (NOT DEFINED WAMR_BUILD_LIBC_UVWASI)
set (WAMR_BUILD_LIBC_UVWASI 1)
endif ()
if (WAMR_BUILD_LIBC_WASI EQUAL 1)
message (WARNING "-- don't accept WAMR_BUILD_LIBC_WASI=1 on MINGW or MSVC")
set (WAMR_BUILD_LIBC_WASI 0)
endif ()
endif ()
if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN)
set (WAMR_BUILD_LIBC_BUILTIN 1)
endif ()
if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD)
set (WAMR_BUILD_LIB_PTHREAD 1)
endif ()
if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS)
set (WAMR_BUILD_LIB_WASI_THREADS 1)
endif ()
if (WAMR_BUILD_LIBC_UVWASI EQUAL 1)
message ("-- Libc WASI enabled with uvwasi implementation")
endif ()
if (WAMR_BUILD_LIBC_WASI EQUAL 1)
message ("-- Libc WASI enabled")
endif ()
if ((NOT WAMR_BUILD_LIBC_WASI) AND (NOT WAMR_BUILD_LIBC_UVWASI))
message ("-- Libc WASI disabled")
endif ()
if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1)
message ("-- Libc builtin enabled")
else ()
message ("-- Libc builtin disabled")
endif ()
if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
message ("-- Lib pthread enabled")
else ()
message ("-- Lib pthread disabled")
endif ()
if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
message ("-- Lib wasi-threads enabled")
else ()
message ("-- Lib wasi-threads disabled")
endif ()
include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake)
include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake)
include (${SHARED_DIR}/utils/shared_utils.cmake)
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake)
include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake)
if (NOT MINGW)
if (NOT MSVC)
include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake)
else()
include (${IWASM_DIR}/libraries/libc-uvwasi/libc_uvwasi.cmake)
endif()
endif()
include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake)
include (${IWASM_DIR}/libraries/lib-wasi-threads/lib_wasi_threads.cmake)
include (${IWASM_DIR}/common/iwasm_common.cmake)
include (${IWASM_DIR}/interpreter/iwasm_interp.cmake)
include (${IWASM_DIR}/aot/iwasm_aot.cmake)
include (${IWASM_DIR}/compilation/iwasm_compl.cmake)
if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1)
include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake)
endif ()
if (WAMR_BUILD_LIBC_UVWASI EQUAL 1)
include (${IWASM_DIR}/libraries/libc-uvwasi/libc_uvwasi.cmake)
endif ()
if (WAMR_BUILD_LIBC_WASI EQUAL 1)
include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake)
endif ()
if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake)
endif ()
if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
include (${IWASM_DIR}/libraries/lib-wasi-threads/lib_wasi_threads.cmake)
endif ()
# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion")
if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang" OR MSVC))

View File

@ -184,9 +184,14 @@ print_help()
printf(" multiple names, e.g.\n");
printf(" --emit-custom-sections=section1,section2,sectionN\n");
#if BH_HAS_DLFCN
printf(" --native-lib=<lib> Register native libraries to the WASM module, which\n");
printf(" are shared object (.so) files, for example:\n");
printf(" --native-lib=test1.so --native-lib=test2.so\n");
printf(" --native-lib=<lib> Register native libraries to the WASM module, which\n");
printf(" are shared object (.so) files, for example:\n");
printf(" --native-lib=test1.so --native-lib=test2.so\n");
#endif
printf(" --invoke-c-api-import Treat unknown import function as wasm-c-api import function and\n");
printf(" quick call it from AOT code\n");
#if WASM_ENABLE_LINUX_PERF != 0
printf(" --enable-linux-perf Enable linux perf support\n");
#endif
printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n");
printf(" --version Show version information\n");
@ -325,6 +330,9 @@ main(int argc, char *argv[])
void *native_handle_list[8] = { NULL };
uint32 native_handle_count = 0;
#endif
#if WASM_ENABLE_LINUX_PERF != 0
bool enable_linux_perf = false;
#endif
option.opt_level = 3;
option.size_level = 3;
@ -526,7 +534,15 @@ main(int argc, char *argv[])
native_lib_list[native_lib_count++] = argv[0] + 13;
}
#endif
else if (!strncmp(argv[0], "--version", 9)) {
else if (!strcmp(argv[0], "--invoke-c-api-import")) {
option.quick_invoke_c_api_import = true;
}
#if WASM_ENABLE_LINUX_PERF != 0
else if (!strcmp(argv[0], "--enable-linux-perf")) {
enable_linux_perf = true;
}
#endif
else if (!strcmp(argv[0], "--version")) {
uint32 major, minor, patch;
wasm_runtime_get_version(&major, &minor, &patch);
printf("wamrc %u.%u.%u\n", major, minor, patch);
@ -579,6 +595,9 @@ main(int argc, char *argv[])
init_args.mem_alloc_option.allocator.malloc_func = malloc;
init_args.mem_alloc_option.allocator.realloc_func = realloc;
init_args.mem_alloc_option.allocator.free_func = free;
#if WASM_ENABLE_LINUX_PERF != 0
init_args.enable_linux_perf = enable_linux_perf;
#endif
/* initialize runtime environment */
if (!wasm_runtime_full_init(&init_args)) {