mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-07-16 17:28:31 +00:00
Merge main into dev/gc
This commit is contained in:
commit
a7dab94e93
|
@ -29,6 +29,7 @@ iwasm VM core
|
|||
- [Thread management and pthread library](./doc/pthread_library.md), ref to [sample](samples/multi-thread)
|
||||
- [Linux SGX (Intel Software Guard Extension) support](./doc/linux_sgx.md)
|
||||
- [Source debugging](./doc/source_debugging.md)
|
||||
- [XIP (Execution In Place) support](./doc/xip.md)
|
||||
|
||||
### post-MVP features
|
||||
- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions)
|
||||
|
|
|
@ -61,9 +61,13 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|||
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC")
|
||||
endif ()
|
||||
else ()
|
||||
add_definitions (-m32)
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32")
|
||||
include(CheckCCompilerFlag)
|
||||
Check_C_Compiler_Flag(-m32 M32_OK)
|
||||
if (M32_OK OR WAMR_BUILD_TARGET STREQUAL "X86_32")
|
||||
add_definitions (-m32)
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@ static const aot_intrinsic g_intrinsic_mapping[] = {
|
|||
{ "f64_convert_i64_u", "aot_intrinsic_u64_to_f64", AOT_INTRINSIC_FLAG_U64_TO_F64 },
|
||||
{ "f32_convert_i64_s", "aot_intrinsic_i64_to_f32", AOT_INTRINSIC_FLAG_I64_TO_F32 },
|
||||
{ "f32_convert_i64_u", "aot_intrinsic_u64_to_f32", AOT_INTRINSIC_FLAG_U64_TO_F32 },
|
||||
{ "i32_trunc_f64_u", "aot_intrinsic_f64_to_u32", AOT_INTRINSIC_FLAG_I32_TO_F64 },
|
||||
{ "i32_trunc_f64_u", "aot_intrinsic_f64_to_u32", AOT_INTRINSIC_FLAG_F64_TO_U32 },
|
||||
{ "i32_trunc_f64_s", "aot_intrinsic_f64_to_i32", AOT_INTRINSIC_FLAG_F64_TO_I32 },
|
||||
{ "f32_demote_f64", "aot_intrinsic_f64_to_f32", AOT_INTRINSIC_FLAG_F64_TO_F32 },
|
||||
{ "f64_promote_f32", "aot_intrinsic_f32_to_f64", AOT_INTRINSIC_FLAG_F32_TO_F64 },
|
||||
{ "f32_cmp", "aot_intrinsic_f32_cmp", AOT_INTRINSIC_FLAG_F32_CMP },
|
||||
|
|
|
@ -90,7 +90,7 @@ static bool
|
|||
check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
if (buf + length > buf_end) {
|
||||
if (buf + length < buf || buf + length > buf_end) {
|
||||
set_error_buf(error_buf, error_buf_size, "unexpect end");
|
||||
return false;
|
||||
}
|
||||
|
@ -166,6 +166,7 @@ GET_U64_FROM_ADDR(uint32 *addr)
|
|||
#define BIN_TYPE_ELF32B 1 /* 32-bit big endian */
|
||||
#define BIN_TYPE_ELF64L 2 /* 64-bit little endian */
|
||||
#define BIN_TYPE_ELF64B 3 /* 64-bit big endian */
|
||||
#define BIN_TYPE_COFF32 4 /* 32-bit little endian */
|
||||
#define BIN_TYPE_COFF64 6 /* 64-bit little endian */
|
||||
|
||||
/* Legal values for e_type (object file type). */
|
||||
|
@ -188,7 +189,8 @@ GET_U64_FROM_ADDR(uint32 *addr)
|
|||
#define E_MACHINE_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */
|
||||
#define E_MACHINE_XTENSA 94 /* Tensilica Xtensa Architecture */
|
||||
#define E_MACHINE_RISCV 243 /* RISC-V 32/64 */
|
||||
#define E_MACHINE_WIN_X86_64 0x8664 /* Windowx x86-64 architecture */
|
||||
#define E_MACHINE_WIN_I386 0x14c /* Windows i386 architecture */
|
||||
#define E_MACHINE_WIN_X86_64 0x8664 /* Windows x86-64 architecture */
|
||||
|
||||
/* Legal values for e_version */
|
||||
#define E_VERSION_CURRENT 1 /* Current version */
|
||||
|
@ -317,6 +319,7 @@ get_aot_file_target(AOTTargetInfo *target_info, char *target_buf,
|
|||
machine_type = "x86_64";
|
||||
break;
|
||||
case E_MACHINE_386:
|
||||
case E_MACHINE_WIN_I386:
|
||||
machine_type = "i386";
|
||||
break;
|
||||
case E_MACHINE_ARM:
|
||||
|
@ -2194,6 +2197,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end,
|
|||
|| !strcmp(group->section_name, ".text")
|
||||
#endif
|
||||
) {
|
||||
#if !defined(BH_PLATFORM_LINUX) && !defined(BH_PLATFORM_LINUX_SGX) \
|
||||
&& !defined(BH_PLATFORM_DARWIN)
|
||||
if (module->native_symbol_count > 0) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"cannot apply relocation to text section "
|
||||
|
@ -2201,6 +2206,7 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end,
|
|||
"\"--enable-indirect-mode\" flag");
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
if (!do_text_relocation(module, group, error_buf, error_buf_size))
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ typedef struct {
|
|||
REG_SYM(aot_intrinsic_i64_to_f64), \
|
||||
REG_SYM(aot_intrinsic_u64_to_f64), \
|
||||
REG_SYM(aot_intrinsic_f64_to_f32), \
|
||||
REG_SYM(aot_intrinsic_f64_to_i32), \
|
||||
REG_SYM(aot_intrinsic_f64_to_u32), \
|
||||
REG_SYM(aot_intrinsic_f32_to_f64), \
|
||||
REG_SYM(aot_intrinsic_f32_cmp), \
|
||||
|
|
|
@ -1774,7 +1774,7 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size,
|
|||
aot_set_exception(module_inst, "app heap corrupted");
|
||||
}
|
||||
else {
|
||||
aot_set_exception(module_inst, "out of memory");
|
||||
LOG_WARNING("warning: allocate %u bytes memory failed", size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -148,9 +148,6 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
|
|||
wasm_exec_env_destroy_internal(exec_env);
|
||||
return NULL;
|
||||
}
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_debug_instance_create(cluster);
|
||||
#endif
|
||||
#endif /* end of WASM_ENABLE_THREAD_MGR */
|
||||
|
||||
return exec_env;
|
||||
|
@ -165,7 +162,6 @@ wasm_exec_env_destroy(WASMExecEnv *exec_env)
|
|||
if (cluster) {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_cluster_thread_exited(exec_env);
|
||||
wasm_debug_instance_destroy(cluster);
|
||||
#endif
|
||||
wasm_cluster_terminate_all_except_self(cluster, exec_env);
|
||||
wasm_cluster_del_exec_env(cluster, exec_env);
|
||||
|
|
|
@ -294,6 +294,84 @@ get_package_type(const uint8 *buf, uint32 size)
|
|||
return Package_Type_Unknown;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
static uint8 *
|
||||
align_ptr(const uint8 *p, uint32 b)
|
||||
{
|
||||
uintptr_t v = (uintptr_t)p;
|
||||
uintptr_t m = b - 1;
|
||||
return (uint8 *)((v + m) & ~m);
|
||||
}
|
||||
|
||||
#define CHECK_BUF(buf, buf_end, length) \
|
||||
do { \
|
||||
if (buf + length < buf || buf + length > buf_end) \
|
||||
return false; \
|
||||
} while (0)
|
||||
|
||||
#define read_uint32(p, p_end, res) \
|
||||
do { \
|
||||
p = (uint8 *)align_ptr(p, sizeof(uint32)); \
|
||||
CHECK_BUF(p, p_end, sizeof(uint32)); \
|
||||
res = *(uint32 *)p; \
|
||||
p += sizeof(uint32); \
|
||||
} while (0)
|
||||
|
||||
bool
|
||||
wasm_runtime_is_xip_file(const uint8 *buf, uint32 size)
|
||||
{
|
||||
const uint8 *p = buf, *p_end = buf + size;
|
||||
uint32 section_type, sub_section_type, section_size;
|
||||
|
||||
if (get_package_type(buf, size) != Wasm_Module_AoT)
|
||||
return false;
|
||||
|
||||
CHECK_BUF(p, p_end, 8);
|
||||
p += 8;
|
||||
while (p < p_end) {
|
||||
read_uint32(p, p_end, section_type);
|
||||
read_uint32(p, p_end, section_size);
|
||||
CHECK_BUF(p, p_end, section_size);
|
||||
|
||||
if (section_type == AOT_SECTION_TYPE_CUSTOM) {
|
||||
read_uint32(p, p_end, sub_section_type);
|
||||
if (sub_section_type == AOT_CUSTOM_SECTION_NATIVE_SYMBOL) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
p -= sizeof(uint32);
|
||||
}
|
||||
}
|
||||
else if (section_type >= AOT_SECTION_TYPE_SIGANATURE) {
|
||||
return false;
|
||||
}
|
||||
p += section_size;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_AOT */
|
||||
|
||||
#if (WASM_ENABLE_THREAD_MGR != 0) && (WASM_ENABLE_DEBUG_INTERP != 0)
|
||||
uint32
|
||||
wasm_runtime_start_debug_instance(WASMExecEnv *exec_env)
|
||||
{
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster);
|
||||
|
||||
if (cluster->debug_inst) {
|
||||
LOG_WARNING("Cluster already bind to a debug instance");
|
||||
return cluster->debug_inst->control_thread->port;
|
||||
}
|
||||
|
||||
if (wasm_debug_instance_create(cluster)) {
|
||||
return cluster->debug_inst->control_thread->port;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static module_reader reader;
|
||||
static module_destroyer destroyer;
|
||||
|
@ -1431,7 +1509,7 @@ wasm_runtime_create_exec_env_and_call_wasm(
|
|||
if (module_inst->module_type == Wasm_Module_Bytecode)
|
||||
ret = wasm_create_exec_env_and_call_function(
|
||||
(WASMModuleInstance *)module_inst, (WASMFunctionInstance *)function,
|
||||
argc, argv);
|
||||
argc, argv, true);
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT)
|
||||
|
|
|
@ -406,6 +406,10 @@ wasm_runtime_destroy(void);
|
|||
WASM_RUNTIME_API_EXTERN PackageType
|
||||
get_package_type(const uint8 *buf, uint32 size);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN bool
|
||||
wasm_runtime_is_xip_file(const uint8 *buf, uint32 size);
|
||||
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN WASMModuleCommon *
|
||||
wasm_runtime_load(const uint8 *buf, uint32 size, char *error_buf,
|
||||
|
@ -494,6 +498,12 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env,
|
|||
uint32 num_results, wasm_val_t *results,
|
||||
uint32 num_args, ...);
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN uint32
|
||||
wasm_runtime_start_debug_instance(WASMExecEnv *exec_env);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Call a function reference of a given WASM runtime instance with
|
||||
* arguments.
|
||||
|
|
|
@ -224,7 +224,8 @@ acquire_wait_info(void *address, bool create)
|
|||
AtomicWaitInfo *wait_info = NULL;
|
||||
bh_list_status ret;
|
||||
|
||||
wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address);
|
||||
if (address)
|
||||
wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address);
|
||||
|
||||
if (!create)
|
||||
return wait_info;
|
||||
|
|
|
@ -2539,6 +2539,39 @@ fail:
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Check whether the target supports hardware atomic instructions */
|
||||
static bool
|
||||
aot_require_lower_atomic_pass(AOTCompContext *comp_ctx)
|
||||
{
|
||||
bool ret = false;
|
||||
if (!strncmp(comp_ctx->target_arch, "riscv", 5)) {
|
||||
char *feature =
|
||||
LLVMGetTargetMachineFeatureString(comp_ctx->target_machine);
|
||||
|
||||
if (feature) {
|
||||
if (!strstr(feature, "+a")) {
|
||||
ret = true;
|
||||
}
|
||||
LLVMDisposeMessage(feature);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check whether the target needs to expand switch to if/else */
|
||||
static bool
|
||||
aot_require_lower_switch_pass(AOTCompContext *comp_ctx)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
/* IR switch/case will cause .rodata relocation on riscv */
|
||||
if (!strncmp(comp_ctx->target_arch, "riscv", 5)) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
aot_compile_wasm(AOTCompContext *comp_ctx)
|
||||
{
|
||||
|
@ -2626,6 +2659,27 @@ aot_compile_wasm(AOTCompContext *comp_ctx)
|
|||
LLVMPassManagerBuilderDispose(pass_mgr_builder);
|
||||
}
|
||||
|
||||
if (comp_ctx->optimize && comp_ctx->is_indirect_mode) {
|
||||
LLVMPassManagerRef common_pass_mgr = NULL;
|
||||
|
||||
if (!(common_pass_mgr = LLVMCreatePassManager())) {
|
||||
aot_set_last_error("create pass manager failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
aot_add_expand_memory_op_pass(common_pass_mgr);
|
||||
|
||||
if (aot_require_lower_atomic_pass(comp_ctx))
|
||||
LLVMAddLowerAtomicPass(common_pass_mgr);
|
||||
|
||||
if (aot_require_lower_switch_pass(comp_ctx))
|
||||
LLVMAddLowerSwitchPass(common_pass_mgr);
|
||||
|
||||
LLVMRunPassManager(common_pass_mgr, comp_ctx->module);
|
||||
|
||||
LLVMDisposePassManager(common_pass_mgr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1913,7 +1913,8 @@ struct coff_hdr {
|
|||
#define IMAGE_FILE_MACHINE_I386 0x014c
|
||||
#define IMAGE_FILE_MACHINE_IA64 0x0200
|
||||
|
||||
#define AOT_COFF_BIN_TYPE 6
|
||||
#define AOT_COFF32_BIN_TYPE 4 /* 32-bit little endian */
|
||||
#define AOT_COFF64_BIN_TYPE 6 /* 64-bit little endian */
|
||||
|
||||
#define EI_NIDENT 16
|
||||
|
||||
|
@ -2029,8 +2030,11 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
|
|||
obj_data->target_info.e_version = 1;
|
||||
obj_data->target_info.e_flags = 0;
|
||||
|
||||
if (coff_header->u16Machine == IMAGE_FILE_MACHINE_AMD64)
|
||||
obj_data->target_info.bin_type = AOT_COFF_BIN_TYPE;
|
||||
if (coff_header->u16Machine == IMAGE_FILE_MACHINE_AMD64
|
||||
|| coff_header->u16Machine == IMAGE_FILE_MACHINE_IA64)
|
||||
obj_data->target_info.bin_type = AOT_COFF64_BIN_TYPE;
|
||||
else if (coff_header->u16Machine == IMAGE_FILE_MACHINE_I386)
|
||||
obj_data->target_info.bin_type = AOT_COFF32_BIN_TYPE;
|
||||
}
|
||||
else if (bin_type == LLVMBinaryTypeELF32L
|
||||
|| bin_type == LLVMBinaryTypeELF32B) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "aot_emit_memory.h"
|
||||
#include "aot_emit_exception.h"
|
||||
#include "../aot/aot_runtime.h"
|
||||
#include "aot_intrinsic.h"
|
||||
|
||||
#define BUILD_ICMP(op, left, right, res, name) \
|
||||
do { \
|
||||
|
@ -951,13 +952,66 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
|||
if (!(dst_addr = check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len)))
|
||||
return false;
|
||||
|
||||
/* TODO: lookup func ptr of "memmove" to call for XIP mode */
|
||||
if (comp_ctx->is_indirect_mode) {
|
||||
LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type;
|
||||
LLVMValueRef func, params[3];
|
||||
int32 func_idx;
|
||||
|
||||
if (!(res = LLVMBuildMemMove(comp_ctx->builder, dst_addr, 1, src_addr, 1,
|
||||
len))) {
|
||||
aot_set_last_error("llvm build memmove failed.");
|
||||
return false;
|
||||
if (!(dst_addr =
|
||||
LLVMBuildBitCast(comp_ctx->builder, dst_addr, INT32_PTR_TYPE,
|
||||
"memmove dst addr cast type"))) {
|
||||
aot_set_last_error("llvm cast memmove dst addr type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(src_addr =
|
||||
LLVMBuildBitCast(comp_ctx->builder, src_addr, INT32_PTR_TYPE,
|
||||
"memmove src addr cast type"))) {
|
||||
aot_set_last_error("llvm cast memmove src addr type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
param_types[0] = INT32_PTR_TYPE;
|
||||
param_types[1] = INT32_PTR_TYPE;
|
||||
param_types[2] = I32_TYPE;
|
||||
ret_type = INT32_PTR_TYPE;
|
||||
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) {
|
||||
aot_set_last_error("create LLVM function pointer type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
func_idx = aot_get_native_symbol_index(comp_ctx, "memmove");
|
||||
if (func_idx < 0) {
|
||||
return false;
|
||||
}
|
||||
if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol,
|
||||
func_ptr_type, func_idx))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
params[0] = dst_addr;
|
||||
params[1] = src_addr;
|
||||
params[2] = len;
|
||||
if (!(res = LLVMBuildCall(comp_ctx->builder, func, params, 3,
|
||||
"call memmove"))) {
|
||||
aot_set_last_error("llvm build memmove failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(res = LLVMBuildMemMove(comp_ctx->builder, dst_addr, 1, src_addr,
|
||||
1, len))) {
|
||||
aot_set_last_error("llvm build memmove failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
|
@ -981,11 +1035,57 @@ aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* TODO: lookup func ptr of "memset" to call for XIP mode */
|
||||
if (comp_ctx->is_indirect_mode) {
|
||||
LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type;
|
||||
LLVMValueRef func, params[3];
|
||||
int32 func_idx;
|
||||
|
||||
if (!(res = LLVMBuildMemSet(comp_ctx->builder, dst_addr, val, len, 1))) {
|
||||
aot_set_last_error("llvm build memset failed.");
|
||||
return false;
|
||||
if (!(dst_addr =
|
||||
LLVMBuildBitCast(comp_ctx->builder, dst_addr, INT32_PTR_TYPE,
|
||||
"memset dst addr cast type"))) {
|
||||
aot_set_last_error("llvm cast memset dst addr type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
param_types[0] = INT32_PTR_TYPE;
|
||||
param_types[1] = INT8_TYPE;
|
||||
param_types[2] = I32_TYPE;
|
||||
ret_type = INT32_PTR_TYPE;
|
||||
|
||||
if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false))) {
|
||||
aot_set_last_error("create LLVM function type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) {
|
||||
aot_set_last_error("create LLVM function pointer type failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
func_idx = aot_get_native_symbol_index(comp_ctx, "memset");
|
||||
if (func_idx < 0) {
|
||||
return false;
|
||||
}
|
||||
if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol,
|
||||
func_ptr_type, func_idx))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
params[0] = dst_addr;
|
||||
params[1] = val;
|
||||
params[2] = len;
|
||||
if (!(res = LLVMBuildCall(comp_ctx->builder, func, params, 3,
|
||||
"call memset"))) {
|
||||
aot_set_last_error("llvm build memset failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(res =
|
||||
LLVMBuildMemSet(comp_ctx->builder, dst_addr, val, len, 1))) {
|
||||
aot_set_last_error("llvm build memset failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
fail:
|
||||
|
@ -1127,16 +1227,20 @@ aot_compile_op_atomic_cmpxchg(AOTCompContext *comp_ctx,
|
|||
}
|
||||
|
||||
if (op_type == VALUE_TYPE_I32) {
|
||||
if (!(result = LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE,
|
||||
"result_i32"))) {
|
||||
goto fail;
|
||||
if (LLVMTypeOf(result) != I32_TYPE) {
|
||||
if (!(result = LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE,
|
||||
"result_i32"))) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
PUSH_I32(result);
|
||||
}
|
||||
else {
|
||||
if (!(result = LLVMBuildZExt(comp_ctx->builder, result, I64_TYPE,
|
||||
"result_i64"))) {
|
||||
goto fail;
|
||||
if (LLVMTypeOf(result) != I64_TYPE) {
|
||||
if (!(result = LLVMBuildZExt(comp_ctx->builder, result, I64_TYPE,
|
||||
"result_i64"))) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
PUSH_I64(result);
|
||||
}
|
||||
|
|
|
@ -445,6 +445,9 @@ aot_get_func_from_table(const AOTCompContext *comp_ctx, LLVMValueRef base,
|
|||
bool
|
||||
aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str);
|
||||
|
||||
void
|
||||
aot_add_expand_memory_op_pass(LLVMPassManagerRef pass);
|
||||
|
||||
#if WASM_ENABLE_LAZY_JIT != 0
|
||||
void
|
||||
aot_handle_llvm_errmsg(char *error_buf, uint32 error_buf_size,
|
||||
|
|
|
@ -6,20 +6,29 @@
|
|||
#include <llvm/ADT/SmallVector.h>
|
||||
#include <llvm/ADT/Twine.h>
|
||||
#include <llvm/ADT/Triple.h>
|
||||
#include <llvm/Analysis/TargetTransformInfo.h>
|
||||
#include <llvm/CodeGen/TargetPassConfig.h>
|
||||
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <llvm/MC/MCSubtargetInfo.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm-c/Core.h>
|
||||
#include <llvm-c/ExecutionEngine.h>
|
||||
#include <llvm-c/Initialization.h>
|
||||
#include <llvm/ExecutionEngine/GenericValue.h>
|
||||
#include <llvm/ExecutionEngine/JITEventListener.h>
|
||||
#include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/IntrinsicInst.h>
|
||||
#include <llvm/IR/LegacyPassManager.h>
|
||||
#include <llvm/Support/CommandLine.h>
|
||||
#include <llvm/Support/ErrorHandling.h>
|
||||
#include <llvm/Target/CodeGenCWrappers.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm/Target/TargetOptions.h>
|
||||
#include <llvm/Transforms/Utils/LowerMemIntrinsics.h>
|
||||
#include <cstring>
|
||||
|
||||
using namespace llvm;
|
||||
|
@ -33,6 +42,9 @@ WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
|
|||
extern "C" bool
|
||||
aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str);
|
||||
|
||||
extern "C" void
|
||||
aot_add_expand_memory_op_pass(LLVMPassManagerRef pass);
|
||||
|
||||
extern "C" void
|
||||
aot_func_disable_tce(LLVMValueRef func);
|
||||
|
||||
|
@ -106,6 +118,109 @@ WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
|
|||
return 1;
|
||||
}
|
||||
|
||||
class ExpandMemoryOpPass : public llvm::ModulePass
|
||||
{
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
ExpandMemoryOpPass()
|
||||
: ModulePass(ID)
|
||||
{}
|
||||
|
||||
bool runOnModule(Module &M) override;
|
||||
|
||||
bool expandMemIntrinsicUses(Function &F);
|
||||
StringRef getPassName() const override
|
||||
{
|
||||
return "Expand memory operation intrinsics";
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override
|
||||
{
|
||||
AU.addRequired<TargetTransformInfoWrapperPass>();
|
||||
}
|
||||
};
|
||||
|
||||
char ExpandMemoryOpPass::ID = 0;
|
||||
|
||||
bool
|
||||
ExpandMemoryOpPass::expandMemIntrinsicUses(Function &F)
|
||||
{
|
||||
Intrinsic::ID ID = F.getIntrinsicID();
|
||||
bool Changed = false;
|
||||
|
||||
for (auto I = F.user_begin(), E = F.user_end(); I != E;) {
|
||||
Instruction *Inst = cast<Instruction>(*I);
|
||||
++I;
|
||||
|
||||
switch (ID) {
|
||||
case Intrinsic::memcpy:
|
||||
{
|
||||
auto *Memcpy = cast<MemCpyInst>(Inst);
|
||||
Function *ParentFunc = Memcpy->getParent()->getParent();
|
||||
const TargetTransformInfo &TTI =
|
||||
getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
|
||||
*ParentFunc);
|
||||
expandMemCpyAsLoop(Memcpy, TTI);
|
||||
Changed = true;
|
||||
Memcpy->eraseFromParent();
|
||||
break;
|
||||
}
|
||||
case Intrinsic::memmove:
|
||||
{
|
||||
auto *Memmove = cast<MemMoveInst>(Inst);
|
||||
expandMemMoveAsLoop(Memmove);
|
||||
Changed = true;
|
||||
Memmove->eraseFromParent();
|
||||
break;
|
||||
}
|
||||
case Intrinsic::memset:
|
||||
{
|
||||
auto *Memset = cast<MemSetInst>(Inst);
|
||||
expandMemSetAsLoop(Memset);
|
||||
Changed = true;
|
||||
Memset->eraseFromParent();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
bool
|
||||
ExpandMemoryOpPass::runOnModule(Module &M)
|
||||
{
|
||||
bool Changed = false;
|
||||
|
||||
for (Function &F : M) {
|
||||
if (!F.isDeclaration())
|
||||
continue;
|
||||
|
||||
switch (F.getIntrinsicID()) {
|
||||
case Intrinsic::memcpy:
|
||||
case Intrinsic::memmove:
|
||||
case Intrinsic::memset:
|
||||
if (expandMemIntrinsicUses(F))
|
||||
Changed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
void
|
||||
aot_add_expand_memory_op_pass(LLVMPassManagerRef pass)
|
||||
{
|
||||
unwrap(pass)->add(new ExpandMemoryOpPass());
|
||||
}
|
||||
|
||||
bool
|
||||
aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str)
|
||||
{
|
||||
|
|
|
@ -16,3 +16,11 @@ endif()
|
|||
|
||||
set (IWASM_COMPL_SOURCE ${source_all})
|
||||
|
||||
# Disalbe rtti to works with LLVM
|
||||
|
||||
if (MSVC)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
|
||||
else()
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
endif()
|
||||
|
||||
|
|
|
@ -235,6 +235,17 @@ wasm_runtime_free(void *ptr);
|
|||
WASM_RUNTIME_API_EXTERN package_type_t
|
||||
get_package_type(const uint8_t *buf, uint32_t size);
|
||||
|
||||
/**
|
||||
* Check whether a file is an AOT XIP (Execution In Place) file
|
||||
*
|
||||
* @param buf the package buffer
|
||||
* @param size the package buffer size
|
||||
*
|
||||
* @return true if success, false otherwise
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN bool
|
||||
wasm_runtime_is_xip_file(const uint8_t *buf, uint32_t size);
|
||||
|
||||
/**
|
||||
* It is a callback for WAMR providing by embedding to load a module file
|
||||
* into a buffer
|
||||
|
@ -408,6 +419,26 @@ wasm_runtime_create_exec_env(wasm_module_inst_t module_inst,
|
|||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_runtime_destroy_exec_env(wasm_exec_env_t exec_env);
|
||||
|
||||
/**
|
||||
* Start debug instance based on given execution environment.
|
||||
* Note:
|
||||
* The debug instance will be destroyed during destroying the
|
||||
* execution environment, developers don't need to destroy it
|
||||
* manually.
|
||||
* If the cluster of this execution environment has already
|
||||
* been bound to a debug instance, this function will return true
|
||||
* directly.
|
||||
* If developer spawns some exec_env by wasm_runtime_spawn_exec_env,
|
||||
* don't need to call this function for every spawned exec_env as
|
||||
* they are sharing the same cluster with the main exec_env.
|
||||
*
|
||||
* @param exec_env the execution environment to start debug instance
|
||||
*
|
||||
* @return debug port if success, 0 otherwise.
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN uint32_t
|
||||
wasm_runtime_start_debug_instance(wasm_exec_env_t exec_env);
|
||||
|
||||
/**
|
||||
* Initialize thread environment.
|
||||
* Note:
|
||||
|
|
|
@ -695,6 +695,20 @@ struct WASMModule {
|
|||
HashMap *ref_type_set;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
/**
|
||||
* Count how many instances reference this module. When source
|
||||
* debugging feature enabled, the debugger may modify the code
|
||||
* section of the module, so we need to report a warning if user
|
||||
* create several instances based on the same module
|
||||
*
|
||||
* Sub_instances created by lib-pthread or spawn API will not
|
||||
* influence or check the ref count
|
||||
*/
|
||||
uint32 ref_count;
|
||||
korp_mutex ref_count_lock;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
|
||||
const uint8 *name_section_buf;
|
||||
const uint8 *name_section_buf_end;
|
||||
|
|
|
@ -55,7 +55,7 @@ static bool
|
|||
check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
if (buf + length > buf_end) {
|
||||
if (buf + length < buf || buf + length > buf_end) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"unexpected end of section or function");
|
||||
return false;
|
||||
|
@ -67,7 +67,7 @@ static bool
|
|||
check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length,
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
if (buf + length > buf_end) {
|
||||
if (buf + length < buf || buf + length > buf_end) {
|
||||
set_error_buf(error_buf, error_buf_size, "unexpected end");
|
||||
return false;
|
||||
}
|
||||
|
@ -1747,7 +1747,6 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end,
|
|||
bool linked_call_conv_raw = false;
|
||||
bool is_native_symbol = false;
|
||||
|
||||
CHECK_BUF(p, p_end, 1);
|
||||
read_leb_uint32(p, p_end, declare_type_index);
|
||||
*p_buf = p;
|
||||
|
||||
|
@ -3901,6 +3900,18 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!aux_stack_top_global) {
|
||||
/* Auxiliary stack global isn't found, it must be unused
|
||||
in the wasm app, as if it is used, the global must be
|
||||
defined. Here we set it to __heap_base global and set
|
||||
its size to 0. */
|
||||
aux_stack_top_global = aux_heap_base_global;
|
||||
aux_stack_top = aux_heap_base;
|
||||
module->aux_stack_top_global_index =
|
||||
module->aux_heap_base_global_index;
|
||||
module->aux_stack_bottom = aux_stack_top;
|
||||
module->aux_stack_size = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3945,7 +3956,7 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
|||
export->name, export->index);
|
||||
|
||||
/* resolve retain function.
|
||||
If not find, reset malloc function index */
|
||||
If not found, reset malloc function index */
|
||||
export_tmp = module->exports;
|
||||
for (j = 0; j < module->export_count; j++, export_tmp++) {
|
||||
if ((export_tmp->kind == EXPORT_KIND_FUNC)
|
||||
|
@ -4096,6 +4107,10 @@ create_module(char *error_buf, uint32 error_buf_size)
|
|||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
bh_list_init(&module->fast_opcode_list);
|
||||
if (os_mutex_init(&module->ref_count_lock) != 0) {
|
||||
wasm_runtime_free(module);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return module;
|
||||
}
|
||||
|
@ -4205,7 +4220,6 @@ create_sections(const uint8 *buf, uint32 size, WASMSection **p_section_list,
|
|||
}
|
||||
last_section_index = section_index;
|
||||
}
|
||||
CHECK_BUF1(p, p_end, 1);
|
||||
read_leb_uint32(p, p_end, section_size);
|
||||
CHECK_BUF1(p, p_end, section_size);
|
||||
|
||||
|
@ -4439,6 +4453,7 @@ wasm_loader_unload(WASMModule *module)
|
|||
wasm_runtime_free(fast_opcode);
|
||||
fast_opcode = next;
|
||||
}
|
||||
os_mutex_destroy(&module->ref_count_lock);
|
||||
#endif
|
||||
|
||||
wasm_runtime_free(module);
|
||||
|
|
|
@ -25,14 +25,14 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
|
|||
string);
|
||||
}
|
||||
|
||||
#define CHECK_BUF(buf, buf_end, length) \
|
||||
do { \
|
||||
bh_assert(buf + length <= buf_end); \
|
||||
#define CHECK_BUF(buf, buf_end, length) \
|
||||
do { \
|
||||
bh_assert(buf + length >= buf && buf + length <= buf_end); \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_BUF1(buf, buf_end, length) \
|
||||
do { \
|
||||
bh_assert(buf + length <= buf_end); \
|
||||
#define CHECK_BUF1(buf, buf_end, length) \
|
||||
do { \
|
||||
bh_assert(buf + length >= buf && buf + length <= buf_end); \
|
||||
} while (0)
|
||||
|
||||
#define skip_leb(p) while (*p++ & 0x80)
|
||||
|
@ -45,7 +45,7 @@ is_32bit_type(uint8 type)
|
|||
{
|
||||
if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
|| type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF)
|
||||
|| type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
|
||||
#endif
|
||||
)
|
||||
return true;
|
||||
|
@ -412,7 +412,6 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end,
|
|||
void *linked_attachment = NULL;
|
||||
bool linked_call_conv_raw = false;
|
||||
|
||||
CHECK_BUF(p, p_end, 1);
|
||||
read_leb_uint32(p, p_end, declare_type_index);
|
||||
*p_buf = p;
|
||||
|
||||
|
@ -1962,6 +1961,18 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!aux_stack_top_global) {
|
||||
/* Auxiliary stack global isn't found, it must be unused
|
||||
in the wasm app, as if it is used, the global must be
|
||||
defined. Here we set it to __heap_base global and set
|
||||
its size to 0. */
|
||||
aux_stack_top_global = aux_heap_base_global;
|
||||
aux_stack_top = aux_heap_base;
|
||||
module->aux_stack_top_global_index =
|
||||
module->aux_heap_base_global_index;
|
||||
module->aux_stack_bottom = aux_stack_top;
|
||||
module->aux_stack_size = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2005,7 +2016,7 @@ load_from_sections(WASMModule *module, WASMSection *sections,
|
|||
export->name, export->index);
|
||||
|
||||
/* resolve retain function.
|
||||
If not find, reset malloc function index */
|
||||
If not found, reset malloc function index */
|
||||
export_tmp = module->exports;
|
||||
for (j = 0; j < module->export_count; j++, export_tmp++) {
|
||||
if ((export_tmp->kind == EXPORT_KIND_FUNC)
|
||||
|
@ -2234,7 +2245,6 @@ create_sections(const uint8 *buf, uint32 size, WASMSection **p_section_list,
|
|||
|| last_section_index < section_index);
|
||||
last_section_index = section_index;
|
||||
}
|
||||
CHECK_BUF1(p, p_end, 1);
|
||||
read_leb_uint32(p, p_end, section_size);
|
||||
CHECK_BUF1(p, p_end, section_size);
|
||||
|
||||
|
|
|
@ -900,7 +900,7 @@ execute_post_inst_function(WASMModuleInstance *module_inst)
|
|||
return true;
|
||||
|
||||
return wasm_create_exec_env_and_call_function(module_inst, post_inst_func,
|
||||
0, NULL);
|
||||
0, NULL, false);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
|
@ -929,7 +929,7 @@ execute_memory_init_function(WASMModuleInstance *module_inst)
|
|||
return true;
|
||||
|
||||
return wasm_create_exec_env_and_call_function(module_inst, memory_init_func,
|
||||
0, NULL);
|
||||
0, NULL, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -944,7 +944,8 @@ execute_start_function(WASMModuleInstance *module_inst)
|
|||
bh_assert(!func->is_import_func && func->param_cell_num == 0
|
||||
&& func->ret_cell_num == 0);
|
||||
|
||||
return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL);
|
||||
return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL,
|
||||
false);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -972,11 +973,11 @@ execute_malloc_function(WASMModuleInstance *module_inst,
|
|||
}
|
||||
|
||||
ret = wasm_create_exec_env_and_call_function(module_inst, malloc_func, argc,
|
||||
argv);
|
||||
argv, false);
|
||||
|
||||
if (retain_func && ret) {
|
||||
ret = wasm_create_exec_env_and_call_function(module_inst, retain_func,
|
||||
1, argv);
|
||||
1, argv, false);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
|
@ -992,7 +993,7 @@ execute_free_function(WASMModuleInstance *module_inst,
|
|||
|
||||
argv[0] = offset;
|
||||
return wasm_create_exec_env_and_call_function(module_inst, free_func, 1,
|
||||
argv);
|
||||
argv, false);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
|
@ -1125,6 +1126,19 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
|
|||
if (!module)
|
||||
return NULL;
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
if (!is_sub_inst) {
|
||||
os_mutex_lock(&module->ref_count_lock);
|
||||
if (module->ref_count != 0) {
|
||||
LOG_WARNING(
|
||||
"warning: multiple instances referencing the same module may "
|
||||
"cause unexpected behaviour during debugging");
|
||||
}
|
||||
module->ref_count++;
|
||||
os_mutex_unlock(&module->ref_count_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check heap size */
|
||||
heap_size = align_uint(heap_size, 8);
|
||||
if (heap_size > APP_HEAP_SIZE_MAX)
|
||||
|
@ -1133,6 +1147,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
|
|||
/* Allocate the memory */
|
||||
if (!(module_inst = runtime_malloc(sizeof(WASMModuleInstance), error_buf,
|
||||
error_buf_size))) {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
if (!is_sub_inst) {
|
||||
os_mutex_lock(&module->ref_count_lock);
|
||||
module->ref_count--;
|
||||
os_mutex_unlock(&module->ref_count_lock);
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1525,7 +1546,9 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
|
|||
(WASMModuleInstanceCommon *)module_inst);
|
||||
#endif
|
||||
(void)global_data_end;
|
||||
|
||||
return module_inst;
|
||||
|
||||
fail:
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
|
@ -1582,6 +1605,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
if (!is_sub_inst) {
|
||||
os_mutex_lock(&module_inst->module->ref_count_lock);
|
||||
module_inst->module->ref_count--;
|
||||
os_mutex_unlock(&module_inst->module->ref_count_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
wasm_runtime_free(module_inst);
|
||||
}
|
||||
|
||||
|
@ -1667,7 +1698,8 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
|
|||
bool
|
||||
wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
|
||||
WASMFunctionInstance *func,
|
||||
unsigned argc, uint32 argv[])
|
||||
unsigned argc, uint32 argv[],
|
||||
bool enable_debug)
|
||||
{
|
||||
WASMExecEnv *exec_env;
|
||||
bool ret;
|
||||
|
@ -1686,6 +1718,11 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
|
|||
}
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
if (enable_debug) {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_runtime_start_debug_instance(exec_env);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1836,7 +1873,7 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
|
|||
wasm_set_exception(module_inst, "app heap corrupted");
|
||||
}
|
||||
else {
|
||||
wasm_set_exception(module_inst, "out of memory");
|
||||
LOG_WARNING("warning: allocate %u bytes memory failed", size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -320,7 +320,8 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
|
|||
bool
|
||||
wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
|
||||
WASMFunctionInstance *function,
|
||||
unsigned argc, uint32 argv[]);
|
||||
unsigned argc, uint32 argv[],
|
||||
bool enable_debug);
|
||||
|
||||
bool
|
||||
wasm_create_exec_env_singleton(WASMModuleInstance *module_inst);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include "bh_log.h"
|
||||
#include "gdbserver.h"
|
||||
#include "platform_api_extension.h"
|
||||
#include "bh_platform.h"
|
||||
#include "wasm_interp.h"
|
||||
#include "wasm_opcode.h"
|
||||
#include "wasm_runtime.h"
|
||||
|
@ -54,20 +54,11 @@ control_thread_routine(void *arg)
|
|||
{
|
||||
WASMDebugInstance *debug_inst = (WASMDebugInstance *)arg;
|
||||
WASMDebugControlThread *control_thread = NULL;
|
||||
WASMCluster *cluster = NULL;
|
||||
WASMExecEnv *exec_env;
|
||||
bh_assert(debug_inst);
|
||||
|
||||
control_thread = debug_inst->control_thread;
|
||||
bh_assert(control_thread);
|
||||
|
||||
cluster = debug_inst->cluster;
|
||||
bh_assert(cluster);
|
||||
|
||||
exec_env = bh_list_first_elem(&cluster->exec_env_list);
|
||||
bh_assert(exec_env);
|
||||
|
||||
os_mutex_lock(&exec_env->wait_lock);
|
||||
os_mutex_lock(&debug_inst->wait_lock);
|
||||
|
||||
control_thread->status = RUNNING;
|
||||
|
||||
|
@ -84,19 +75,31 @@ control_thread_routine(void *arg)
|
|||
LOG_WARNING("control thread of debug object %p start\n", debug_inst);
|
||||
|
||||
control_thread->server =
|
||||
wasm_launch_gdbserver(control_thread->ip_addr, control_thread->port);
|
||||
wasm_create_gdbserver(control_thread->ip_addr, &control_thread->port);
|
||||
|
||||
if (!control_thread->server) {
|
||||
LOG_ERROR("Failed to create debug server\n");
|
||||
os_cond_signal(&exec_env->wait_cond);
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
os_cond_signal(&debug_inst->wait_cond);
|
||||
os_mutex_unlock(&debug_inst->wait_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
control_thread->server->thread = control_thread;
|
||||
|
||||
/* control thread ready, notify main thread */
|
||||
os_cond_signal(&exec_env->wait_cond);
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
/*
|
||||
* wasm gdbserver created, the execution thread
|
||||
* doesn't need to wait for the debugger connection,
|
||||
* so we wake up the execution thread before listen
|
||||
*/
|
||||
os_cond_signal(&debug_inst->wait_cond);
|
||||
os_mutex_unlock(&debug_inst->wait_lock);
|
||||
|
||||
/* wait lldb client to connect */
|
||||
if (!wasm_gdbserver_listen(control_thread->server)) {
|
||||
LOG_ERROR("Failed while connecting debugger\n");
|
||||
wasm_runtime_free(control_thread->server);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
os_mutex_lock(&control_thread->wait_lock);
|
||||
|
@ -112,7 +115,7 @@ control_thread_routine(void *arg)
|
|||
os_mutex_unlock(&control_thread->wait_lock);
|
||||
}
|
||||
|
||||
LOG_VERBOSE("control thread of debug object %p stop\n", debug_inst);
|
||||
LOG_VERBOSE("control thread of debug object [%p] stopped\n", debug_inst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -120,12 +123,6 @@ static WASMDebugControlThread *
|
|||
wasm_debug_control_thread_create(WASMDebugInstance *debug_instance)
|
||||
{
|
||||
WASMDebugControlThread *control_thread;
|
||||
WASMCluster *cluster = debug_instance->cluster;
|
||||
WASMExecEnv *exec_env;
|
||||
bh_assert(cluster);
|
||||
|
||||
exec_env = bh_list_first_elem(&cluster->exec_env_list);
|
||||
bh_assert(exec_env);
|
||||
|
||||
if (!(control_thread =
|
||||
wasm_runtime_malloc(sizeof(WASMDebugControlThread)))) {
|
||||
|
@ -139,18 +136,18 @@ wasm_debug_control_thread_create(WASMDebugInstance *debug_instance)
|
|||
|
||||
debug_instance->control_thread = control_thread;
|
||||
|
||||
os_mutex_lock(&exec_env->wait_lock);
|
||||
os_mutex_lock(&debug_instance->wait_lock);
|
||||
|
||||
if (0
|
||||
!= os_thread_create(&control_thread->tid, control_thread_routine,
|
||||
debug_instance, APP_THREAD_STACK_SIZE_MAX)) {
|
||||
os_mutex_unlock(&control_thread->wait_lock);
|
||||
os_mutex_unlock(&debug_instance->wait_lock);
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* wait until the debug control thread ready */
|
||||
os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
os_cond_wait(&debug_instance->wait_cond, &debug_instance->wait_lock);
|
||||
os_mutex_unlock(&debug_instance->wait_lock);
|
||||
if (!control_thread->server)
|
||||
goto fail1;
|
||||
|
||||
|
@ -174,7 +171,8 @@ static void
|
|||
wasm_debug_control_thread_destroy(WASMDebugInstance *debug_instance)
|
||||
{
|
||||
WASMDebugControlThread *control_thread = debug_instance->control_thread;
|
||||
LOG_VERBOSE("control thread of debug object %p stop\n", debug_instance);
|
||||
LOG_VERBOSE("stopping control thread of debug object [%p]\n",
|
||||
debug_instance);
|
||||
control_thread->status = STOPPED;
|
||||
os_mutex_lock(&control_thread->wait_lock);
|
||||
wasm_close_gdbserver(control_thread->server);
|
||||
|
@ -286,6 +284,15 @@ wasm_debug_instance_create(WASMCluster *cluster)
|
|||
return NULL;
|
||||
}
|
||||
memset(instance, 0, sizeof(WASMDebugInstance));
|
||||
|
||||
if (os_mutex_init(&instance->wait_lock) != 0) {
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (os_cond_init(&instance->wait_cond) != 0) {
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
bh_list_init(&instance->break_point_list);
|
||||
|
||||
instance->cluster = cluster;
|
||||
|
@ -297,29 +304,21 @@ wasm_debug_instance_create(WASMCluster *cluster)
|
|||
if (!wasm_debug_control_thread_create(instance)) {
|
||||
LOG_ERROR("WASM Debug Engine error: failed to create control thread");
|
||||
wasm_runtime_free(instance);
|
||||
return NULL;
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static WASMDebugInstance *
|
||||
wasm_cluster_get_debug_instance(WASMDebugEngine *engine, WASMCluster *cluster)
|
||||
{
|
||||
WASMDebugInstance *instance;
|
||||
|
||||
os_mutex_lock(&g_debug_engine->instance_list_lock);
|
||||
instance = bh_list_first_elem(&engine->debug_instance_list);
|
||||
while (instance) {
|
||||
if (instance->cluster == cluster) {
|
||||
os_mutex_unlock(&g_debug_engine->instance_list_lock);
|
||||
return instance;
|
||||
}
|
||||
instance = bh_list_elem_next(instance);
|
||||
}
|
||||
os_mutex_unlock(&g_debug_engine->instance_list_lock);
|
||||
wasm_cluster_set_debug_inst(cluster, instance);
|
||||
|
||||
return instance;
|
||||
|
||||
fail3:
|
||||
os_cond_destroy(&instance->wait_cond);
|
||||
fail2:
|
||||
os_mutex_destroy(&instance->wait_lock);
|
||||
fail1:
|
||||
wasm_runtime_free(instance);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -347,7 +346,7 @@ wasm_debug_instance_destroy(WASMCluster *cluster)
|
|||
return;
|
||||
}
|
||||
|
||||
instance = wasm_cluster_get_debug_instance(g_debug_engine, cluster);
|
||||
instance = cluster->debug_inst;
|
||||
if (instance) {
|
||||
/* destroy control thread */
|
||||
wasm_debug_control_thread_destroy(instance);
|
||||
|
@ -359,7 +358,11 @@ wasm_debug_instance_destroy(WASMCluster *cluster)
|
|||
/* destroy all breakpoints */
|
||||
wasm_debug_instance_destroy_breakpoints(instance);
|
||||
|
||||
os_mutex_destroy(&instance->wait_lock);
|
||||
os_cond_destroy(&instance->wait_cond);
|
||||
|
||||
wasm_runtime_free(instance);
|
||||
cluster->debug_inst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -434,47 +437,78 @@ wasm_debug_instance_get_tids(WASMDebugInstance *instance, uint64 tids[],
|
|||
int len)
|
||||
{
|
||||
WASMExecEnv *exec_env;
|
||||
int i = 0;
|
||||
int i = 0, threads_num = 0;
|
||||
|
||||
if (!instance)
|
||||
return 0;
|
||||
|
||||
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
||||
while (exec_env && i < len) {
|
||||
tids[i++] = exec_env->handle;
|
||||
/* Some threads may not be ready */
|
||||
if (exec_env->handle != 0) {
|
||||
tids[i++] = exec_env->handle;
|
||||
threads_num++;
|
||||
}
|
||||
exec_env = bh_list_elem_next(exec_env);
|
||||
}
|
||||
LOG_VERBOSE("find %d tids\n", i);
|
||||
return i;
|
||||
LOG_VERBOSE("find %d tids\n", threads_num);
|
||||
return threads_num;
|
||||
}
|
||||
|
||||
static WASMExecEnv *
|
||||
get_stopped_thread(WASMCluster *cluster)
|
||||
{
|
||||
WASMExecEnv *exec_env;
|
||||
|
||||
exec_env = bh_list_first_elem(&cluster->exec_env_list);
|
||||
while (exec_env) {
|
||||
if (exec_env->current_status->running_status != STATUS_RUNNING) {
|
||||
return exec_env;
|
||||
}
|
||||
exec_env = bh_list_elem_next(exec_env);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64
|
||||
wasm_debug_instance_wait_thread(WASMDebugInstance *instance, uint64 tid,
|
||||
uint32 *status)
|
||||
{
|
||||
WASMExecEnv *exec_env;
|
||||
WASMExecEnv *last_exec_env = NULL;
|
||||
WASMExecEnv *exec_env = NULL;
|
||||
|
||||
os_mutex_lock(&instance->wait_lock);
|
||||
while ((instance->cluster->exec_env_list.len != 0)
|
||||
&& ((exec_env = get_stopped_thread(instance->cluster)) == NULL)) {
|
||||
os_cond_wait(&instance->wait_cond, &instance->wait_lock);
|
||||
}
|
||||
os_mutex_unlock(&instance->wait_lock);
|
||||
|
||||
/* If cluster has no exec_env, then this whole cluster is exiting */
|
||||
if (instance->cluster->exec_env_list.len == 0) {
|
||||
*status = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
instance->current_tid = exec_env->handle;
|
||||
*status = exec_env->current_status->signal_flag;
|
||||
return exec_env->handle;
|
||||
}
|
||||
|
||||
uint32
|
||||
wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, uint64 tid)
|
||||
{
|
||||
WASMExecEnv *exec_env = NULL;
|
||||
|
||||
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
||||
while (exec_env) {
|
||||
last_exec_env = exec_env;
|
||||
if (instance->current_tid != 0
|
||||
&& last_exec_env->handle == instance->current_tid) {
|
||||
break;
|
||||
if (exec_env->handle == tid) {
|
||||
return exec_env->current_status->signal_flag;
|
||||
}
|
||||
exec_env = bh_list_elem_next(exec_env);
|
||||
}
|
||||
|
||||
if (last_exec_env) {
|
||||
wasm_cluster_wait_thread_status(last_exec_env, status);
|
||||
if (instance->current_tid == 0)
|
||||
instance->current_tid = last_exec_env->handle;
|
||||
return last_exec_env->handle;
|
||||
}
|
||||
else {
|
||||
*status = ~0;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -42,6 +42,8 @@ typedef struct WASMDebugInstance {
|
|||
WASMCluster *cluster;
|
||||
uint32 id;
|
||||
korp_tid current_tid;
|
||||
korp_mutex wait_lock;
|
||||
korp_cond wait_cond;
|
||||
} WASMDebugInstance;
|
||||
|
||||
typedef enum WASMDebugEventKind {
|
||||
|
@ -160,6 +162,9 @@ uint64
|
|||
wasm_debug_instance_wait_thread(WASMDebugInstance *instance, uint64 tid,
|
||||
uint32 *status);
|
||||
|
||||
uint32
|
||||
wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, uint64 tid);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_singlestep(WASMDebugInstance *instance, uint64 tid);
|
||||
|
||||
|
|
|
@ -51,17 +51,18 @@ static struct packet_handler_elem packet_handler_table[255] = {
|
|||
};
|
||||
|
||||
WASMGDBServer *
|
||||
wasm_launch_gdbserver(char *host, int port)
|
||||
wasm_create_gdbserver(char *host, int *port)
|
||||
{
|
||||
int listen_fd = -1;
|
||||
const int one = 1;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t socklen;
|
||||
int ret;
|
||||
int sockt_fd = 0;
|
||||
|
||||
WASMGDBServer *server;
|
||||
|
||||
bh_assert(port);
|
||||
|
||||
if (!(server = wasm_runtime_malloc(sizeof(WASMGDBServer)))) {
|
||||
LOG_ERROR("wasm gdb server error: failed to allocate memory");
|
||||
return NULL;
|
||||
|
@ -90,7 +91,7 @@ wasm_launch_gdbserver(char *host, int port)
|
|||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr(host);
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_port = htons(*port);
|
||||
|
||||
ret = bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
|
@ -103,25 +104,12 @@ wasm_launch_gdbserver(char *host, int port)
|
|||
LOG_ERROR("%s", strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
LOG_WARNING("Debug server listening on %s:%d\n", host,
|
||||
ntohs(addr.sin_port));
|
||||
|
||||
LOG_WARNING("Listening on %s:%d\n", host, ntohs(addr.sin_port));
|
||||
|
||||
ret = listen(listen_fd, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("wasm gdb server error: listen() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*port = ntohs(addr.sin_port);
|
||||
server->listen_fd = listen_fd;
|
||||
|
||||
sockt_fd = accept(listen_fd, NULL, NULL);
|
||||
if (sockt_fd < 0) {
|
||||
LOG_ERROR("wasm gdb server error: accept() failed");
|
||||
goto fail;
|
||||
}
|
||||
LOG_VERBOSE("accept gdb client");
|
||||
server->socket_fd = sockt_fd;
|
||||
server->noack = false;
|
||||
return server;
|
||||
|
||||
fail:
|
||||
|
@ -134,6 +122,35 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_gdbserver_listen(WASMGDBServer *server)
|
||||
{
|
||||
int ret;
|
||||
int sockt_fd = 0;
|
||||
|
||||
ret = listen(server->listen_fd, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("wasm gdb server error: listen() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sockt_fd = accept(server->listen_fd, NULL, NULL);
|
||||
if (sockt_fd < 0) {
|
||||
LOG_ERROR("wasm gdb server error: accept() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LOG_VERBOSE("accept gdb client");
|
||||
server->socket_fd = sockt_fd;
|
||||
server->noack = false;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
shutdown(server->listen_fd, SHUT_RDWR);
|
||||
close(server->listen_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_close_gdbserver(WASMGDBServer *server)
|
||||
{
|
||||
|
|
|
@ -33,7 +33,10 @@ typedef struct WASMGDBServer {
|
|||
} WASMGDBServer;
|
||||
|
||||
WASMGDBServer *
|
||||
wasm_launch_gdbserver(char *addr, int port);
|
||||
wasm_create_gdbserver(char *addr, int *port);
|
||||
|
||||
bool
|
||||
wasm_gdbserver_listen(WASMGDBServer *server);
|
||||
|
||||
void
|
||||
wasm_close_gdbserver(WASMGDBServer *server);
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#define MAX_PACKET_SIZE (0x20000)
|
||||
static char tmpbuf[MAX_PACKET_SIZE];
|
||||
|
||||
static void
|
||||
send_thread_stop_status(WASMGDBServer *server, uint32_t status, uint64_t tid);
|
||||
|
||||
void
|
||||
handle_generay_set(WASMGDBServer *server, char *payload)
|
||||
{
|
||||
|
@ -261,6 +264,20 @@ handle_generay_query(WASMGDBServer *server, char *payload)
|
|||
if (args && (!strcmp(name, "WasmGlobal"))) {
|
||||
porcess_wasm_global(server, args);
|
||||
}
|
||||
|
||||
if (!strcmp(name, "Offsets")) {
|
||||
write_packet(server, "");
|
||||
}
|
||||
|
||||
if (!strncmp(name, "ThreadStopInfo", strlen("ThreadStopInfo"))) {
|
||||
int32 prefix_len = strlen("ThreadStopInfo");
|
||||
uint64 tid = strtol(name + prefix_len, NULL, 16);
|
||||
|
||||
uint32 status = wasm_debug_instance_get_thread_status(
|
||||
server->thread->debug_instance, tid);
|
||||
|
||||
send_thread_stop_status(server, status, tid);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -332,19 +349,32 @@ handle_v_packet(WASMGDBServer *server, char *payload)
|
|||
write_packet(server, "vCont;c;C;s;S;");
|
||||
|
||||
if (!strcmp("Cont", name)) {
|
||||
if (args && args[0] == 's') {
|
||||
char *numstring = strchr(args, ':');
|
||||
if (numstring) {
|
||||
*numstring++ = '\0';
|
||||
uint64_t tid = strtol(numstring, NULL, 16);
|
||||
wasm_debug_instance_set_cur_thread(
|
||||
(WASMDebugInstance *)server->thread->debug_instance, tid);
|
||||
wasm_debug_instance_singlestep(
|
||||
(WASMDebugInstance *)server->thread->debug_instance, tid);
|
||||
tid = wasm_debug_instance_wait_thread(
|
||||
(WASMDebugInstance *)server->thread->debug_instance, tid,
|
||||
&status);
|
||||
send_thread_stop_status(server, status, tid);
|
||||
if (args) {
|
||||
if (args[0] == 's' || args[0] == 'c') {
|
||||
char *numstring = strchr(args, ':');
|
||||
if (numstring) {
|
||||
*numstring++ = '\0';
|
||||
uint64_t tid = strtol(numstring, NULL, 16);
|
||||
wasm_debug_instance_set_cur_thread(
|
||||
(WASMDebugInstance *)server->thread->debug_instance,
|
||||
tid);
|
||||
|
||||
if (args[0] == 's') {
|
||||
wasm_debug_instance_singlestep(
|
||||
(WASMDebugInstance *)server->thread->debug_instance,
|
||||
tid);
|
||||
}
|
||||
else {
|
||||
wasm_debug_instance_continue(
|
||||
(WASMDebugInstance *)
|
||||
server->thread->debug_instance);
|
||||
}
|
||||
|
||||
tid = wasm_debug_instance_wait_thread(
|
||||
(WASMDebugInstance *)server->thread->debug_instance,
|
||||
tid, &status);
|
||||
send_thread_stop_status(server, status, tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -332,7 +332,7 @@ create_cluster_info(WASMCluster *cluster)
|
|||
if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) {
|
||||
return NULL;
|
||||
}
|
||||
memset(node, 0, sizeof(WASMCluster));
|
||||
memset(node, 0, sizeof(ClusterInfoNode));
|
||||
|
||||
node->thread_list = &node->thread_list_head;
|
||||
ret = bh_list_init(node->thread_list);
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
|
||||
#include "thread_manager.h"
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
#include "debug_engine.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
bh_list_link l;
|
||||
void (*destroy_cb)(WASMCluster *);
|
||||
|
@ -227,6 +231,11 @@ wasm_cluster_destroy(WASMCluster *cluster)
|
|||
wasm_runtime_free(cluster->stack_tops);
|
||||
if (cluster->stack_segment_occupied)
|
||||
wasm_runtime_free(cluster->stack_segment_occupied);
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_debug_instance_destroy(cluster);
|
||||
#endif
|
||||
|
||||
wasm_runtime_free(cluster);
|
||||
}
|
||||
|
||||
|
@ -488,31 +497,18 @@ wasm_cluster_create_exenv_status()
|
|||
WASMCurrentEnvStatus *status;
|
||||
|
||||
if (!(status = wasm_runtime_malloc(sizeof(WASMCurrentEnvStatus)))) {
|
||||
goto fail;
|
||||
return NULL;
|
||||
}
|
||||
if (os_mutex_init(&status->wait_lock) != 0)
|
||||
goto fail1;
|
||||
|
||||
if (os_cond_init(&status->wait_cond) != 0)
|
||||
goto fail2;
|
||||
status->step_count = 0;
|
||||
status->signal_flag = 0;
|
||||
status->running_status = 0;
|
||||
return status;
|
||||
|
||||
fail2:
|
||||
os_mutex_destroy(&status->wait_lock);
|
||||
fail1:
|
||||
wasm_runtime_free(status);
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status)
|
||||
{
|
||||
os_mutex_destroy(&status->wait_lock);
|
||||
os_cond_destroy(&status->wait_cond);
|
||||
wasm_runtime_free(status);
|
||||
}
|
||||
|
||||
|
@ -529,29 +525,34 @@ wasm_cluster_clear_thread_signal(WASMExecEnv *exec_env)
|
|||
exec_env->current_status->signal_flag = 0;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_wait_thread_status(WASMExecEnv *exec_env, uint32 *status)
|
||||
{
|
||||
os_mutex_lock(&exec_env->current_status->wait_lock);
|
||||
while (wasm_cluster_thread_is_running(exec_env)) {
|
||||
os_cond_wait(&exec_env->current_status->wait_cond,
|
||||
&exec_env->current_status->wait_lock);
|
||||
}
|
||||
*status = exec_env->current_status->signal_flag;
|
||||
os_mutex_unlock(&exec_env->current_status->wait_lock);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo)
|
||||
{
|
||||
exec_env->current_status->signal_flag = signo;
|
||||
}
|
||||
|
||||
static void
|
||||
notify_debug_instance(WASMExecEnv *exec_env)
|
||||
{
|
||||
WASMCluster *cluster;
|
||||
|
||||
cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster);
|
||||
|
||||
if (!cluster->debug_inst) {
|
||||
return;
|
||||
}
|
||||
|
||||
os_mutex_lock(&cluster->debug_inst->wait_lock);
|
||||
os_cond_signal(&cluster->debug_inst->wait_cond);
|
||||
os_mutex_unlock(&cluster->debug_inst->wait_lock);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_thread_stopped(WASMExecEnv *exec_env)
|
||||
{
|
||||
exec_env->current_status->running_status = STATUS_STOP;
|
||||
os_cond_signal(&exec_env->current_status->wait_cond);
|
||||
notify_debug_instance(exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -578,7 +579,7 @@ void
|
|||
wasm_cluster_thread_exited(WASMExecEnv *exec_env)
|
||||
{
|
||||
exec_env->current_status->running_status = STATUS_EXIT;
|
||||
os_cond_signal(&exec_env->current_status->wait_cond);
|
||||
notify_debug_instance(exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -595,7 +596,14 @@ wasm_cluster_thread_step(WASMExecEnv *exec_env)
|
|||
exec_env->current_status->running_status = STATUS_STEP;
|
||||
os_cond_signal(&exec_env->wait_cond);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst)
|
||||
{
|
||||
cluster->debug_inst = inst;
|
||||
}
|
||||
|
||||
#endif /* end of WASM_ENABLE_DEBUG_INTERP */
|
||||
|
||||
int32
|
||||
wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val)
|
||||
|
|
|
@ -39,6 +39,8 @@ typedef struct WASMCurrentEnvStatus {
|
|||
korp_cond wait_cond;
|
||||
} WASMCurrentEnvStatus;
|
||||
|
||||
typedef struct WASMDebugInstance WASMDebugInstance;
|
||||
|
||||
WASMCurrentEnvStatus *
|
||||
wasm_cluster_create_exenv_status();
|
||||
|
||||
|
@ -69,6 +71,9 @@ wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo);
|
|||
void
|
||||
wasm_cluster_thread_step(WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst);
|
||||
|
||||
#endif
|
||||
typedef struct WASMCluster {
|
||||
struct WASMCluster *next;
|
||||
|
@ -84,6 +89,9 @@ typedef struct WASMCluster {
|
|||
uint32 stack_size;
|
||||
/* Record which segments are occupied */
|
||||
bool *stack_segment_occupied;
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
WASMDebugInstance *debug_inst;
|
||||
#endif
|
||||
} WASMCluster;
|
||||
|
||||
void
|
||||
|
|
|
@ -146,6 +146,10 @@ Currently we only profile the memory consumption of module, module_instance and
|
|||
> Note: The WAMR application entry (`core/iwasm/common/wasm_application.c`) encapsulate some common process to instantiate, execute the wasm functions and print the results. Some platform related APIs are used in these functions, so you can enable this flag to exclude this file if your platform doesn't support those APIs.
|
||||
> *Don't enable this flag if you are building `product-mini`*
|
||||
|
||||
#### **Enable source debugging features**
|
||||
- **WAMR_BUILD_DEBUG_INTERP**=1/0, default to 0 if not set
|
||||
> Note: There are some other setup required by source debugging, please refer to [source_debugging.md](./source_debugging.md) for more details.
|
||||
|
||||
**Combination of configurations:**
|
||||
|
||||
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:
|
||||
|
|
|
@ -89,3 +89,51 @@ lldb-12 iwasm -- test.aot
|
|||
```
|
||||
|
||||
Then you can use lldb commands to debug both wamr runtime and your wasm application in ***current terminal***
|
||||
|
||||
## 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();
|
||||
```
|
||||
|
||||
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.
|
||||
|
|
14
doc/xip.md
Normal file
14
doc/xip.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# WAMR XIP (Execution In Place) feature introduction
|
||||
|
||||
Some IoT devices may require to run the AOT file from flash or ROM which is read-only, so as to reduce the memory consumption, or resolve the issue that there is no executable memory available to run AOT code. In such case, the AOT code inside the AOT file shouldn't be duplicated into memory and shouldn't be modified (or patched) by the AOT relocations. To address this, WAMR implements the XIP (Execution In Place) feature, which generates the AOT relocations as few as possible:
|
||||
- In the AOT code, an AOT function calls other functions with indirect mode: it doesn't call other functions directly, but looks up their pointers from the function pointer table passed by its first argument exec_env, and then calls the function pointer found. By this way the relocations to other functions are eliminated.
|
||||
- Eliminate the calls to the LLVM intrinsic functions, or, replace calling them with calling runtime self implemented functions instead, e.g. the calling to `llvm.experimental.constrained.fadd.f32` is replaced by the calling to `aot_intrinsic_fadd_f32`.
|
||||
|
||||
The XIP file is an AOT file without (or with few) relocations to patch the AOT code (or text section). Developer can use the option `--enable-indirect-mode --disable-llvm-intrinsics` for wamrc to generate the AOT file, e.g.:
|
||||
```bash
|
||||
wamrc --enable-indirect-mode --disable-llvm-intrinsics -o <aot_file> <wasm_file>
|
||||
```
|
||||
|
||||
## Known issues
|
||||
|
||||
There may be some relocations to the ".rodata" like sections which require to patch the AOT code. More work will be done to resolve it in the future.
|
|
@ -52,6 +52,8 @@ typedef struct EnclaveModule {
|
|||
uint32 wasi_env_list_size;
|
||||
char **wasi_argv;
|
||||
uint32 wasi_argc;
|
||||
bool is_xip_file;
|
||||
uint32 total_size_mapped;
|
||||
} EnclaveModule;
|
||||
|
||||
#if WASM_ENABLE_SPEC_TEST == 0
|
||||
|
@ -127,28 +129,57 @@ handle_cmd_load_module(uint64 *args, uint32 argc)
|
|||
uint32 error_buf_size = *(uint32 *)args++;
|
||||
uint64 total_size = sizeof(EnclaveModule) + (uint64)wasm_file_size;
|
||||
EnclaveModule *enclave_module;
|
||||
bool is_xip_file = false;
|
||||
|
||||
bh_assert(argc == 4);
|
||||
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(enclave_module =
|
||||
(EnclaveModule *)wasm_runtime_malloc((uint32)total_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"WASM module load failed: "
|
||||
"allocate memory failed.");
|
||||
*(void **)args_org = NULL;
|
||||
return;
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
is_xip_file = wasm_runtime_is_xip_file((uint8 *)wasm_file, wasm_file_size);
|
||||
#endif
|
||||
|
||||
if (!is_xip_file) {
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(enclave_module = (EnclaveModule *)wasm_runtime_malloc(
|
||||
(uint32)total_size))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"WASM module load failed: "
|
||||
"allocate memory failed.");
|
||||
*(void **)args_org = NULL;
|
||||
return;
|
||||
}
|
||||
memset(enclave_module, 0, (uint32)total_size);
|
||||
}
|
||||
else {
|
||||
int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC;
|
||||
int map_flags = MMAP_MAP_NONE;
|
||||
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(enclave_module = (EnclaveModule *)os_mmap(
|
||||
NULL, (uint32)total_size, map_prot, map_flags))) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"WASM module load failed: mmap memory failed.");
|
||||
*(void **)args_org = NULL;
|
||||
return;
|
||||
}
|
||||
memset(enclave_module, 0, (uint32)total_size);
|
||||
enclave_module->is_xip_file = true;
|
||||
enclave_module->total_size_mapped = (uint32)total_size;
|
||||
}
|
||||
|
||||
memset(enclave_module, 0, (uint32)total_size);
|
||||
enclave_module->wasm_file = (uint8 *)enclave_module + sizeof(EnclaveModule);
|
||||
bh_memcpy_s(enclave_module->wasm_file, wasm_file_size, wasm_file,
|
||||
wasm_file_size);
|
||||
if (is_xip_file) {
|
||||
enclave_module->is_xip_file = true;
|
||||
}
|
||||
|
||||
if (!(enclave_module->module =
|
||||
wasm_runtime_load(enclave_module->wasm_file, wasm_file_size,
|
||||
error_buf, error_buf_size))) {
|
||||
wasm_runtime_free(enclave_module);
|
||||
if (!is_xip_file)
|
||||
wasm_runtime_free(enclave_module);
|
||||
else
|
||||
os_munmap(enclave_module, (uint32)total_size);
|
||||
*(void **)args_org = NULL;
|
||||
return;
|
||||
}
|
||||
|
@ -170,7 +201,10 @@ handle_cmd_unload_module(uint64 *args, uint32 argc)
|
|||
wasm_runtime_free(enclave_module->wasi_arg_buf);
|
||||
|
||||
wasm_runtime_unload(enclave_module->module);
|
||||
wasm_runtime_free(enclave_module);
|
||||
if (!enclave_module->is_xip_file)
|
||||
wasm_runtime_free(enclave_module);
|
||||
else
|
||||
os_munmap(enclave_module, enclave_module->total_size_mapped);
|
||||
|
||||
LOG_VERBOSE("Unload module success.\n");
|
||||
}
|
||||
|
|
|
@ -34,8 +34,6 @@ print_help()
|
|||
printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n");
|
||||
printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n"
|
||||
" that runs commands in the form of \"FUNC ARG...\"\n");
|
||||
printf(" --xip Enable XIP (Execution In Place) mode to run AOT file\n"
|
||||
" generated with \"--enable-indirect-mode\" flag\n");
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
printf(" --env=<env> Pass wasi environment variables with \"key=value\"\n");
|
||||
printf(" to the program, for example:\n");
|
||||
|
@ -240,7 +238,7 @@ main(int argc, char *argv[])
|
|||
int log_verbose_level = 2;
|
||||
#endif
|
||||
bool is_repl_mode = false;
|
||||
bool is_xip_mode = false;
|
||||
bool is_xip_file = false;
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
const char *dir_list[8] = { NULL };
|
||||
uint32 dir_list_size = 0;
|
||||
|
@ -273,9 +271,6 @@ main(int argc, char *argv[])
|
|||
else if (!strcmp(argv[0], "--repl")) {
|
||||
is_repl_mode = true;
|
||||
}
|
||||
else if (!strcmp(argv[0], "--xip")) {
|
||||
is_xip_mode = true;
|
||||
}
|
||||
else if (!strncmp(argv[0], "--stack-size=", 13)) {
|
||||
if (argv[0][13] == '\0')
|
||||
return print_help();
|
||||
|
@ -392,10 +387,11 @@ main(int argc, char *argv[])
|
|||
(uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size)))
|
||||
goto fail1;
|
||||
|
||||
if (is_xip_mode) {
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (wasm_runtime_is_xip_file(wasm_file_buf, wasm_file_size)) {
|
||||
uint8 *wasm_file_mapped;
|
||||
int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC;
|
||||
int map_flags = MMAP_MAP_NONE;
|
||||
int map_flags = MMAP_MAP_32BIT;
|
||||
|
||||
if (!(wasm_file_mapped =
|
||||
os_mmap(NULL, (uint32)wasm_file_size, map_prot, map_flags))) {
|
||||
|
@ -408,7 +404,9 @@ main(int argc, char *argv[])
|
|||
wasm_file_size);
|
||||
wasm_runtime_free(wasm_file_buf);
|
||||
wasm_file_buf = wasm_file_mapped;
|
||||
is_xip_file = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer);
|
||||
|
@ -450,7 +448,7 @@ fail3:
|
|||
|
||||
fail2:
|
||||
/* free the file buffer */
|
||||
if (!is_xip_mode)
|
||||
if (!is_xip_file)
|
||||
wasm_runtime_free(wasm_file_buf);
|
||||
else
|
||||
os_munmap(wasm_file_buf, wasm_file_size);
|
||||
|
|
|
@ -51,6 +51,7 @@ def ignore_the_case(
|
|||
multi_module_flag=False,
|
||||
multi_thread_flag=False,
|
||||
simd_flag=False,
|
||||
xip_flag=False,
|
||||
):
|
||||
if case_name in ["comments", "inline-module", "names"]:
|
||||
return True
|
||||
|
@ -100,6 +101,7 @@ def test_case(
|
|||
multi_module_flag=False,
|
||||
multi_thread_flag=False,
|
||||
simd_flag=False,
|
||||
xip_flag=False,
|
||||
clean_up_flag=True,
|
||||
verbose_flag=True,
|
||||
):
|
||||
|
@ -114,6 +116,7 @@ def test_case(
|
|||
multi_module_flag,
|
||||
multi_thread_flag,
|
||||
simd_flag,
|
||||
xip_flag,
|
||||
):
|
||||
return True
|
||||
|
||||
|
@ -139,6 +142,9 @@ def test_case(
|
|||
if simd_flag:
|
||||
CMD.append("--simd")
|
||||
|
||||
if xip_flag:
|
||||
CMD.append("--xip")
|
||||
|
||||
if not clean_up_flag:
|
||||
CMD.append("--no_cleanup")
|
||||
|
||||
|
@ -195,6 +201,7 @@ def test_suite(
|
|||
multi_module_flag=False,
|
||||
multi_thread_flag=False,
|
||||
simd_flag=False,
|
||||
xip_flag=False,
|
||||
clean_up_flag=True,
|
||||
verbose_flag=True,
|
||||
):
|
||||
|
@ -217,6 +224,7 @@ def test_suite(
|
|||
multi_module_flag,
|
||||
multi_thread_flag,
|
||||
simd_flag,
|
||||
xip_flag,
|
||||
clean_up_flag,
|
||||
verbose_flag,
|
||||
)
|
||||
|
@ -239,6 +247,7 @@ def test_suite_parallelly(
|
|||
multi_module_flag=False,
|
||||
multi_thread_flag=False,
|
||||
simd_flag=False,
|
||||
xip_flag=False,
|
||||
clean_up_flag=False,
|
||||
verbose_flag=False,
|
||||
):
|
||||
|
@ -266,6 +275,7 @@ def test_suite_parallelly(
|
|||
multi_module_flag,
|
||||
multi_thread_flag,
|
||||
simd_flag,
|
||||
xip_flag,
|
||||
clean_up_flag,
|
||||
verbose_flag,
|
||||
],
|
||||
|
@ -323,6 +333,13 @@ def main():
|
|||
dest="simd_flag",
|
||||
help="Running with the SIMD feature",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-X",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="xip_flag",
|
||||
help="Running with the XIP feature",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
action="store_true",
|
||||
|
@ -387,6 +404,7 @@ def main():
|
|||
options.multi_module_flag,
|
||||
options.multi_thread_flag,
|
||||
options.simd_flag,
|
||||
options.xip_flag,
|
||||
options.clean_up_flag,
|
||||
options.verbose_flag,
|
||||
)
|
||||
|
@ -403,6 +421,7 @@ def main():
|
|||
options.multi_module_flag,
|
||||
options.multi_thread_flag,
|
||||
options.simd_flag,
|
||||
options.xip_flag,
|
||||
options.clean_up_flag,
|
||||
options.verbose_flag,
|
||||
)
|
||||
|
@ -419,6 +438,7 @@ def main():
|
|||
options.multi_module_flag,
|
||||
options.multi_thread_flag,
|
||||
options.simd_flag,
|
||||
options.xip_flag,
|
||||
options.clean_up_flag,
|
||||
options.verbose_flag,
|
||||
)
|
||||
|
|
|
@ -210,6 +210,9 @@ parser.add_argument('--sgx', action='store_true',
|
|||
parser.add_argument('--simd', default=False, action='store_true',
|
||||
help="Enable SIMD")
|
||||
|
||||
parser.add_argument('--xip', default=False, action='store_true',
|
||||
help="Enable XIP")
|
||||
|
||||
parser.add_argument('--multi-thread', default=False, action='store_true',
|
||||
help="Enable Multi-thread")
|
||||
|
||||
|
@ -942,6 +945,10 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r):
|
|||
if not opts.simd:
|
||||
cmd.append("--disable-simd")
|
||||
|
||||
if opts.xip:
|
||||
cmd.append("--enable-indirect-mode")
|
||||
cmd.append("--disable-llvm-intrinsics")
|
||||
|
||||
if opts.multi_thread:
|
||||
cmd.append("--enable-multi-thread")
|
||||
|
||||
|
|
|
@ -17,10 +17,11 @@ function help()
|
|||
echo "-s {suite_name} test only one suite (spec)"
|
||||
echo "-m set compile target of iwasm(x86_64\x86_32\armv7_vfp\thumbv7_vfp\riscv64_lp64d\riscv64_lp64)"
|
||||
echo "-t set compile type of iwasm(classic-interp\fast-interp\jit\aot)"
|
||||
echo "-M enable the multi module feature"
|
||||
echo "-M enable multi module feature"
|
||||
echo "-p enable multi thread feature"
|
||||
echo "-S enable SIMD feature"
|
||||
echo "-G enable GC feature"
|
||||
echo "-X enable XIP feature"
|
||||
echo "-x test SGX"
|
||||
echo "-b use the wabt binary release package instead of compiling from the source code"
|
||||
echo "-P run the spec test parallelly"
|
||||
|
@ -37,13 +38,14 @@ ENABLE_MULTI_THREAD=0
|
|||
COLLECT_CODE_COVERAGE=0
|
||||
ENABLE_SIMD=0
|
||||
ENABLE_GC=0
|
||||
ENABLE_XIP=0
|
||||
#unit test case arrary
|
||||
TEST_CASE_ARR=()
|
||||
SGX_OPT=""
|
||||
PLATFORM=$(uname -s | tr A-Z a-z)
|
||||
PARALLELISM=0
|
||||
|
||||
while getopts ":s:cabt:m:MCpSxPG" opt
|
||||
while getopts ":s:cabt:m:MCpSXxPG" opt
|
||||
do
|
||||
OPT_PARSED="TRUE"
|
||||
case $opt in
|
||||
|
@ -108,6 +110,10 @@ do
|
|||
echo "enable SIMD feature"
|
||||
ENABLE_SIMD=1
|
||||
;;
|
||||
X)
|
||||
echo "enable XIP feature"
|
||||
ENABLE_XIP=1
|
||||
;;
|
||||
x)
|
||||
echo "test SGX"
|
||||
SGX_OPT="--sgx"
|
||||
|
@ -403,7 +409,11 @@ function spec_test()
|
|||
fi
|
||||
|
||||
if [[ ${ENABLE_MULTI_THREAD} == 1 ]]; then
|
||||
ARGS_FOR_SPEC_TEST+="-p "
|
||||
ARGS_FOR_SPEC_TEST+="-p "
|
||||
fi
|
||||
|
||||
if [[ ${ENABLE_XIP} == 1 ]]; then
|
||||
ARGS_FOR_SPEC_TEST+="-X "
|
||||
fi
|
||||
|
||||
# require warmc only in aot mode
|
||||
|
|
Loading…
Reference in New Issue
Block a user