From fbcf8c2c60b32ade99881a0d42c93c13b6911c9c Mon Sep 17 00:00:00 2001 From: Xu Jun Date: Tue, 18 Jul 2023 16:06:21 +0800 Subject: [PATCH 01/30] Fix some static scan issues (#2362) --- core/iwasm/interpreter/wasm_loader.c | 9 +++++---- core/iwasm/interpreter/wasm_runtime.c | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 1ce4aab0..f1a71a8a 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -7014,6 +7014,7 @@ static bool copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, char *error_buf, uint32 error_buf_size) { + bool ret = false; int16 *frame_offset = NULL; uint8 *cells = NULL, cell; int16 *src_offsets = NULL; @@ -7084,13 +7085,13 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, if (is_if_block) PUSH_OFFSET_TYPE(VALUE_TYPE_I32); + ret = true; + +fail: /* Free the emit data */ wasm_runtime_free(emit_data); - return true; - -fail: - return false; + return ret; } #endif diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 5b441dc8..00f0cf66 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1104,10 +1104,14 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst, goto fail; } +#if WASM_ENABLE_LIBC_WASI != 0 if (initialize_func && !wasm_call_function(exec_env, initialize_func, 0, NULL)) { goto fail; } +#else + (void)initialize_func; +#endif if (post_inst_func && !wasm_call_function(exec_env, post_inst_func, 0, NULL)) { From 57abdfdb5c19dab7c2f2a126082910f65ffc7af0 Mon Sep 17 00:00:00 2001 From: Cengizhan Pasaoglu Date: Wed, 19 Jul 2023 12:58:52 +0300 Subject: [PATCH 02/30] Fix typo (dwarf) in the codebase (#2367) In the codebase, the struct and functions were written without "f" for dwarf. --- core/iwasm/compilation/aot.h | 4 +-- .../compilation/debug/dwarf_extractor.cpp | 32 +++++++++---------- .../iwasm/compilation/debug/dwarf_extractor.h | 4 +-- core/iwasm/include/aot_export.h | 4 +-- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 02b146cb..08846063 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -43,7 +43,7 @@ typedef WASMType AOTFuncType; typedef WASMExport AOTExport; #if WASM_ENABLE_DEBUG_AOT != 0 -typedef void *dwar_extractor_handle_t; +typedef void *dwarf_extractor_handle_t; #endif typedef enum AOTIntCond { @@ -285,7 +285,7 @@ typedef struct AOTCompData { WASMModule *wasm_module; #if WASM_ENABLE_DEBUG_AOT != 0 - dwar_extractor_handle_t extractor; + dwarf_extractor_handle_t extractor; #endif } AOTCompData; diff --git a/core/iwasm/compilation/debug/dwarf_extractor.cpp b/core/iwasm/compilation/debug/dwarf_extractor.cpp index 160aadee..99182f82 100644 --- a/core/iwasm/compilation/debug/dwarf_extractor.cpp +++ b/core/iwasm/compilation/debug/dwarf_extractor.cpp @@ -28,25 +28,25 @@ using namespace lldb; -typedef struct dwar_extractor { +typedef struct dwarf_extractor { SBDebugger debugger; SBTarget target; SBModule module; -} dwar_extractor; +} dwarf_extractor; -#define TO_HANDLE(extractor) (dwar_extractor_handle_t)(extractor) +#define TO_HANDLE(extractor) (dwarf_extractor_handle_t)(extractor) -#define TO_EXTACTOR(handle) (dwar_extractor *)(handle) +#define TO_EXTACTOR(handle) (dwarf_extractor *)(handle) static bool is_debugger_initialized; -dwar_extractor_handle_t +dwarf_extractor_handle_t create_dwarf_extractor(AOTCompData *comp_data, char *file_name) { char *arch = NULL; char *platform = NULL; - dwar_extractor *extractor = NULL; + dwarf_extractor *extractor = NULL; //__attribute__((constructor)) may be better? if (!is_debugger_initialized) { @@ -61,7 +61,7 @@ create_dwarf_extractor(AOTCompData *comp_data, char *file_name) SBError error; SBFileSpec exe_file_spec(file_name, true); - if (!(extractor = new dwar_extractor())) { + if (!(extractor = new dwarf_extractor())) { LOG_ERROR("Create Dwarf Extractor error: failed to allocate memory"); goto fail3; } @@ -101,9 +101,9 @@ fail3: } void -destroy_dwarf_extractor(dwar_extractor_handle_t handle) +destroy_dwarf_extractor(dwarf_extractor_handle_t handle) { - dwar_extractor *extractor = TO_EXTACTOR(handle); + dwarf_extractor *extractor = TO_EXTACTOR(handle); if (!extractor) return; extractor->debugger.DeleteTarget(extractor->target); @@ -116,7 +116,7 @@ destroy_dwarf_extractor(dwar_extractor_handle_t handle) LLVMMetadataRef dwarf_gen_file_info(const AOTCompContext *comp_ctx) { - dwar_extractor *extractor; + dwarf_extractor *extractor; int units_number; LLVMMetadataRef file_info = NULL; const char *file_name; @@ -193,7 +193,7 @@ dwarf_gen_mock_vm_info(AOTCompContext *comp_ctx) LLVMMetadataRef dwarf_gen_comp_unit_info(const AOTCompContext *comp_ctx) { - dwar_extractor *extractor; + dwarf_extractor *extractor; int units_number; LLVMMetadataRef comp_unit = NULL; @@ -292,7 +292,7 @@ lldb_function_to_function_dbi(const AOTCompContext *comp_ctx, SBTypeList function_args = function.GetType().GetFunctionArgumentTypes(); SBType return_type = function.GetType().GetFunctionReturnType(); const size_t num_function_args = function_args.GetSize(); - dwar_extractor *extractor; + dwarf_extractor *extractor; if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor))) return NULL; @@ -393,7 +393,7 @@ dwarf_gen_func_info(const AOTCompContext *comp_ctx, const AOTFuncContext *func_ctx) { LLVMMetadataRef func_info = NULL; - dwar_extractor *extractor; + dwarf_extractor *extractor; uint64_t vm_offset; AOTFunc *func = func_ctx->aot_func; @@ -423,7 +423,7 @@ dwarf_get_func_name(const AOTCompContext *comp_ctx, const AOTFuncContext *func_ctx, char *name, int len) { LLVMMetadataRef func_info = NULL; - dwar_extractor *extractor; + dwarf_extractor *extractor; uint64_t vm_offset; AOTFunc *func = func_ctx->aot_func; @@ -454,7 +454,7 @@ dwarf_gen_location(const AOTCompContext *comp_ctx, const AOTFuncContext *func_ctx, uint64_t vm_offset) { LLVMMetadataRef location_info = NULL; - dwar_extractor *extractor; + dwarf_extractor *extractor; AOTFunc *func = func_ctx->aot_func; if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor))) @@ -493,7 +493,7 @@ dwarf_gen_func_ret_location(const AOTCompContext *comp_ctx, const AOTFuncContext *func_ctx) { LLVMMetadataRef func_info = NULL; - dwar_extractor *extractor; + dwarf_extractor *extractor; uint64_t vm_offset; AOTFunc *func = func_ctx->aot_func; LLVMMetadataRef location_info = NULL; diff --git a/core/iwasm/compilation/debug/dwarf_extractor.h b/core/iwasm/compilation/debug/dwarf_extractor.h index c48e8f5c..0bacb97f 100644 --- a/core/iwasm/compilation/debug/dwarf_extractor.h +++ b/core/iwasm/compilation/debug/dwarf_extractor.h @@ -18,7 +18,7 @@ typedef unsigned int LLDBLangType; struct AOTCompData; typedef struct AOTCompData *aot_comp_data_t; -typedef void *dwar_extractor_handle_t; +typedef void *dwarf_extractor_handle_t; struct AOTCompContext; typedef struct AOTCompContext AOTCompContext; @@ -26,7 +26,7 @@ typedef struct AOTCompContext AOTCompContext; struct AOTFuncContext; typedef struct AOTFuncContext AOTFuncContext; -dwar_extractor_handle_t +dwarf_extractor_handle_t create_dwarf_extractor(aot_comp_data_t comp_data, char *file_name); LLVMMetadataRef diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 09765ad7..ce8ae81f 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -26,8 +26,8 @@ void aot_destroy_comp_data(aot_comp_data_t comp_data); #if WASM_ENABLE_DEBUG_AOT != 0 -typedef void *dwar_extractor_handle_t; -dwar_extractor_handle_t +typedef void *dwarf_extractor_handle_t; +dwarf_extractor_handle_t create_dwarf_extractor(aot_comp_data_t comp_data, char *file_name); #endif From fbe072c0d34f1900a93931f963ff2c8276381367 Mon Sep 17 00:00:00 2001 From: dongsheng28849455 <68947925+dongsheng28849455@users.noreply.github.com> Date: Fri, 21 Jul 2023 07:54:13 +0800 Subject: [PATCH 03/30] Bring up WAMR on esp32-s3 device (#2348) esp32-s3's instruction memory and data memory can be accessed through mutual mirroring way, so we define a new feature named as WASM_MEM_DUAL_BUS_MIRROR. --- core/config.h | 11 +++ core/iwasm/aot/aot_loader.c | 12 +++ core/iwasm/aot/arch/aot_reloc_xtensa.c | 10 ++- .../platform/include/platform_api_vmcore.h | 5 ++ core/shared/platform/nuttx/nuttx_platform.c | 81 ++++++++++++++++++- product-mini/platforms/nuttx/wamr.mk | 6 ++ 6 files changed, 122 insertions(+), 3 deletions(-) diff --git a/core/config.h b/core/config.h index f33290f0..b6198811 100644 --- a/core/config.h +++ b/core/config.h @@ -461,4 +461,15 @@ #define WASM_CONFIGURABLE_BOUNDS_CHECKS 0 #endif +/* Some chip cannot support external ram with rwx attr at the same time, + it has to map it into 2 spaces of idbus and dbus, code in dbus can be + read/written and read/executed in ibus. so there are 2 steps to execute + the code, first, copy&do relocaiton in dbus space, and second execute + it in ibus space, since in the 2 spaces the contents are the same, + so we call it bus mirror. + */ +#ifndef WASM_MEM_DUAL_BUS_MIRROR +#define WASM_MEM_DUAL_BUS_MIRROR 0 +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 2f4dcd31..50e36f9e 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -3013,6 +3013,9 @@ create_sections(AOTModule *module, const uint8 *buf, uint32 size, uint32 section_size; uint64 total_size; uint8 *aot_text; +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + uint8 *mirrored_text; +#endif if (!resolve_execute_mode(buf, size, &is_indirect_mode, error_buf, error_buf_size)) { @@ -3071,8 +3074,17 @@ create_sections(AOTModule *module, const uint8 *buf, uint32 size, bh_assert((uintptr_t)aot_text < INT32_MAX); #endif #endif + +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + mirrored_text = os_get_dbus_mirror(aot_text); + bh_assert(mirrored_text != NULL); + bh_memcpy_s(mirrored_text, (uint32)total_size, + section->section_body, (uint32)section_size); + os_dcache_flush(); +#else bh_memcpy_s(aot_text, (uint32)total_size, section->section_body, (uint32)section_size); +#endif section->section_body = aot_text; destroy_aot_text = true; diff --git a/core/iwasm/aot/arch/aot_reloc_xtensa.c b/core/iwasm/aot/arch/aot_reloc_xtensa.c index 3327c396..6ca6a085 100644 --- a/core/iwasm/aot/arch/aot_reloc_xtensa.c +++ b/core/iwasm/aot/arch/aot_reloc_xtensa.c @@ -207,6 +207,10 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, case R_XTENSA_32: { uint8 *insn_addr = target_section_addr + reloc_offset; +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + insn_addr = os_get_dbus_mirror((void *)insn_addr); + bh_assert(insn_addr != NULL); +#endif int32 initial_addend; /* (S + A) */ if ((intptr_t)insn_addr & 3) { @@ -265,6 +269,11 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, return false; } +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + insn_addr = os_get_dbus_mirror((void *)insn_addr); + bh_assert(insn_addr != NULL); + l32r_insn = (l32r_insn_t *)insn_addr; +#endif imm16 = (int16)(relative_offset >> 2); /* write back the imm16 to the l32r instruction */ @@ -285,7 +294,6 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, #if __GNUC__ >= 9 #pragma GCC diagnostic pop #endif - break; } diff --git a/core/shared/platform/include/platform_api_vmcore.h b/core/shared/platform/include/platform_api_vmcore.h index c2f03c9e..15fc1d38 100644 --- a/core/shared/platform/include/platform_api_vmcore.h +++ b/core/shared/platform/include/platform_api_vmcore.h @@ -129,6 +129,11 @@ os_munmap(void *addr, size_t size); int os_mprotect(void *addr, size_t size, int prot); +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) +void * +os_get_dbus_mirror(void *ibus); +#endif + /** * Flush cpu data cache, in some CPUs, after applying relocation to the * AOT code, the code may haven't been written back to the cpu data cache, diff --git a/core/shared/platform/nuttx/nuttx_platform.c b/core/shared/platform/nuttx/nuttx_platform.c index 9cb123e0..0bd1f680 100644 --- a/core/shared/platform/nuttx/nuttx_platform.c +++ b/core/shared/platform/nuttx/nuttx_platform.c @@ -10,6 +10,46 @@ #include #endif +#if defined(CONFIG_ARCH_CHIP_ESP32S3) +/* + * TODO: Move these methods below the operating system level + */ +#define MEM_DUAL_BUS_OFFSET (0x42000000 - 0x3C000000) +#define IRAM0_CACHE_ADDRESS_LOW 0x42000000 +#define IRAM0_CACHE_ADDRESS_HIGH 0x44000000 +#define IRAM_ATTR locate_data(".iram1") + +#define in_ibus_ext(addr) \ + (((uint32)addr >= IRAM0_CACHE_ADDRESS_LOW) \ + && ((uint32)addr < IRAM0_CACHE_ADDRESS_HIGH)) +void IRAM_ATTR +bus_sync(void) +{ + extern void cache_writeback_all(void); + extern uint32_t Cache_Disable_ICache(void); + extern void Cache_Enable_ICache(uint32_t autoload); + + irqstate_t flags; + uint32_t preload; + + flags = enter_critical_section(); + + cache_writeback_all(); + preload = Cache_Disable_ICache(); + Cache_Enable_ICache(preload); + + leave_critical_section(flags); +} +#else +#define MEM_DUAL_BUS_OFFSET (0) +#define IRAM0_CACHE_ADDRESS_LOW (0) +#define IRAM0_CACHE_ADDRESS_HIGH (0) +#define in_ibus_ext(addr) (0) +static void +bus_sync(void) +{} +#endif + int bh_platform_init() { @@ -47,6 +87,10 @@ os_dumps_proc_mem_info(char *out, unsigned int size) void * os_mmap(void *hint, size_t size, int prot, int flags) { +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + void *i_addr, *d_addr; +#endif + #if defined(CONFIG_ARCH_USE_TEXT_HEAP) if ((prot & MMAP_PROT_EXEC) != 0) { return up_textheap_memalign(sizeof(void *), size); @@ -55,6 +99,17 @@ os_mmap(void *hint, size_t size, int prot, int flags) if ((uint64)size >= UINT32_MAX) return NULL; + +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + if ((prot & MMAP_PROT_EXEC) != 0) { + d_addr = malloc((uint32)size); + if (d_addr == NULL) { + return NULL; + } + i_addr = (void *)((uint8 *)d_addr + MEM_DUAL_BUS_OFFSET); + return in_ibus_ext(i_addr) ? i_addr : d_addr; + } +#endif return malloc((uint32)size); } @@ -67,7 +122,14 @@ os_munmap(void *addr, size_t size) return; } #endif - return free(addr); + +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + if (in_ibus_ext(addr)) { + free((void *)((uint8 *)addr - MEM_DUAL_BUS_OFFSET)); + return; + } +#endif + free(addr); } int @@ -78,7 +140,22 @@ os_mprotect(void *addr, size_t size, int prot) void os_dcache_flush() -{} +{ + bus_sync(); +} + +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) +void * +os_get_dbus_mirror(void *ibus) +{ + if (in_ibus_ext(ibus)) { + return (void *)((uint8 *)ibus - MEM_DUAL_BUS_OFFSET); + } + else { + return ibus; + } +} +#endif /* If AT_FDCWD is provided, maybe we have openat family */ #if !defined(AT_FDCWD) diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 1844dc54..2a0cec58 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -141,6 +141,12 @@ else CFLAGS += -DWASM_ENABLE_WORD_ALIGN_READ=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_MEM_DUAL_BUS_MIRROR),y) +CFLAGS += -DWASM_MEM_DUAL_BUS_MIRROR=1 +else +CFLAGS += -DWASM_MEM_DUAL_BUS_MIRROR=0 +endif + ifeq ($(CONFIG_INTERPRETERS_WAMR_FAST), y) CFLAGS += -DWASM_ENABLE_FAST_INTERP=1 CFLAGS += -DWASM_ENABLE_INTERP=1 From 0f4edf97359d8005fc2eb092a4fe908ffddcfd04 Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Fri, 21 Jul 2023 01:27:09 +0100 Subject: [PATCH 04/30] Implement suspend flags as atomic variable (#2361) We have observed a significant performance degradation after merging https://github.com/bytecodealliance/wasm-micro-runtime/pull/1991 Instead of protecting suspend flags with a mutex, we implement the flags as atomic variable and only use mutex when atomics are not available on a given platform. --- core/iwasm/common/wasm_exec_env.h | 12 +-- core/iwasm/common/wasm_suspend_flags.h | 74 +++++++++++++++++++ core/iwasm/interpreter/wasm_interp_classic.c | 45 +++++++---- core/iwasm/interpreter/wasm_interp_fast.c | 23 +++--- .../lib-pthread/lib_pthread_wrapper.c | 3 +- .../libraries/thread-mgr/thread_manager.c | 22 ++++-- core/shared/utils/bh_platform.h | 1 + .../src => shared/utils}/gnuc.h | 0 8 files changed, 135 insertions(+), 45 deletions(-) create mode 100644 core/iwasm/common/wasm_suspend_flags.h rename core/{iwasm/libraries/libc-wasi/sandboxed-system-primitives/src => shared/utils}/gnuc.h (100%) diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 29b28a15..bf989208 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -7,6 +7,7 @@ #define _WASM_EXEC_ENV_H #include "bh_assert.h" +#include "wasm_suspend_flags.h" #if WASM_ENABLE_INTERP != 0 #include "../interpreter/wasm.h" #endif @@ -57,15 +58,8 @@ typedef struct WASMExecEnv { exception. */ uint8 *native_stack_boundary; - /* Used to terminate or suspend current thread - bit 0: need to terminate - bit 1: need to suspend - bit 2: need to go into breakpoint - bit 3: return from pthread_exit */ - union { - uint32 flags; - uintptr_t __padding__; - } suspend_flags; + /* Used to terminate or suspend current thread */ + WASMSuspendFlags suspend_flags; /* Auxiliary stack boundary */ union { diff --git a/core/iwasm/common/wasm_suspend_flags.h b/core/iwasm/common/wasm_suspend_flags.h new file mode 100644 index 00000000..0558eaf6 --- /dev/null +++ b/core/iwasm/common/wasm_suspend_flags.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_SUSPEND_FLAGS_H +#define _WASM_SUSPEND_FLAGS_H + +#include "bh_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Need to terminate */ +#define WASM_SUSPEND_FLAG_TERMINATE 0x1 +/* Need to suspend */ +#define WASM_SUSPEND_FLAG_SUSPEND 0x2 +/* Need to go into breakpoint */ +#define WASM_SUSPEND_FLAG_BREAKPOINT 0x4 +/* Return from pthread_exit */ +#define WASM_SUSPEND_FLAG_EXIT 0x8 + +typedef union WASMSuspendFlags { + uint32 flags; + uintptr_t __padding__; +} WASMSuspendFlags; + +#if defined(__GNUC_PREREQ) +#if __GNUC_PREREQ(4, 7) +#define CLANG_GCC_HAS_ATOMIC_BUILTIN +#endif +#elif defined(__clang__) +#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 0) +#define CLANG_GCC_HAS_ATOMIC_BUILTIN +#endif +#endif + +#if defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) +#define WASM_SUSPEND_FLAGS_IS_ATOMIC 1 +#define WASM_SUSPEND_FLAGS_GET(s_flags) \ + __atomic_load_n(&s_flags.flags, __ATOMIC_SEQ_CST) +#define WASM_SUSPEND_FLAGS_FETCH_OR(s_flags, val) \ + __atomic_fetch_or(&s_flags.flags, val, __ATOMIC_SEQ_CST) +#define WASM_SUSPEND_FLAGS_FETCH_AND(s_flags, val) \ + __atomic_fetch_and(&s_flags.flags, val, __ATOMIC_SEQ_CST) +#else /* else of defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) */ +#define WASM_SUSPEND_FLAGS_GET(s_flags) (s_flags.flags) +#define WASM_SUSPEND_FLAGS_FETCH_OR(s_flags, val) (s_flags.flags |= val) +#define WASM_SUSPEND_FLAGS_FETCH_AND(s_flags, val) (s_flags.flags &= val) + +/* The flag can be defined by the user if the platform + supports atomic access to uint32 aligned memory. */ +#ifdef WASM_UINT32_IS_ATOMIC +#define WASM_SUSPEND_FLAGS_IS_ATOMIC 1 +#else /* else of WASM_UINT32_IS_ATOMIC */ +#define WASM_SUSPEND_FLAGS_IS_ATOMIC 0 +#endif /* WASM_UINT32_IS_ATOMIC */ + +#endif + +#if WASM_SUSPEND_FLAGS_IS_ATOMIC != 0 +#define WASM_SUSPEND_FLAGS_LOCK(lock) (void)0 +#define WASM_SUSPEND_FLAGS_UNLOCK(lock) (void)0 +#else /* else of WASM_SUSPEND_FLAGS_IS_ATOMIC */ +#define WASM_SUSPEND_FLAGS_LOCK(lock) os_mutex_lock(&lock) +#define WASM_SUSPEND_FLAGS_UNLOCK(lock) os_mutex_unlock(&lock); +#endif /* WASM_SUSPEND_FLAGS_IS_ATOMIC */ + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_SUSPEND_FLAGS_H */ \ No newline at end of file diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 69037b59..55fca292 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1062,21 +1062,33 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, os_mutex_unlock(&exec_env->wait_lock); \ } while (0) #else -#define CHECK_SUSPEND_FLAGS() \ - do { \ - os_mutex_lock(&exec_env->wait_lock); \ - if (exec_env->suspend_flags.flags != 0) { \ - if (exec_env->suspend_flags.flags & 0x01) { \ - /* terminate current thread */ \ - os_mutex_unlock(&exec_env->wait_lock); \ - return; \ - } \ - while (exec_env->suspend_flags.flags & 0x02) { \ - /* suspend current thread */ \ - os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \ - } \ - } \ - os_mutex_unlock(&exec_env->wait_lock); \ +#if WASM_SUSPEND_FLAGS_IS_ATOMIC != 0 +/* The lock is only needed when the suspend_flags is atomic; otherwise + the lock is already taken at the time when SUSPENSION_LOCK() is called. */ +#define SUSPENSION_LOCK() os_mutex_lock(&exec_env->wait_lock); +#define SUSPENSION_UNLOCK() os_mutex_unlock(&exec_env->wait_lock); +#else +#define SUSPENSION_LOCK() +#define SUSPENSION_UNLOCK() +#endif + +#define CHECK_SUSPEND_FLAGS() \ + do { \ + WASM_SUSPEND_FLAGS_LOCK(exec_env->wait_lock); \ + if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \ + & WASM_SUSPEND_FLAG_TERMINATE) { \ + /* terminate current thread */ \ + WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \ + return; \ + } \ + while (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \ + & WASM_SUSPEND_FLAG_SUSPEND) { \ + /* suspend current thread */ \ + SUSPENSION_LOCK() \ + os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \ + SUSPENSION_UNLOCK() \ + } \ + WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \ } while (0) #endif /* WASM_ENABLE_DEBUG_INTERP */ #endif /* WASM_ENABLE_THREAD_MGR */ @@ -3783,7 +3795,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(DEBUG_OP_BREAK) { wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP); - exec_env->suspend_flags.flags |= 2; + WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags, + WASM_SUSPEND_FLAG_SUSPEND); frame_ip--; SYNC_ALL_TO_FRAME(); CHECK_SUSPEND_FLAGS(); diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 40a7d38c..070fcdbe 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1065,18 +1065,17 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, #endif #if WASM_ENABLE_THREAD_MGR != 0 -#define CHECK_SUSPEND_FLAGS() \ - do { \ - os_mutex_lock(&exec_env->wait_lock); \ - if (exec_env->suspend_flags.flags != 0) { \ - if (exec_env->suspend_flags.flags & 0x01) { \ - /* terminate current thread */ \ - os_mutex_unlock(&exec_env->wait_lock); \ - return; \ - } \ - /* TODO: support suspend and breakpoint */ \ - } \ - os_mutex_unlock(&exec_env->wait_lock); \ +#define CHECK_SUSPEND_FLAGS() \ + do { \ + WASM_SUSPEND_FLAGS_LOCK(exec_env->wait_lock); \ + if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) \ + & WASM_SUSPEND_FLAG_TERMINATE) { \ + /* terminate current thread */ \ + WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \ + return; \ + } \ + /* TODO: support suspend and breakpoint */ \ + WASM_SUSPEND_FLAGS_UNLOCK(exec_env->wait_lock); \ } while (0) #endif diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 206479c2..8876d51b 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -531,7 +531,8 @@ pthread_start_routine(void *arg) else { info_node->u.ret = (void *)(uintptr_t)argv[0]; #ifdef OS_ENABLE_HW_BOUND_CHECK - if (exec_env->suspend_flags.flags & 0x08) + if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) + & WASM_SUSPEND_FLAG_EXIT) /* argv[0] isn't set after longjmp(1) to invoke_native_with_hw_bound_check */ info_node->u.ret = exec_env->thread_ret_value; diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 9303eb3f..fc44652e 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -606,7 +606,8 @@ thread_manager_start_routine(void *arg) #ifdef OS_ENABLE_HW_BOUND_CHECK os_mutex_lock(&exec_env->wait_lock); - if (exec_env->suspend_flags.flags & 0x08) + if (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) + & WASM_SUSPEND_FLAG_EXIT) ret = exec_env->thread_ret_value; os_mutex_unlock(&exec_env->wait_lock); #endif @@ -993,7 +994,9 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) if (exec_env->jmpbuf_stack_top) { /* Store the return value in exec_env */ exec_env->thread_ret_value = retval; - exec_env->suspend_flags.flags |= 0x08; + + WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags, + WASM_SUSPEND_FLAG_EXIT); #ifndef BH_PLATFORM_WINDOWS /* Pop all jmpbuf_node except the last one */ @@ -1055,7 +1058,8 @@ set_thread_cancel_flags(WASMExecEnv *exec_env) #if WASM_ENABLE_DEBUG_INTERP != 0 wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); #endif - exec_env->suspend_flags.flags |= 0x01; + WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags, + WASM_SUSPEND_FLAG_TERMINATE); os_mutex_unlock(&exec_env->wait_lock); } @@ -1178,7 +1182,8 @@ void wasm_cluster_suspend_thread(WASMExecEnv *exec_env) { /* Set the suspend flag */ - exec_env->suspend_flags.flags |= 0x02; + WASM_SUSPEND_FLAGS_FETCH_OR(exec_env->suspend_flags, + WASM_SUSPEND_FLAG_SUSPEND); } static void @@ -1214,7 +1219,8 @@ wasm_cluster_suspend_all_except_self(WASMCluster *cluster, void wasm_cluster_resume_thread(WASMExecEnv *exec_env) { - exec_env->suspend_flags.flags &= ~0x02; + WASM_SUSPEND_FLAGS_FETCH_AND(exec_env->suspend_flags, + ~WASM_SUSPEND_FLAG_SUSPEND); os_cond_signal(&exec_env->wait_cond); } @@ -1343,8 +1349,10 @@ bool wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env) { os_mutex_lock(&exec_env->wait_lock); - bool is_thread_terminated = - (exec_env->suspend_flags.flags & 0x01) ? true : false; + bool is_thread_terminated = (WASM_SUSPEND_FLAGS_GET(exec_env->suspend_flags) + & WASM_SUSPEND_FLAG_TERMINATE) + ? true + : false; os_mutex_unlock(&exec_env->wait_lock); return is_thread_terminated; diff --git a/core/shared/utils/bh_platform.h b/core/shared/utils/bh_platform.h index 86aef839..9821d710 100644 --- a/core/shared/utils/bh_platform.h +++ b/core/shared/utils/bh_platform.h @@ -16,6 +16,7 @@ #include "bh_log.h" #include "bh_queue.h" #include "bh_vector.h" +#include "gnuc.h" #include "runtime_timer.h" /** diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h b/core/shared/utils/gnuc.h similarity index 100% rename from core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h rename to core/shared/utils/gnuc.h From 24c6c6977ba1d7fcbcb09c4b3fcfaea2ed0527fe Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 24 Jul 2023 15:15:48 +0800 Subject: [PATCH 05/30] Fix llvm jit failed to lookup aot_stack_sizes symbol issue (#2384) LVM JIT failed to lookup symbol "aot_stack_sizes" as it is an internal symbol, change to lookup "aot_stack_sizes_alias" instead. Reported in #2372. --- core/iwasm/compilation/aot_compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 94a378c4..e99e2ae7 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -2696,7 +2696,7 @@ aot_compile_wasm(AOTCompContext *comp_ctx) if (comp_ctx->stack_sizes != NULL) { LLVMOrcJITTargetAddress addr; if ((err = LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &addr, - aot_stack_sizes_name))) { + aot_stack_sizes_alias_name))) { aot_handle_llvm_errmsg("failed to look up stack_sizes", err); return false; } From 1cafa375680b6ea8b120e0d4d6006521d858ae2d Mon Sep 17 00:00:00 2001 From: Cengizhan Pasaoglu Date: Mon, 24 Jul 2023 12:43:13 +0300 Subject: [PATCH 06/30] Update Docker image for latest version of external libraries & tools (#2374) Devcontainer is too old to catch up the latest versions of dependencies. This PR updates the libraries & tools that WASM environment requires for Docker image. **Impediments:** - LLVM 16 can not be retrieved directly by using shell command as provided before. So we upgrade all tools manually as a workaround and just put LLVM issue URL as a comment in the script. **Improvements:** - Use `Debian 12 (Bookworm)` as a base image instead of `Ubuntu 20.04`. - `GCC9` upgraded to `GCC12`. - `LLVM14` upgraded to `LLVM16`. - `Clang10` upgraded to `Clang10`. - `Binaryen111` upgraded to `Binaryen114`. - `WASI-19` upgraded to `WASI-20` - `WABT-1.0.29` upgraded to `WABT-1.0.33` - `Bazelisk-1.12.0` upgraded to `Bazelisk-1.17.0` - `GithubCLI-2.20.2` upgraded to `GithubCLI-2.32.0` - `NodeJS-19.x` upgraded to `NodeJS-20.x` - `EMSDK-3.0.0` upgraded to `EMSDK-3.1.43` **Notes:** `Python 2.7` is removed due to no support anymore and not found in the repository. --- .devcontainer/Dockerfile | 78 ++++++++++++++++++++------------- .devcontainer/devcontainer.json | 23 +++++----- 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 2a8fcbca..1587a7dd 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,20 +1,21 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp/.devcontainer/base.Dockerfile -# [Choice] Debian / Ubuntu version (use Debian 11/9, Ubuntu 18.04/21.04 on local arm64/Apple Silicon): debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04 -ARG VARIANT=ubuntu-20.04 -FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT} +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/cpp/.devcontainer/base.Dockerfile +# [Choice] Debian / Ubuntu version (use Debian 12/11/9, Ubuntu 18.04/21.04 on local arm64/Apple Silicon): debian-12, debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04 +ARG VARIANT=debian-12 +FROM mcr.microsoft.com/vscode/devcontainers/cpp:${VARIANT} ARG DEBIAN_FRONTEND=noninteractive ENV TZ=Asian/Shanghai # hadolint ignore=DL3008 RUN apt-get update \ + && apt-get upgrade -y \ && apt-get install -y apt-transport-https apt-utils build-essential \ - ca-certificates ccache curl g++-multilib git gnupg \ - libgcc-9-dev lib32gcc-9-dev lsb-release \ - ninja-build ocaml ocamlbuild python2.7 \ + ca-certificates ccache cmake curl g++-multilib git gnupg \ + libgcc-12-dev lib32gcc-12-dev lsb-release \ + ninja-build ocaml ocamlbuild \ software-properties-common tree tzdata \ unzip valgrind vim wget zip --no-install-recommends \ && apt-get clean -y \ @@ -22,32 +23,32 @@ RUN apt-get update \ # # binaryen -ARG BINARYEN_VER=111 +ARG BINARYEN_VER=114 WORKDIR /opt RUN wget -c --progress=dot:giga https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_VER}/binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz \ && tar xf binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz \ - && ln -sf /opt/binaryen-version_111 /opt/binaryen \ + && ln -sf /opt/binaryen-version_${BINARYEN_VER} /opt/binaryen \ && rm binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz # # CMAKE (https://apt.kitware.com/) SHELL ["/bin/bash", "-o", "pipefail", "-c"] # hadolint ignore=DL3008 -RUN wget --progress=dot:giga -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \ - && echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null \ - && apt-get update \ - && rm /usr/share/keyrings/kitware-archive-keyring.gpg \ - && apt-get install -y kitware-archive-keyring --no-install-recommends \ - && apt-get install -y cmake --no-install-recommends \ - && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* +ARG CMAKE_VER=3.27.0 +RUN wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.sh \ + -q -O /tmp/cmake-install.sh \ + && chmod u+x /tmp/cmake-install.sh \ + && mkdir /opt/cmake-${CMAKE_VER} \ + && /tmp/cmake-install.sh --skip-license --prefix=/opt/cmake-${CMAKE_VER} \ + && rm /tmp/cmake-install.sh \ + && ln -s /opt/cmake-${CMAKE_VER}/bin/* /usr/local/bin # # install emsdk WORKDIR /opt RUN git clone https://github.com/emscripten-core/emsdk.git -ARG EMSDK_VER=3.0.0 +ARG EMSDK_VER=3.1.43 WORKDIR /opt/emsdk RUN git pull \ && ./emsdk install ${EMSDK_VER} \ @@ -56,7 +57,7 @@ RUN git pull \ # # install wasi-sdk -ARG WASI_SDK_VER=19 +ARG WASI_SDK_VER=20 RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt \ && tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \ && ln -sf /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ @@ -64,7 +65,7 @@ RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases # #install wabt -ARG WABT_VER=1.0.29 +ARG WABT_VER=1.0.33 RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz -P /opt \ && tar xf /opt/wabt-${WABT_VER}-ubuntu.tar.gz -C /opt \ && ln -sf /opt/wabt-${WABT_VER} /opt/wabt \ @@ -72,7 +73,7 @@ RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wabt/releases/dow # # install bazelisk -ARG BAZELISK_VER=1.12.0 +ARG BAZELISK_VER=1.17.0 RUN mkdir /opt/bazelisk \ && wget -c --progress=dot:giga https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VER}/bazelisk-linux-amd64 -P /opt/bazelisk \ && chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \ @@ -80,16 +81,30 @@ RUN mkdir /opt/bazelisk \ # # install clang+llvm -ARG LLVM_VER=14 -RUN apt-get purge -y clang-10 llvm-10 && apt-get autoremove -y +ARG LLVM_VER=16 +RUN apt-get purge -y clang-14 llvm-14 && apt-get autoremove -y WORKDIR /etc/apt/apt.conf.d RUN touch 99verfiy-peer.conf \ && echo "Acquire { https::Verify-Peer false }" > 99verfiy-peer.conf WORKDIR /tmp -RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \ - && chmod a+x ./llvm.sh \ - && ./llvm.sh ${LLVM_VER} all +#RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \ +# && chmod a+x ./llvm.sh \ +# && ./llvm.sh ${LLVM_VER} all + +# Workaround due to https://github.com/llvm/llvm-project/issues/62475 +# hadolint ignore=DL3008 +RUN set -ex \ + && echo "deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-${LLVM_VER} main" > /etc/apt/sources.list.d/apt.llvm.org.list \ + && wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc \ + && apt-get update \ + && apt-get install -y \ + clang-${LLVM_VER} lldb-${LLVM_VER} lld-${LLVM_VER} clangd-${LLVM_VER} clang-tidy-${LLVM_VER} clang-format-${LLVM_VER} clang-tools-${LLVM_VER} \ + llvm-${LLVM_VER}-dev lld-${LLVM_VER} lldb-${LLVM_VER} llvm-${LLVM_VER}-tools libomp-${LLVM_VER}-dev libc++-${LLVM_VER}-dev libc++abi-${LLVM_VER}-dev \ + libclang-common-${LLVM_VER}-dev libclang-${LLVM_VER}-dev libclang-cpp${LLVM_VER}-dev libunwind-${LLVM_VER}-dev \ + libclang-rt-${LLVM_VER}-dev libpolly-${LLVM_VER}-dev --no-install-recommends \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* # # [Optional] @@ -105,18 +120,19 @@ RUN apt-get update \ # # Install required python packages # hadolint ignore=DL3013 -RUN python3 -m pip install --no-cache-dir --upgrade pip \ - && pip3 install --no-cache-dir black nose pycparser pylint +RUN python3 -m pip install --no-cache-dir --break-system-packages --upgrade pip \ + && pip3 install --no-cache-dir --break-system-packages black nose pycparser pylint # # Install github-cli. It doens't work as a feature of devcontainer.json +ARG GH_CLI_VER=2.32.0 WORKDIR /tmp -RUN wget -q https://github.com/cli/cli/releases/download/v2.20.2/gh_2.20.2_linux_amd64.deb \ - && dpkg -i gh_2.20.2_linux_amd64.deb +RUN wget -q https://github.com/cli/cli/releases/download/v${GH_CLI_VER}/gh_${GH_CLI_VER}_linux_amd64.deb \ + && dpkg -i gh_${GH_CLI_VER}_linux_amd64.deb # # Install NodeJS -RUN wget -qO- https://deb.nodesource.com/setup_19.x | bash - +RUN wget -qO- https://deb.nodesource.com/setup_20.x | bash - # hadolint ignore=DL3008 RUN apt-get install -y nodejs --no-install-recommends diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 24e1bdfd..5feb1756 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,20 +1,23 @@ // Copyright (C) 2019 Intel Corporation. All rights reserved. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: -// https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp +// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/cpp { "name": "WAMR-Dev", "build": { "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04 - // Use Debian 11, Debian 9, Ubuntu 18.04 or Ubuntu 21.04 on local arm64/Apple Silicon + // Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-12, debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04 + // Use Debian 12, Debian 11, Debian 9, Ubuntu 18.04 or Ubuntu 21.04 on local arm64/Apple Silicon "args": { - "BINARYEN_VER": "111", - "EMSDK_VER": "3.0.0", - "LLVM_VER": "15", - "VARIANT": "ubuntu-20.04", - "WASI_SDK_VER": "19", - "WABT_VER": "1.0.31" + "BINARYEN_VER": "114", + "BAZELISK_VER": "1.17.0", + "CMAKE_VER": "3.27.0", + "EMSDK_VER": "3.1.43", + "GH_CLI_VER": "2.32.0", + "LLVM_VER": "16", + "VARIANT": "debian-12", + "WASI_SDK_VER": "20", + "WABT_VER": "1.0.33" } }, "runArgs": [ @@ -34,7 +37,7 @@ "llvm-vs-code-extensions.vscode-clangd", "ms-python.python", "ms-python.vscode-pylance", - "ms-vscode.cmake-tools", + "ms-vscode.cmake-tools" ] } }, From ada7e3fe881473818789c9a5d4c38e7ff0bf4054 Mon Sep 17 00:00:00 2001 From: dongheng <930490596@qq.com> Date: Thu, 27 Jul 2023 10:17:21 +0800 Subject: [PATCH 07/30] ESP-IDF platform supports to load AOT to PSRAM and run it (#2385) --- core/shared/platform/esp-idf/espidf_memmap.c | 73 +++++++++++++++++-- .../platform/esp-idf/shared_platform.cmake | 6 ++ .../platforms/esp-idf/build_and_run.sh | 4 +- product-mini/platforms/esp-idf/main/main.c | 8 +- 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/core/shared/platform/esp-idf/espidf_memmap.c b/core/shared/platform/esp-idf/espidf_memmap.c index 693094a6..0a1fd4fe 100644 --- a/core/shared/platform/esp-idf/espidf_memmap.c +++ b/core/shared/platform/esp-idf/espidf_memmap.c @@ -5,16 +5,34 @@ #include "platform_api_vmcore.h" #include "platform_api_extension.h" +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) +#include "soc/mmu.h" +#include "rom/cache.h" + +#define MEM_DUAL_BUS_OFFSET (IRAM0_CACHE_ADDRESS_LOW - DRAM0_CACHE_ADDRESS_LOW) + +#define in_ibus_ext(addr) \ + (((uint32)addr >= IRAM0_CACHE_ADDRESS_LOW) \ + && ((uint32)addr < IRAM0_CACHE_ADDRESS_HIGH)) + +static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED; +#endif void * os_mmap(void *hint, size_t size, int prot, int flags) { if (prot & MMAP_PROT_EXEC) { +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + uint32_t mem_caps = MALLOC_CAP_SPIRAM; +#else + uint32_t mem_caps = MALLOC_CAP_EXEC; +#endif + // Memory allocation with MALLOC_CAP_EXEC will return 4-byte aligned // Reserve extra 4 byte to fixup alignment and size for the pointer to // the originally allocated address void *buf_origin = - heap_caps_malloc(size + 4 + sizeof(uintptr_t), MALLOC_CAP_EXEC); + heap_caps_malloc(size + 4 + sizeof(uintptr_t), mem_caps); if (!buf_origin) { return NULL; } @@ -25,19 +43,35 @@ os_mmap(void *hint, size_t size, int prot, int flags) uintptr_t *addr_field = buf_fixed - sizeof(uintptr_t); *addr_field = (uintptr_t)buf_origin; +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + return buf_fixed + MEM_DUAL_BUS_OFFSET; +#else return buf_fixed; +#endif } else { - return os_malloc(size); +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + uint32_t mem_caps = MALLOC_CAP_SPIRAM; +#else + uint32_t mem_caps = MALLOC_CAP_8BIT; +#endif + return heap_caps_malloc(size, mem_caps); } } void os_munmap(void *addr, size_t size) { + char *ptr = (char *)addr; + +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + if (in_ibus_ext(ptr)) { + ptr -= MEM_DUAL_BUS_OFFSET; + } +#endif // We don't need special handling of the executable allocations // here, free() of esp-idf handles it properly - return os_free(addr); + return os_free(ptr); } int @@ -47,5 +81,34 @@ os_mprotect(void *addr, size_t size, int prot) } void -os_dcache_flush() -{} +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + IRAM_ATTR +#endif + os_dcache_flush() +{ +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) + uint32_t preload; + extern void Cache_WriteBack_All(void); + + portENTER_CRITICAL(&s_spinlock); + + Cache_WriteBack_All(); + preload = Cache_Disable_ICache(); + Cache_Enable_ICache(preload); + + portEXIT_CRITICAL(&s_spinlock); +#endif +} + +#if (WASM_MEM_DUAL_BUS_MIRROR != 0) +void * +os_get_dbus_mirror(void *ibus) +{ + if (in_ibus_ext(ibus)) { + return (void *)((char *)ibus - MEM_DUAL_BUS_OFFSET); + } + else { + return ibus; + } +} +#endif diff --git a/core/shared/platform/esp-idf/shared_platform.cmake b/core/shared/platform/esp-idf/shared_platform.cmake index 13bc45dc..8d7fe5d8 100644 --- a/core/shared/platform/esp-idf/shared_platform.cmake +++ b/core/shared/platform/esp-idf/shared_platform.cmake @@ -11,3 +11,9 @@ include_directories(${PLATFORM_SHARED_DIR}/../include) file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) 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 +# users can use SRAM to for Wi-Fi/BLE and peripheral driver. +if(CONFIG_ESP32S3_SPIRAM_SUPPORT) + add_definitions(-DWASM_MEM_DUAL_BUS_MIRROR=1) +endif() diff --git a/product-mini/platforms/esp-idf/build_and_run.sh b/product-mini/platforms/esp-idf/build_and_run.sh index dd8dd5ca..f764a301 100755 --- a/product-mini/platforms/esp-idf/build_and_run.sh +++ b/product-mini/platforms/esp-idf/build_and_run.sh @@ -5,14 +5,16 @@ ESP32_TARGET="esp32" ESP32C3_TARGET="esp32c3" +ESP32S3_TARGET="esp32s3" usage () { echo "USAGE:" - echo "$0 $ESP32_TARGET|$ESP32C3_TARGET" + echo "$0 $ESP32_TARGET|$ESP32C3_TARGET|$ESP32S3_TARGET" echo "Example:" echo " $0 $ESP32_TARGET" echo " $0 $ESP32C3_TARGET" + echo " $0 $ESP32S3_TARGET" exit 1 } diff --git a/product-mini/platforms/esp-idf/main/main.c b/product-mini/platforms/esp-idf/main/main.c index 417fad56..fbfb04c2 100644 --- a/product-mini/platforms/esp-idf/main/main.c +++ b/product-mini/platforms/esp-idf/main/main.c @@ -12,6 +12,12 @@ #include "esp_log.h" +#ifdef CONFIG_IDF_TARGET_ESP32S3 +#define IWASM_MAIN_STACK_SIZE 5120 +#else +#define IWASM_MAIN_STACK_SIZE 4096 +#endif + #define LOG_TAG "wamr" static void * @@ -146,7 +152,7 @@ app_main(void) pthread_attr_t tattr; pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); - pthread_attr_setstacksize(&tattr, 4096); + pthread_attr_setstacksize(&tattr, IWASM_MAIN_STACK_SIZE); res = pthread_create(&t, &tattr, iwasm_main, (void *)NULL); assert(res == 0); From 6110ea39fdcb9e86683213b6036c2787c0b9e9a5 Mon Sep 17 00:00:00 2001 From: TianlongLiang <111852609+TianlongLiang@users.noreply.github.com> Date: Thu, 27 Jul 2023 08:54:53 +0200 Subject: [PATCH 08/30] Add hadolint CI for Dockerfile linting (#2387) --- .github/workflows/hadolint_dockerfiles.yml | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/hadolint_dockerfiles.yml diff --git a/.github/workflows/hadolint_dockerfiles.yml b/.github/workflows/hadolint_dockerfiles.yml new file mode 100644 index 00000000..bdabeb6e --- /dev/null +++ b/.github/workflows/hadolint_dockerfiles.yml @@ -0,0 +1,47 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: hadolint dockerfiles + +on: + # will be triggered on PR events + pull_request: + types: + - opened + - synchronize + paths: + - "**/Dockerfile*" + - ".github/workflows/hadolint_dockerfiles.yml" + push: + branches: + - main + - "dev/**" + paths: + - "**/Dockerfile*" + - ".github/workflows/hadolint_dockerfiles.yml" + # allow to be triggered manually + workflow_dispatch: + +# Cancel any in-flight jobs for the same PR/branch so there's only one active +# at a time +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + run-hadolint-on-dockerfiles: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # on default, hadolint will fail on warnings and errors + - name: Run hadolint on dockerfiles + run: | + docker pull hadolint/hadolint:latest-debian + find . -name "*Dockerfile*" | while read dockerfile; do + echo "run hadolint on $dockerfile:" + docker run --rm -i hadolint/hadolint:latest-debian hadolint - <"$dockerfile" + echo "successful" + done \ No newline at end of file From 228417ab8c2980879853545163f6ec8d933ff01e Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Thu, 27 Jul 2023 22:37:23 +0900 Subject: [PATCH 09/30] Move generic parts of wasm_suspend_flags.h to bh_atomic.h (#2393) --- core/iwasm/common/wasm_suspend_flags.h | 40 ++++--------------- core/shared/utils/bh_atomic.h | 53 ++++++++++++++++++++++++++ core/shared/utils/bh_platform.h | 1 - 3 files changed, 60 insertions(+), 34 deletions(-) create mode 100644 core/shared/utils/bh_atomic.h diff --git a/core/iwasm/common/wasm_suspend_flags.h b/core/iwasm/common/wasm_suspend_flags.h index 0558eaf6..b7ecbb0b 100644 --- a/core/iwasm/common/wasm_suspend_flags.h +++ b/core/iwasm/common/wasm_suspend_flags.h @@ -6,7 +6,7 @@ #ifndef _WASM_SUSPEND_FLAGS_H #define _WASM_SUSPEND_FLAGS_H -#include "bh_platform.h" +#include "bh_atomic.h" #ifdef __cplusplus extern "C" { @@ -22,42 +22,16 @@ extern "C" { #define WASM_SUSPEND_FLAG_EXIT 0x8 typedef union WASMSuspendFlags { - uint32 flags; + bh_atomic_32_t flags; uintptr_t __padding__; } WASMSuspendFlags; -#if defined(__GNUC_PREREQ) -#if __GNUC_PREREQ(4, 7) -#define CLANG_GCC_HAS_ATOMIC_BUILTIN -#endif -#elif defined(__clang__) -#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 0) -#define CLANG_GCC_HAS_ATOMIC_BUILTIN -#endif -#endif - -#if defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) -#define WASM_SUSPEND_FLAGS_IS_ATOMIC 1 -#define WASM_SUSPEND_FLAGS_GET(s_flags) \ - __atomic_load_n(&s_flags.flags, __ATOMIC_SEQ_CST) +#define WASM_SUSPEND_FLAGS_IS_ATOMIC BH_ATOMIC_32_IS_ATOMIC +#define WASM_SUSPEND_FLAGS_GET(s_flags) BH_ATOMIC_32_LOAD(s_flags.flags) #define WASM_SUSPEND_FLAGS_FETCH_OR(s_flags, val) \ - __atomic_fetch_or(&s_flags.flags, val, __ATOMIC_SEQ_CST) + BH_ATOMIC_32_FETCH_OR(s_flags.flags, val) #define WASM_SUSPEND_FLAGS_FETCH_AND(s_flags, val) \ - __atomic_fetch_and(&s_flags.flags, val, __ATOMIC_SEQ_CST) -#else /* else of defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) */ -#define WASM_SUSPEND_FLAGS_GET(s_flags) (s_flags.flags) -#define WASM_SUSPEND_FLAGS_FETCH_OR(s_flags, val) (s_flags.flags |= val) -#define WASM_SUSPEND_FLAGS_FETCH_AND(s_flags, val) (s_flags.flags &= val) - -/* The flag can be defined by the user if the platform - supports atomic access to uint32 aligned memory. */ -#ifdef WASM_UINT32_IS_ATOMIC -#define WASM_SUSPEND_FLAGS_IS_ATOMIC 1 -#else /* else of WASM_UINT32_IS_ATOMIC */ -#define WASM_SUSPEND_FLAGS_IS_ATOMIC 0 -#endif /* WASM_UINT32_IS_ATOMIC */ - -#endif + BH_ATOMIC_32_FETCH_AND(s_flags.flags, val) #if WASM_SUSPEND_FLAGS_IS_ATOMIC != 0 #define WASM_SUSPEND_FLAGS_LOCK(lock) (void)0 @@ -71,4 +45,4 @@ typedef union WASMSuspendFlags { } #endif -#endif /* end of _WASM_SUSPEND_FLAGS_H */ \ No newline at end of file +#endif /* end of _WASM_SUSPEND_FLAGS_H */ diff --git a/core/shared/utils/bh_atomic.h b/core/shared/utils/bh_atomic.h new file mode 100644 index 00000000..4dfffa72 --- /dev/null +++ b/core/shared/utils/bh_atomic.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _BH_ATOMIC_H +#define _BH_ATOMIC_H + +#include "gnuc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32 bh_atomic_32_t; + +#if defined(__GNUC_PREREQ) +#if __GNUC_PREREQ(4, 7) +#define CLANG_GCC_HAS_ATOMIC_BUILTIN +#endif +#elif defined(__clang__) +#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 0) +#define CLANG_GCC_HAS_ATOMIC_BUILTIN +#endif +#endif + +#if defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) +#define BH_ATOMIC_32_IS_ATOMIC 1 +#define BH_ATOMIC_32_LOAD(v) __atomic_load_n(&(v), __ATOMIC_SEQ_CST) +#define BH_ATOMIC_32_FETCH_OR(v, val) \ + __atomic_fetch_or(&(v), (val), __ATOMIC_SEQ_CST) +#define BH_ATOMIC_32_FETCH_AND(v, val) \ + __atomic_fetch_and(&(v), (val), __ATOMIC_SEQ_CST) +#else /* else of defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) */ +#define BH_ATOMIC_32_LOAD(v) (v) +#define BH_ATOMIC_32_FETCH_OR(v, val) ((v) |= (val)) +#define BH_ATOMIC_32_FETCH_AND(v, val) ((v) &= (val)) + +/* The flag can be defined by the user if the platform + supports atomic access to uint32 aligned memory. */ +#ifdef WASM_UINT32_IS_ATOMIC +#define BH_ATOMIC_32_IS_ATOMIC 1 +#else /* else of WASM_UINT32_IS_ATOMIC */ +#define BH_ATOMIC_32_IS_ATOMIC 0 +#endif /* WASM_UINT32_IS_ATOMIC */ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* end of _BH_ATOMIC_H */ diff --git a/core/shared/utils/bh_platform.h b/core/shared/utils/bh_platform.h index 9821d710..86aef839 100644 --- a/core/shared/utils/bh_platform.h +++ b/core/shared/utils/bh_platform.h @@ -16,7 +16,6 @@ #include "bh_log.h" #include "bh_queue.h" #include "bh_vector.h" -#include "gnuc.h" #include "runtime_timer.h" /** From 59b2099b68ae3e027f2787397226e503501e38b8 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 27 Jul 2023 21:53:48 +0800 Subject: [PATCH 10/30] Fix some check issues on table operations (#2392) Fix some check issues on table.init, table.fill and table.copy, and unify the check method for all running modes. Fix issue #2390 and #2096. --- core/iwasm/aot/aot_runtime.c | 15 +++---- core/iwasm/fast-jit/fe/jit_emit_table.c | 41 ++++++++++---------- core/iwasm/interpreter/wasm.h | 19 ++++++++- core/iwasm/interpreter/wasm_interp_classic.c | 36 ++++++++--------- core/iwasm/interpreter/wasm_interp_fast.c | 30 ++++++++------ core/iwasm/interpreter/wasm_runtime.c | 15 +++---- 6 files changed, 91 insertions(+), 65 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 35735b94..e0d56a69 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -2489,13 +2489,13 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx, tbl_seg = module->table_init_data_list[tbl_seg_idx]; bh_assert(tbl_seg); - if (!length) { + if (offset_len_out_of_bounds(src_offset, length, tbl_seg->func_index_count) + || offset_len_out_of_bounds(dst_offset, length, tbl_inst->cur_size)) { + aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); return; } - if (length + src_offset > tbl_seg->func_index_count - || dst_offset + length > tbl_inst->cur_size) { - aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + if (!length) { return; } @@ -2528,8 +2528,9 @@ aot_table_copy(AOTModuleInstance *module_inst, uint32 src_tbl_idx, dst_tbl_inst = module_inst->tables[dst_tbl_idx]; bh_assert(dst_tbl_inst); - if ((uint64)dst_offset + length > dst_tbl_inst->cur_size - || (uint64)src_offset + length > src_tbl_inst->cur_size) { + if (offset_len_out_of_bounds(dst_offset, length, dst_tbl_inst->cur_size) + || offset_len_out_of_bounds(src_offset, length, + src_tbl_inst->cur_size)) { aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); return; } @@ -2554,7 +2555,7 @@ aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx, uint32 length, tbl_inst = module_inst->tables[tbl_idx]; bh_assert(tbl_inst); - if (data_offset + length > tbl_inst->cur_size) { + if (offset_len_out_of_bounds(data_offset, length, tbl_inst->cur_size)) { aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); return; } diff --git a/core/iwasm/fast-jit/fe/jit_emit_table.c b/core/iwasm/fast-jit/fe/jit_emit_table.c index 9fb61931..ea1b3388 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_table.c +++ b/core/iwasm/fast-jit/fe/jit_emit_table.c @@ -88,27 +88,28 @@ fail: static int wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 elem_idx, - uint32 dst, uint32 len, uint32 src) + uint32 dst_offset, uint32 len, uint32 src_offset) { WASMTableInstance *tbl; uint32 tbl_sz; WASMTableSeg *elem; uint32 elem_len; - tbl = inst->tables[tbl_idx]; - tbl_sz = tbl->cur_size; - if (dst > tbl_sz || tbl_sz - dst < len) - goto out_of_bounds; - elem = inst->module->table_segments + elem_idx; elem_len = elem->function_count; - if (src > elem_len || elem_len - src < len) + if (offset_len_out_of_bounds(src_offset, len, elem_len)) + goto out_of_bounds; + + tbl = inst->tables[tbl_idx]; + tbl_sz = tbl->cur_size; + if (offset_len_out_of_bounds(dst_offset, len, tbl_sz)) goto out_of_bounds; bh_memcpy_s((uint8 *)tbl + offsetof(WASMTableInstance, elems) - + dst * sizeof(uint32), - (uint32)((tbl_sz - dst) * sizeof(uint32)), - elem->func_indexes + src, (uint32)(len * sizeof(uint32))); + + dst_offset * sizeof(uint32), + (uint32)((tbl_sz - dst_offset) * sizeof(uint32)), + elem->func_indexes + src_offset, + (uint32)(len * sizeof(uint32))); return 0; out_of_bounds: @@ -157,14 +158,14 @@ wasm_copy_table(WASMModuleInstance *inst, uint32 src_tbl_idx, WASMTableInstance *src_tbl, *dst_tbl; uint32 src_tbl_sz, dst_tbl_sz; - src_tbl = inst->tables[src_tbl_idx]; - src_tbl_sz = src_tbl->cur_size; - if (src_offset > src_tbl_sz || src_tbl_sz - src_offset < len) - goto out_of_bounds; - dst_tbl = inst->tables[dst_tbl_idx]; dst_tbl_sz = dst_tbl->cur_size; - if (dst_offset > dst_tbl_sz || dst_tbl_sz - dst_offset < len) + if (offset_len_out_of_bounds(dst_offset, len, dst_tbl_sz)) + goto out_of_bounds; + + src_tbl = inst->tables[src_tbl_idx]; + src_tbl_sz = src_tbl->cur_size; + if (offset_len_out_of_bounds(src_offset, len, src_tbl_sz)) goto out_of_bounds; bh_memmove_s((uint8 *)dst_tbl + offsetof(WASMTableInstance, elems) @@ -263,7 +264,7 @@ fail: } static int -wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst, +wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst_offset, uint32 val, uint32 len) { WASMTableInstance *tbl; @@ -272,11 +273,11 @@ wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst, tbl = inst->tables[tbl_idx]; tbl_sz = tbl->cur_size; - if (dst > tbl_sz || tbl_sz - dst < len) + if (offset_len_out_of_bounds(dst_offset, len, tbl_sz)) goto out_of_bounds; - for (; len != 0; dst++, len--) { - tbl->elems[dst] = val; + for (; len != 0; dst_offset++, len--) { + tbl->elems[dst_offset] = val; } return 0; diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 0797a018..c7d9f1de 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -627,7 +627,6 @@ typedef struct WASMBranchBlock { uint32 cell_num; } WASMBranchBlock; -/* Execution environment, e.g. stack info */ /** * Align an unsigned value on a alignment boundary. * @@ -643,6 +642,24 @@ align_uint(unsigned v, unsigned b) return (v + m) & ~m; } +/** + * Check whether a piece of data is out of range + * + * @param offset the offset that the data starts + * @param len the length of the data + * @param max_size the maximum size of the data range + * + * @return true if out of range, false otherwise + */ +inline static bool +offset_len_out_of_bounds(uint32 offset, uint32 len, uint32 max_size) +{ + if (offset + len < offset /* integer overflow */ + || offset + len > max_size) + return true; + return false; +} + /** * Return the hash value of c string. */ diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 55fca292..23e165be 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -3247,7 +3247,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, case WASM_OP_TABLE_INIT: { uint32 tbl_idx, elem_idx; - uint64 n, s, d; + uint32 n, s, d; WASMTableInstance *tbl_inst; read_leb_uint32(frame_ip, frame_ip_end, elem_idx); @@ -3262,20 +3262,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, s = (uint32)POP_I32(); d = (uint32)POP_I32(); - /* TODO: what if the element is not passive? */ - - if (!n) { - break; - } - - if (n + s > module->module->table_segments[elem_idx] - .function_count - || d + n > tbl_inst->cur_size) { + if (offset_len_out_of_bounds( + s, n, + module->module->table_segments[elem_idx] + .function_count) + || offset_len_out_of_bounds(d, n, + tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; } + if (!n) { + break; + } + if (module->module->table_segments[elem_idx] .is_dropped) { wasm_set_exception(module, @@ -3316,7 +3317,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, case WASM_OP_TABLE_COPY: { uint32 src_tbl_idx, dst_tbl_idx; - uint64 n, s, d; + uint32 n, s, d; WASMTableInstance *src_tbl_inst, *dst_tbl_inst; read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx); @@ -3333,8 +3334,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, s = (uint32)POP_I32(); d = (uint32)POP_I32(); - if (d + n > dst_tbl_inst->cur_size - || s + n > src_tbl_inst->cur_size) { + if (offset_len_out_of_bounds(d, n, + dst_tbl_inst->cur_size) + || offset_len_out_of_bounds( + s, n, src_tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; @@ -3404,11 +3407,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, fill_val = POP_I32(); i = POP_I32(); - /* TODO: what if the element is not passive? */ - /* TODO: what if the element is dropped? */ - - if (i + n > tbl_inst->cur_size) { - /* TODO: verify warning content */ + if (offset_len_out_of_bounds(i, n, + tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 070fcdbe..458eb2e4 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -3078,7 +3078,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, case WASM_OP_TABLE_INIT: { uint32 tbl_idx, elem_idx; - uint64 n, s, d; + uint32 n, s, d; WASMTableInstance *tbl_inst; elem_idx = read_uint32(frame_ip); @@ -3093,18 +3093,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, s = (uint32)POP_I32(); d = (uint32)POP_I32(); - if (!n) { - break; - } - - if (n + s > module->module->table_segments[elem_idx] - .function_count - || d + n > tbl_inst->cur_size) { + if (offset_len_out_of_bounds( + s, n, + module->module->table_segments[elem_idx] + .function_count) + || offset_len_out_of_bounds(d, n, + tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; } + if (!n) { + break; + } + if (module->module->table_segments[elem_idx] .is_dropped) { wasm_set_exception(module, @@ -3143,7 +3146,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, case WASM_OP_TABLE_COPY: { uint32 src_tbl_idx, dst_tbl_idx; - uint64 n, s, d; + uint32 n, s, d; WASMTableInstance *src_tbl_inst, *dst_tbl_inst; dst_tbl_idx = read_uint32(frame_ip); @@ -3160,8 +3163,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, s = (uint32)POP_I32(); d = (uint32)POP_I32(); - if (d + n > dst_tbl_inst->cur_size - || s + n > src_tbl_inst->cur_size) { + if (offset_len_out_of_bounds(d, n, + dst_tbl_inst->cur_size) + || offset_len_out_of_bounds( + s, n, src_tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; @@ -3232,7 +3237,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, fill_val = POP_I32(); i = POP_I32(); - if (i + n > tbl_inst->cur_size) { + if (offset_len_out_of_bounds(i, n, + tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 00f0cf66..84155a05 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -3301,13 +3301,13 @@ llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx, bh_assert(tbl_inst); bh_assert(tbl_seg); - if (!length) { + if (offset_len_out_of_bounds(src_offset, length, tbl_seg->function_count) + || offset_len_out_of_bounds(dst_offset, length, tbl_inst->cur_size)) { + jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); return; } - if (length + src_offset > tbl_seg->function_count - || dst_offset + length > tbl_inst->cur_size) { - jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + if (!length) { return; } @@ -3349,8 +3349,9 @@ llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx, bh_assert(src_tbl_inst); bh_assert(dst_tbl_inst); - if ((uint64)dst_offset + length > dst_tbl_inst->cur_size - || (uint64)src_offset + length > src_tbl_inst->cur_size) { + if (offset_len_out_of_bounds(dst_offset, length, dst_tbl_inst->cur_size) + || offset_len_out_of_bounds(src_offset, length, + src_tbl_inst->cur_size)) { jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); return; } @@ -3382,7 +3383,7 @@ llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx, tbl_inst = wasm_get_table_inst(module_inst, tbl_idx); bh_assert(tbl_inst); - if (data_offset + length > tbl_inst->cur_size) { + if (offset_len_out_of_bounds(data_offset, length, tbl_inst->cur_size)) { jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); return; } From 7db4815e837bc34942e95aba292ca0eca318cc54 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Fri, 28 Jul 2023 21:36:35 +0900 Subject: [PATCH 11/30] bh_atomic.h: Add comments (#2398) --- core/shared/utils/bh_atomic.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/core/shared/utils/bh_atomic.h b/core/shared/utils/bh_atomic.h index 4dfffa72..61f65a6b 100644 --- a/core/shared/utils/bh_atomic.h +++ b/core/shared/utils/bh_atomic.h @@ -12,6 +12,38 @@ extern "C" { #endif +/* + * Why don't we use C11 stdatomics here? + * + * Unlike C11 stdatomics, + * + * - bh_atomic_xxx_t is guaranteed to have the same size as the base type. + * Thus more friendly to our AOT conventions. + * + * - It's available for C++. + * Although C++23 will have C-compatible stdatomics.h, it isn't widely + * available yet. + */ + +/* + * Note about BH_ATOMIC_32_IS_ATOMIC + * + * If BH_ATOMIC_32_IS_ATOMIC == 0, BH_ATOMIC_xxx operations defined below + * are not really atomic and require an external lock. + * + * Expected usage is: + * + * bh_atomic_32_t var = 0; + * uint32 old; + * #if BH_ATOMIC_32_IS_ATOMIC == 0 + * lock(&some_lock); + * #endif + * old = BH_ATOMIC_32_FETCH_AND(var, 1); + * #if BH_ATOMIC_32_IS_ATOMIC == 0 + * unlock(&some_lock); + * #endif + */ + typedef uint32 bh_atomic_32_t; #if defined(__GNUC_PREREQ) From 10b18d85cdf491d78d36ac36948a6afeff369e8a Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Sat, 29 Jul 2023 10:28:09 +0800 Subject: [PATCH 12/30] Fix ExpandMemoryOpPass doesn't work properly (#2399) The old method may not work for some cases. This PR iterates over all instructions in the function, looking for memcpy, memmove and memset instructions, putting them into a set, and finally expands them into a loop one by one. And move this LLVM Pass after building the pipe line of pass builder to ensure that the memcpy/memmove/memset instrinsics are generated before applying the pass. --- core/iwasm/compilation/aot_llvm_extra.cpp | 77 +++++++++++------------ 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index 1ccb2f54..898fabd8 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -82,43 +82,40 @@ class ExpandMemoryOpPass : public PassInfoMixin PreservedAnalyses ExpandMemoryOpPass::run(Function &F, FunctionAnalysisManager &AM) { - Intrinsic::ID ID = F.getIntrinsicID(); - bool Changed = false; + SmallVector MemCalls; - for (auto I = F.user_begin(), E = F.user_end(); I != E;) { - Instruction *Inst = cast(*I); - ++I; + /* Iterate over all instructions in the function, looking for memcpy, + * memmove, and memset. When we find one, expand it into a loop. */ - switch (ID) { - case Intrinsic::memcpy: - { - auto *Memcpy = cast(Inst); - Function *ParentFunc = Memcpy->getParent()->getParent(); - const TargetTransformInfo &TTI = - AM.getResult(*ParentFunc); - expandMemCpyAsLoop(Memcpy, TTI); - Memcpy->eraseFromParent(); - Changed = true; - break; + for (auto &BB : F) { + for (auto &Inst : BB) { + if (auto *Memcpy = dyn_cast_or_null(&Inst)) { + MemCalls.push_back(Memcpy); } - case Intrinsic::memmove: - { - auto *Memmove = cast(Inst); - expandMemMoveAsLoop(Memmove); - Memmove->eraseFromParent(); - Changed = true; - break; + else if (auto *Memmove = dyn_cast_or_null(&Inst)) { + MemCalls.push_back(Memmove); } - case Intrinsic::memset: - { - auto *Memset = cast(Inst); - expandMemSetAsLoop(Memset); - Memset->eraseFromParent(); - Changed = true; - break; + else if (auto *Memset = dyn_cast_or_null(&Inst)) { + MemCalls.push_back(Memset); } - default: - break; + } + } + + for (MemIntrinsic *MemCall : MemCalls) { + if (MemCpyInst *Memcpy = dyn_cast(MemCall)) { + Function *ParentFunc = Memcpy->getParent()->getParent(); + const TargetTransformInfo &TTI = + AM.getResult(*ParentFunc); + expandMemCpyAsLoop(Memcpy, TTI); + Memcpy->eraseFromParent(); + } + else if (MemMoveInst *Memmove = dyn_cast(MemCall)) { + expandMemMoveAsLoop(Memmove); + Memmove->eraseFromParent(); + } + else if (MemSetInst *Memset = dyn_cast(MemCall)) { + expandMemSetAsLoop(Memset); + Memset->eraseFromParent(); } } @@ -297,13 +294,6 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module) FPM.addPass(SLPVectorizerPass()); FPM.addPass(LoadStoreVectorizerPass()); - /* Run specific passes for AOT indirect mode in last since general - optimization may create some intrinsic function calls like - llvm.memset, so let's remove these function calls here. */ - if (comp_ctx->is_indirect_mode) { - FPM.addPass(ExpandMemoryOpPass()); - } - if (comp_ctx->enable_llvm_pgo || comp_ctx->use_prof_file) { /* LICM pass: loop invariant code motion, attempting to remove as much code from the body of a loop as possible. Experiments @@ -341,6 +331,15 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module) else { MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); } + + /* Run specific passes for AOT indirect mode in last since general + optimization may create some intrinsic function calls like + llvm.memset, so let's remove these function calls here. */ + if (comp_ctx->is_indirect_mode) { + FunctionPassManager FPM1; + FPM1.addPass(ExpandMemoryOpPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM1))); + } } MPM.run(*M, MAM); From 6d6cea1a73452c68545ab617c497fe19848cbd14 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Sun, 30 Jul 2023 20:23:30 +0900 Subject: [PATCH 13/30] Fix non-builtin BH_ATOMIC_32_FETCH_OR and BH_ATOMIC_32_FETCH_AND (#2400) --- core/shared/utils/bh_atomic.h | 20 ++++++++++++++++++-- samples/bh_atomic/CMakeLists.txt | 20 ++++++++++++++++++++ samples/bh_atomic/main.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 samples/bh_atomic/CMakeLists.txt create mode 100644 samples/bh_atomic/main.c diff --git a/core/shared/utils/bh_atomic.h b/core/shared/utils/bh_atomic.h index 61f65a6b..b4378c4b 100644 --- a/core/shared/utils/bh_atomic.h +++ b/core/shared/utils/bh_atomic.h @@ -65,8 +65,24 @@ typedef uint32 bh_atomic_32_t; __atomic_fetch_and(&(v), (val), __ATOMIC_SEQ_CST) #else /* else of defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) */ #define BH_ATOMIC_32_LOAD(v) (v) -#define BH_ATOMIC_32_FETCH_OR(v, val) ((v) |= (val)) -#define BH_ATOMIC_32_FETCH_AND(v, val) ((v) &= (val)) +#define BH_ATOMIC_32_FETCH_OR(v, val) nonatomic_32_fetch_or(&(v), val) +#define BH_ATOMIC_32_FETCH_AND(v, val) nonatomic_32_fetch_and(&(v), val) + +static inline uint32 +nonatomic_32_fetch_or(bh_atomic_32_t *p, uint32 val) +{ + uint32 old = *p; + *p |= val; + return old; +} + +static inline uint32 +nonatomic_32_fetch_and(bh_atomic_32_t *p, uint32 val) +{ + uint32 old = *p; + *p &= val; + return old; +} /* The flag can be defined by the user if the platform supports atomic access to uint32 aligned memory. */ diff --git a/samples/bh_atomic/CMakeLists.txt b/samples/bh_atomic/CMakeLists.txt new file mode 100644 index 00000000..f6905274 --- /dev/null +++ b/samples/bh_atomic/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (C) 2023 Midokura Japan KK. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.0) +project(bh_atomic) + +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if(APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif() + +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_LIBC_BUILTIN 0) + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..) +include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_executable(bh_atomic main.c) + +target_link_libraries(bh_atomic) diff --git a/samples/bh_atomic/main.c b/samples/bh_atomic/main.c new file mode 100644 index 00000000..adb0dd02 --- /dev/null +++ b/samples/bh_atomic/main.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 Midokura Japan KK. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +#include "bh_platform.h" +#include "bh_atomic.h" + +int +main(int argc, char **argv) +{ + bh_atomic_32_t v; + uint32 o; + + v = 0x00ff00ff; + o = BH_ATOMIC_32_LOAD(v); + assert(o == 0x00ff00ff); + + v = 0x00ff00ff; + o = BH_ATOMIC_32_FETCH_OR(v, 0xffff0000); + assert(o == 0x00ff00ff); + assert(v == 0xffff00ff); + + v = 0x00ff00ff; + o = BH_ATOMIC_32_FETCH_AND(v, 0xffff0000); + assert(o == 0x00ff00ff); + assert(v == 0x00ff0000); + + return 0; +} From 151600fef2954ffd418f417bc22a899bf327c3a5 Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Sun, 30 Jul 2023 12:34:09 +0100 Subject: [PATCH 14/30] Fix wasi-sockets tests (#2389) Tests were failing because the right permissions were not provided to iwasm. Also, test failures didn't trigger build failure due to typo - also fixed in this change. In addition to that, this PR fixes a few issues with the test itself: * the `server_init_complete` was not reset early enough causing the client to occasionally assume the server started even though it didn't yet * set `SO_REUSEADDR` on the server socket so the port can be reused shortly after closing the previous socket * defined receive-send-receive sequence from server to make sure server is alive at the time of sending message --- .../libraries/lib-socket/test/nslookup.c | 1 + .../iwasm/libraries/lib-socket/test/tcp_udp.c | 227 +++++++++--------- .../wasi-test-script/run_wasi_tests.sh | 14 +- 3 files changed, 122 insertions(+), 120 deletions(-) diff --git a/core/iwasm/libraries/lib-socket/test/nslookup.c b/core/iwasm/libraries/lib-socket/test/nslookup.c index 543a3fb2..8e64d06b 100644 --- a/core/iwasm/libraries/lib-socket/test/nslookup.c +++ b/core/iwasm/libraries/lib-socket/test/nslookup.c @@ -46,6 +46,7 @@ test_nslookup_mt(void *params) { int *af = (int *)params; test_nslookup(*af); + return NULL; } int diff --git a/core/iwasm/libraries/lib-socket/test/tcp_udp.c b/core/iwasm/libraries/lib-socket/test/tcp_udp.c index 49231de8..0ed03125 100644 --- a/core/iwasm/libraries/lib-socket/test/tcp_udp.c +++ b/core/iwasm/libraries/lib-socket/test/tcp_udp.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #ifdef __wasi__ #include #include @@ -12,105 +14,123 @@ #endif #include #include +#include + #define SERVER_MSG "Message from server." #define PORT 8989 -pthread_mutex_t mut; -pthread_cond_t cond; + +pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + int server_init_complete = 0; -char buffer[sizeof(SERVER_MSG) + 1]; -struct socket_info { - union { - struct sockaddr_in addr_ipv4; - struct sockaddr_in6 addr_ipv6; - } addr; +typedef struct { + struct sockaddr_storage addr; + socklen_t addr_len; int sock; -}; - -struct thread_args { - int family; int protocol; -}; +} socket_info_t; -struct socket_info -init_socket_addr(int family, int protocol) +void +wait_for_server(int wait_time_seconds) { - int sock = socket(family, protocol, 0); - assert(sock != -1); + int res = 0; + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += wait_time_seconds; - struct socket_info info; - if (family == AF_INET) { - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(PORT); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - info.addr.addr_ipv4 = addr; + pthread_mutex_lock(&mut); + while (server_init_complete == 0) { + res = pthread_cond_timedwait(&cond, &mut, &ts); + if (res == ETIMEDOUT) + break; } - else if (family == AF_INET6) { - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(PORT); - addr.sin6_addr = in6addr_loopback; - info.addr.addr_ipv6 = addr; - } - info.sock = sock; - return info; + pthread_mutex_unlock(&mut); + + assert(res == 0); } void -assert_thread_args(struct thread_args *args) +notify_server_started() { - assert(args->family == AF_INET || args->family == AF_INET6); - assert(args->protocol == SOCK_STREAM || args->protocol == SOCK_DGRAM); + pthread_mutex_lock(&mut); + server_init_complete = 1; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mut); +} + +socket_info_t +init_socket_addr(int family, int protocol) +{ + socket_info_t info; + + info.sock = socket(family, protocol, 0); + assert(info.sock != -1); + info.protocol = protocol; + + memset(&info.addr, 0, sizeof(info.addr)); + + if (family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)&info.addr; + addr->sin_family = AF_INET; + addr->sin_port = htons(PORT); + addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + info.addr_len = sizeof(struct sockaddr_in); + } + else if (family == AF_INET6) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&info.addr; + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(PORT); + addr->sin6_addr = in6addr_loopback; + info.addr_len = sizeof(struct sockaddr_in6); + } + + return info; } void * server(void *arg) { - server_init_complete = 0; - struct thread_args *args = (struct thread_args *)arg; - assert_thread_args(args); - - struct socket_info init_server_sock = - init_socket_addr(args->family, args->protocol); - - int server_sock = init_server_sock.sock; - socklen_t addr_size; + char buffer[sizeof(SERVER_MSG) + 1] = { 0 }; struct sockaddr_storage client_addr; - strcpy(buffer, SERVER_MSG); + socket_info_t *info = (socket_info_t *)arg; + struct sockaddr *server_addr = (struct sockaddr *)&info->addr; + int server_sock = info->sock; - struct sockaddr *server_addr = (struct sockaddr *)&init_server_sock.addr; - int ret = bind(server_sock, server_addr, - args->family == AF_INET ? sizeof(struct sockaddr_in) - : sizeof(struct sockaddr_in6)); - assert(ret == 0); + int optval = 1; + assert(setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &optval, + sizeof(optval)) + == 0); - (args->protocol == SOCK_STREAM) && listen(server_sock, 1); - pthread_mutex_lock(&mut); - server_init_complete = 1; - pthread_mutex_unlock(&mut); - pthread_cond_signal(&cond); + assert(bind(server_sock, server_addr, info->addr_len) == 0); - addr_size = sizeof(client_addr); - if (args->protocol == SOCK_STREAM) { + if (info->protocol == SOCK_STREAM) + listen(server_sock, 1); + notify_server_started(); + + socklen_t addr_size = info->addr_len; + if (info->protocol == SOCK_STREAM) { int client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &addr_size); assert(client_sock >= 0); - sendto(client_sock, buffer, strlen(buffer), 0, - (struct sockaddr *)&client_addr, addr_size); - - assert(close(client_sock) == 0); + assert(recv(client_sock, buffer, sizeof(buffer), 0) > 0); + strcpy(buffer, SERVER_MSG); + assert(send(client_sock, buffer, sizeof(buffer), 0) > 0); + assert(recv(client_sock, buffer, sizeof(buffer), 0) > 0); } else { - recvfrom(server_sock, buffer, sizeof(buffer), 0, - (struct sockaddr *)&client_addr, &addr_size); - sendto(server_sock, buffer, strlen(buffer), 0, - (struct sockaddr *)&client_addr, addr_size); - - assert(close(server_sock) == 0); + assert(recvfrom(server_sock, buffer, sizeof(buffer), 0, + (struct sockaddr *)&client_addr, &addr_size) + > 0); + strcpy(buffer, SERVER_MSG); + assert(sendto(server_sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&client_addr, addr_size) + > 0); + assert(recvfrom(server_sock, buffer, sizeof(buffer), 0, + (struct sockaddr *)&client_addr, &addr_size) + > 0); } + assert(close(server_sock) == 0); return NULL; } @@ -118,46 +138,23 @@ server(void *arg) void * client(void *arg) { - struct thread_args *args = (struct thread_args *)arg; - assert_thread_args(args); + char buffer[sizeof(SERVER_MSG) + 1]; + socket_info_t *info = (socket_info_t *)arg; + int sock = info->sock; + struct sockaddr *addr = (struct sockaddr *)&info->addr; - pthread_mutex_lock(&mut); + wait_for_server(1); - while (server_init_complete == 0) { - pthread_cond_wait(&cond, &mut); + if (info->protocol == SOCK_STREAM) { + assert(connect(sock, addr, info->addr_len) != -1); } - struct socket_info init_client_sock = - init_socket_addr(args->family, args->protocol); - int sock = init_client_sock.sock; - pthread_mutex_unlock(&mut); - - if (args->family == AF_INET) { - struct sockaddr_in addr = init_client_sock.addr.addr_ipv4; - if (args->protocol == SOCK_STREAM) { - assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1); - } - else { - assert(sendto(sock, buffer, strlen(buffer), 0, - (struct sockaddr *)&addr, sizeof(addr)) - != -1); - } - } - else { - struct sockaddr_in6 addr = init_client_sock.addr.addr_ipv6; - if (args->protocol == SOCK_STREAM) { - assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1); - } - else { - assert(sendto(sock, buffer, strlen(buffer), 0, - (struct sockaddr *)&addr, sizeof(addr)) - != -1); - } - } - - recv(sock, buffer, sizeof(buffer), 0); - assert(strcmp(buffer, SERVER_MSG) == 0); + assert(sendto(sock, "open", strlen("open"), 0, addr, info->addr_len) > 0); + assert(recv(sock, buffer, sizeof(buffer), 0) > 0); + assert(strncmp(buffer, SERVER_MSG, strlen(SERVER_MSG)) == 0); + assert(sendto(sock, "close", sizeof("close"), 0, addr, info->addr_len) > 0); assert(close(sock) == 0); + return NULL; } @@ -165,17 +162,19 @@ void test_protocol(int family, int protocol) { pthread_t server_thread, client_thread; - assert(pthread_cond_init(&cond, NULL) == 0); - assert(pthread_mutex_init(&mut, NULL) == 0); + socket_info_t server_info = init_socket_addr(family, protocol); + socket_info_t client_info = init_socket_addr(family, protocol); - struct thread_args args = { family, protocol }; - assert(pthread_create(&server_thread, NULL, server, (void *)&args) == 0); - assert(pthread_create(&client_thread, NULL, client, (void *)&args) == 0); + printf("Testing address family: %d protocol: %d\n", family, protocol); + + server_init_complete = 0; + + assert(pthread_create(&server_thread, NULL, server, (void *)&server_info) + == 0); + assert(pthread_create(&client_thread, NULL, client, (void *)&client_info) + == 0); assert(pthread_join(server_thread, NULL) == 0); assert(pthread_join(client_thread, NULL) == 0); - - assert(pthread_mutex_destroy(&mut) == 0); - assert(pthread_cond_destroy(&cond) == 0); } int @@ -190,4 +189,4 @@ main(int argc, char **argv) test_protocol(AF_INET6, SOCK_DGRAM); return 0; -} \ No newline at end of file +} diff --git a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh index eb6cf3f9..7738b508 100755 --- a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh +++ b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh @@ -11,7 +11,9 @@ readonly TARGET=$2 readonly WORK_DIR=$PWD readonly PLATFORM=$(uname -s | tr A-Z a-z) readonly WAMR_DIR="${WORK_DIR}/../../../.." -readonly IWASM_CMD="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm" +readonly IWASM_CMD="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm \ + --allow-resolve=google-public-dns-a.google.com \ + --addr-pool=::1/128,127.0.0.1/32" readonly WAMRC_CMD="${WORK_DIR}/../../../../wamr-compiler/build/wamrc" readonly C_TESTS="tests/c/testsuite/" readonly ASSEMBLYSCRIPT_TESTS="tests/assemblyscript/testsuite/" @@ -35,12 +37,12 @@ run_aot_tests () { echo "Running $test_aot" expected=0 - if [ -f ${test_json} ]; then + if [ -f ${test_json} ]; then expected=$(jq .exit_code ${test_json}) fi - + ${IWASM_CMD} $test_aot - + ret=${PIPESTATUS[0]} echo "expected=$expected, actual=$ret" @@ -48,7 +50,7 @@ run_aot_tests () { exit_code=1 fi done -} +} if [[ $MODE != "aot" ]];then python3 -m venv wasi-env && source wasi-env/bin/activate @@ -60,7 +62,7 @@ if [[ $MODE != "aot" ]];then ${ASSEMBLYSCRIPT_TESTS} \ ${THREAD_PROPOSAL_TESTS} \ ${THREAD_INTERNAL_TESTS} \ - ${LIB_SOCKET_TESTS} \ + ${LIB_SOCKET_TESTS} exit_code=${PIPESTATUS[0]} deactivate else From b1fa27e91d8cf2868bd1d764aabd5579db78a2bd Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Mon, 31 Jul 2023 18:56:15 +0900 Subject: [PATCH 15/30] bh_atomic.h: Add BH_ATOMIC_32_FETCH_ADD/BH_ATOMIC_32_FETCH_SUB (#2408) --- core/shared/utils/bh_atomic.h | 22 ++++++++++++++++++++++ samples/bh_atomic/main.c | 10 ++++++++++ 2 files changed, 32 insertions(+) diff --git a/core/shared/utils/bh_atomic.h b/core/shared/utils/bh_atomic.h index b4378c4b..64dfee1b 100644 --- a/core/shared/utils/bh_atomic.h +++ b/core/shared/utils/bh_atomic.h @@ -63,10 +63,16 @@ typedef uint32 bh_atomic_32_t; __atomic_fetch_or(&(v), (val), __ATOMIC_SEQ_CST) #define BH_ATOMIC_32_FETCH_AND(v, val) \ __atomic_fetch_and(&(v), (val), __ATOMIC_SEQ_CST) +#define BH_ATOMIC_32_FETCH_ADD(v, val) \ + __atomic_fetch_add(&(v), (val), __ATOMIC_SEQ_CST) +#define BH_ATOMIC_32_FETCH_SUB(v, val) \ + __atomic_fetch_sub(&(v), (val), __ATOMIC_SEQ_CST) #else /* else of defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) */ #define BH_ATOMIC_32_LOAD(v) (v) #define BH_ATOMIC_32_FETCH_OR(v, val) nonatomic_32_fetch_or(&(v), val) #define BH_ATOMIC_32_FETCH_AND(v, val) nonatomic_32_fetch_and(&(v), val) +#define BH_ATOMIC_32_FETCH_ADD(v, val) nonatomic_32_fetch_add(&(v), val) +#define BH_ATOMIC_32_FETCH_SUB(v, val) nonatomic_32_fetch_sub(&(v), val) static inline uint32 nonatomic_32_fetch_or(bh_atomic_32_t *p, uint32 val) @@ -84,6 +90,22 @@ nonatomic_32_fetch_and(bh_atomic_32_t *p, uint32 val) return old; } +static inline uint32 +nonatomic_32_fetch_add(bh_atomic_32_t *p, uint32 val) +{ + uint32 old = *p; + *p += val; + return old; +} + +static inline uint32 +nonatomic_32_fetch_sub(bh_atomic_32_t *p, uint32 val) +{ + uint32 old = *p; + *p -= val; + return old; +} + /* The flag can be defined by the user if the platform supports atomic access to uint32 aligned memory. */ #ifdef WASM_UINT32_IS_ATOMIC diff --git a/samples/bh_atomic/main.c b/samples/bh_atomic/main.c index adb0dd02..61c52800 100644 --- a/samples/bh_atomic/main.c +++ b/samples/bh_atomic/main.c @@ -28,5 +28,15 @@ main(int argc, char **argv) assert(o == 0x00ff00ff); assert(v == 0x00ff0000); + v = 0x00ff00ff; + o = BH_ATOMIC_32_FETCH_ADD(v, 0x10101); + assert(o == 0x00ff00ff); + assert(v == 0x00ff00ff + 0x10101); + + v = 0x00ff00ff; + o = BH_ATOMIC_32_FETCH_SUB(v, 0x10101); + assert(o == 0x00ff00ff); + assert(v == 0x00ff00ff - 0x10101); + return 0; } From 45a4e774de3e2235b3e1bf9580177768464d3b90 Mon Sep 17 00:00:00 2001 From: Cengizhan Pasaoglu Date: Mon, 31 Jul 2023 13:14:50 +0300 Subject: [PATCH 16/30] Upgrade cJSON version to v1.7.16 (#2404) --- ATTRIBUTIONS.md | 2 +- test-tools/host-tool/external/cJSON/cJSON.c | 488 +++++++++++++------- test-tools/host-tool/external/cJSON/cJSON.h | 153 +++--- 3 files changed, 423 insertions(+), 220 deletions(-) diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index 60b6bb1b..ef788bf7 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -22,7 +22,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the | third party components | version number | latest release | vendor pages | CVE details | | --- | --- | --- | --- | --- | -| cjson | 1.7.10 | 1.7.14 | https://github.com/DaveGamble/cJSON | https://www.cvedetails.com/vendor/19164/Cjson-Project.html | +| cjson | 1.7.16 | 1.7.16 | https://github.com/DaveGamble/cJSON | https://www.cvedetails.com/vendor/19164/Cjson-Project.html | | contiki-ng (er-coap) | unspecified | 3.0 | https://github.com/contiki-os/contiki | https://www.cvedetails.com/vendor/16528/Contiki-os.html | | freebsd libm | unspecified | 13.0 | https://www.freebsd.org/ | https://www.cvedetails.com/vendor/6/Freebsd.html | | LVGL | 6.0.1 | 7.11.0 | https://lvgl.io/ | | diff --git a/test-tools/host-tool/external/cJSON/cJSON.c b/test-tools/host-tool/external/cJSON/cJSON.c index 2e35351d..830d2a34 100644 --- a/test-tools/host-tool/external/cJSON/cJSON.c +++ b/test-tools/host-tool/external/cJSON/cJSON.c @@ -1,24 +1,24 @@ /* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ /* cJSON */ /* JSON parser in C. */ @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef ENABLE_LOCALES #include @@ -58,9 +59,33 @@ #include "cJSON.h" /* define our own boolean type */ +#ifdef true +#undef true +#endif #define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif #define false ((cJSON_bool)0) +/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has + * been defined in math.h */ +#ifndef isinf +#define isinf(d) (isnan((d - d)) && !isnan(d)) +#endif +#ifndef isnan +#define isnan(d) (d != d) +#endif + +#ifndef NAN +#ifdef _WIN32 +#define NAN sqrt(-1.0) +#else +#define NAN 0.0 / 0.0 +#endif +#endif + typedef struct { const unsigned char *json; size_t position; @@ -72,7 +97,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) return (const char *)(global_error.json + global_error.position); } -CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item) { if (!cJSON_IsString(item)) { return NULL; @@ -81,18 +106,27 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) return item->valuestring; } +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item) +{ + if (!cJSON_IsNumber(item)) { + return (double)NAN; + } + + return item->valuedouble; +} + /* This is a safeguard to prevent copy-pasters from using incompatible C and * header files */ #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) \ - || (CJSON_VERSION_PATCH != 10) + || (CJSON_VERSION_PATCH != 16) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif CJSON_PUBLIC(const char *) cJSON_Version(void) { static char version[15]; - snprintf(version, sizeof(version), "%i.%i.%i", CJSON_VERSION_MAJOR, - CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, + CJSON_VERSION_PATCH); return version; } @@ -127,8 +161,8 @@ typedef struct internal_hooks { } internal_hooks; #if defined(_MSC_VER) -/* work around MSVC error C2322: '...' address of dillimport '...' - is not static */ +/* work around MSVC error C2322: '...' address of dllimport '...' is not static + */ static void *CJSON_CDECL internal_malloc(size_t size) { @@ -150,13 +184,11 @@ internal_realloc(void *pointer, size_t size) #define internal_realloc realloc #endif -/* clang-format off */ -static internal_hooks global_hooks = { - internal_malloc, - internal_free, - internal_realloc -}; -/* clang-format on */ +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +static internal_hooks global_hooks = { internal_malloc, internal_free, + internal_realloc }; static unsigned char * cJSON_strdup(const unsigned char *string, const internal_hooks *const hooks) @@ -271,8 +303,8 @@ typedef struct { /* get a pointer to the buffer at the position */ #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) -/* Parse the input text to generate a number, and populate the result - into item. */ +/* Parse the input text to generate a number, and populate the result into item. + */ static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) { @@ -287,9 +319,8 @@ parse_number(cJSON *const item, parse_buffer *const input_buffer) } /* copy the number into a temporary buffer and replace '.' with the decimal - * point of the current locale (for strtod) - * This also takes care of '\0' not necessarily being available for marking - * the end of the input */ + * point of the current locale (for strtod) This also takes care of '\0' not + * necessarily being available for marking the end of the input */ for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) { @@ -363,6 +394,32 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) return object->valuedouble = number; } +CJSON_PUBLIC(char *) +cJSON_SetValuestring(cJSON *object, const char *valuestring) +{ + char *copy = NULL; + /* if object's type is not cJSON_String or is cJSON_IsReference, it should + * not set valuestring */ + if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) { + return NULL; + } + if (strlen(valuestring) <= strlen(object->valuestring)) { + strcpy(object->valuestring, valuestring); + return object->valuestring; + } + copy = + (char *)cJSON_strdup((const unsigned char *)valuestring, &global_hooks); + if (copy == NULL) { + return NULL; + } + if (object->valuestring != NULL) { + cJSON_free(object->valuestring); + } + object->valuestring = copy; + + return copy; +} + typedef struct { unsigned char *buffer; size_t length; @@ -438,9 +495,8 @@ ensure(printbuffer *const p, size_t needed) return NULL; } - if (newbuffer) { - memcpy(newbuffer, p->buffer, p->offset + 1); - } + + memcpy(newbuffer, p->buffer, p->offset + 1); p->hooks.deallocate(p->buffer); } p->length = newsize; @@ -463,6 +519,14 @@ update_offset(printbuffer *const buffer) buffer->offset += strlen((const char *)buffer_pointer); } +/* securely comparison of floating-point variables */ +static cJSON_bool +compare_double(double a, double b) +{ + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); +} + /* Render the number nicely from the given item into a string. */ static cJSON_bool print_number(const cJSON *const item, printbuffer *const output_buffer) @@ -471,35 +535,37 @@ print_number(const cJSON *const item, printbuffer *const output_buffer) double d = item->valuedouble; int length = 0; size_t i = 0; - unsigned char - number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char number_buffer[26] = { + 0 + }; /* temporary buffer to print the number into */ unsigned char decimal_point = get_decimal_point(); - double test; + double test = 0.0; if (output_buffer == NULL) { return false; } /* This checks for NaN and Infinity */ - if ((d * 0) != 0) { - length = snprintf((char *)number_buffer, sizeof(number_buffer), "null"); + if (isnan(d) || isinf(d)) { + length = sprintf((char *)number_buffer, "null"); + } + else if (d == (double)item->valueint) { + length = sprintf((char *)number_buffer, "%d", item->valueint); } else { /* Try 15 decimal places of precision to avoid nonsignificant nonzero * digits */ - length = - snprintf((char *)number_buffer, sizeof(number_buffer), "%1.15g", d); + length = sprintf((char *)number_buffer, "%1.15g", d); /* Check whether the original double can be recovered */ if ((sscanf((char *)number_buffer, "%lg", &test) != 1) - || ((double)test != d)) { + || !compare_double((double)test, d)) { /* If not, print with 17 decimal places of precision */ - length = snprintf((char *)number_buffer, sizeof(number_buffer), - "%1.17g", d); + length = sprintf((char *)number_buffer, "%1.17g", d); } } - /* snprintf failed or buffer overrun occured */ + /* sprintf failed or buffer overrun occurred */ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { return false; } @@ -709,8 +775,7 @@ parse_string(cJSON *const item, parse_buffer *const input_buffer) if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) { - goto fail; - /* string ended unexpectedly */ + goto fail; /* string ended unexpectedly */ } /* This is at most how much we need for the output */ @@ -719,8 +784,7 @@ parse_string(cJSON *const item, parse_buffer *const input_buffer) output = (unsigned char *)input_buffer->hooks.allocate(allocation_length + sizeof("")); if (output == NULL) { - goto fail; - /* allocation failure */ + goto fail; /* allocation failure */ } } @@ -759,7 +823,7 @@ parse_string(cJSON *const item, parse_buffer *const input_buffer) *output_pointer++ = input_pointer[1]; break; - /* UTF-16 literal */ + /* UTF-16 literal */ case 'u': sequence_length = utf16_literal_to_utf8( input_pointer, input_end, &output_pointer); @@ -805,7 +869,7 @@ print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer) { const unsigned char *input_pointer = NULL; - unsigned char *output = NULL, *output_end; + unsigned char *output = NULL; unsigned char *output_pointer = NULL; size_t output_length = 0; /* numbers of additional characters needed for escaping */ @@ -853,7 +917,6 @@ print_string_ptr(const unsigned char *const input, if (output == NULL) { return false; } - output_end = output + output_length + sizeof("\"\""); /* no characters have to be escaped */ if (escape_characters == 0) { @@ -902,9 +965,7 @@ print_string_ptr(const unsigned char *const input, break; default: /* escape and print as unicode codepoint */ - snprintf((char *)output_pointer, - output_end - output_pointer, "u%04x", - *input_pointer); + sprintf((char *)output_pointer, "u%04x", *input_pointer); output_pointer += 4; break; } @@ -945,6 +1006,10 @@ buffer_skip_whitespace(parse_buffer *const buffer) return NULL; } + if (cannot_access_at_index(buffer, 0)) { + return buffer; + } + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { buffer->offset++; @@ -975,10 +1040,28 @@ skip_utf8_bom(parse_buffer *const buffer) return buffer; } -/* Parse an object - create a new root, and populate. */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + size_t buffer_length; + + if (NULL == value) { + return NULL; + } + + /* Adding null character size due to require_null_terminated. */ + buffer_length = strlen(value) + sizeof(""); + + return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, + require_null_terminated); +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) +cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, + const char **return_parse_end, + cJSON_bool require_null_terminated) { parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; cJSON *item = NULL; @@ -987,12 +1070,12 @@ cJSON_ParseWithOpts(const char *value, const char **return_parse_end, global_error.json = NULL; global_error.position = 0; - if (value == NULL) { + if (value == NULL || 0 == buffer_length) { goto fail; } buffer.content = (const unsigned char *)value; - buffer.length = strlen((const char *)value) + sizeof(""); + buffer.length = buffer_length; buffer.offset = 0; buffer.hooks = global_hooks; @@ -1056,7 +1139,13 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) return cJSON_ParseWithOpts(value, 0, 0); } -#define cjson_min(a, b) ((a < b) ? a : b) +CJSON_PUBLIC(cJSON *) +cJSON_ParseWithLength(const char *value, size_t buffer_length) +{ + return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); +} + +#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) static unsigned char * print(const cJSON *const item, cJSON_bool format, @@ -1113,6 +1202,10 @@ fail: hooks->deallocate(buffer->buffer); } + if (printed != NULL) { + hooks->deallocate(printed); + } + return NULL; } @@ -1156,20 +1249,20 @@ cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) } CJSON_PUBLIC(cJSON_bool) -cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, - const cJSON_bool fmt) +cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, + const cJSON_bool format) { printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - if ((len < 0) || (buf == NULL)) { + if ((length < 0) || (buffer == NULL)) { return false; } - p.buffer = (unsigned char *)buf; - p.length = (size_t)len; + p.buffer = (unsigned char *)buffer; + p.length = (size_t)length; p.offset = 0; p.noalloc = true; - p.format = fmt; + p.format = format; p.hooks = global_hooks; return print_value(item, &p); @@ -1341,8 +1434,7 @@ parse_array(cJSON *const item, parse_buffer *const input_buffer) /* allocate next item */ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); if (new_item == NULL) { - goto fail; - /* allocation failure */ + goto fail; /* allocation failure */ } /* attach next item to list */ @@ -1361,8 +1453,7 @@ parse_array(cJSON *const item, parse_buffer *const input_buffer) input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (!parse_value(current_item, input_buffer)) { - goto fail; - /* failed to parse value */ + goto fail; /* failed to parse value */ } buffer_skip_whitespace(input_buffer); } while (can_access_at_index(input_buffer, 0) @@ -1370,13 +1461,16 @@ parse_array(cJSON *const item, parse_buffer *const input_buffer) if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { - goto fail; - /* expected end of array */ + goto fail; /* expected end of array */ } success: input_buffer->depth--; + if (head != NULL) { + head->prev = current_item; + } + item->type = cJSON_Array; item->child = head; @@ -1461,16 +1555,14 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer) if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) { - goto fail; - /* not an object */ + goto fail; /* not an object */ } input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) { - goto success; - /* empty object */ + goto success; /* empty object */ } /* check if we skipped to the end of the buffer */ @@ -1486,8 +1578,7 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer) /* allocate next item */ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); if (new_item == NULL) { - goto fail; - /* allocation failure */ + goto fail; /* allocation failure */ } /* attach next item to list */ @@ -1506,8 +1597,7 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer) input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (!parse_string(current_item, input_buffer)) { - goto fail; - /* faile to parse name */ + goto fail; /* failed to parse name */ } buffer_skip_whitespace(input_buffer); @@ -1517,16 +1607,14 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer) if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) { - goto fail; - /* invalid object */ + goto fail; /* invalid object */ } /* parse the value */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (!parse_value(current_item, input_buffer)) { - goto fail; - /* failed to parse value */ + goto fail; /* failed to parse value */ } buffer_skip_whitespace(input_buffer); } while (can_access_at_index(input_buffer, 0) @@ -1534,13 +1622,16 @@ parse_object(cJSON *const item, parse_buffer *const input_buffer) if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) { - goto fail; - /* expected end of object */ + goto fail; /* expected end of object */ } success: input_buffer->depth--; + if (head != NULL) { + head->prev = current_item; + } + item->type = cJSON_Object; item->child = head; @@ -1792,22 +1883,26 @@ add_item_to_array(cJSON *array, cJSON *item) { cJSON *child = NULL; - if ((item == NULL) || (array == NULL)) { + if ((item == NULL) || (array == NULL) || (array == item)) { return false; } child = array->child; - + /* + * To find the last item in array quickly, we use prev in array + */ if (child == NULL) { /* list is empty, start new one */ array->child = item; + item->prev = item; + item->next = NULL; } else { /* append to the end */ - while (child->next) { - child = child->next; + if (child->prev) { + suffix_object(child->prev, item); + array->child->prev = item; } - suffix_object(child, item); } return true; @@ -1847,7 +1942,8 @@ add_item_to_object(cJSON *const object, const char *const string, char *new_key = NULL; int new_type = cJSON_Invalid; - if ((object == NULL) || (string == NULL) || (item == NULL)) { + if ((object == NULL) || (string == NULL) || (item == NULL) + || (object == item)) { return false; } @@ -2028,7 +2124,7 @@ cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item) return NULL; } - if (item->prev != NULL) { + if (item != parent->child) { /* not the first element */ item->prev->next = item->next; } @@ -2041,6 +2137,11 @@ cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item) /* first element */ parent->child = item->next; } + else if (item->next == NULL) { + /* last element */ + parent->child->prev = item->prev; + } + /* make sure the detached item doesn't point anywhere anymore */ item->prev = NULL; item->next = NULL; @@ -2121,7 +2222,8 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, cJSON *replacement) { - if ((parent == NULL) || (replacement == NULL) || (item == NULL)) { + if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL) + || (item == NULL)) { return false; } @@ -2135,12 +2237,24 @@ cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, if (replacement->next != NULL) { replacement->next->prev = replacement; } - if (replacement->prev != NULL) { - replacement->prev->next = replacement; - } if (parent->child == item) { + if (parent->child->prev == parent->child) { + replacement->prev = replacement; + } parent->child = replacement; } + else { /* + * To find the last item in array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was + * the parent's child + */ + if (replacement->prev != NULL) { + replacement->prev->next = replacement; + } + if (replacement->next == NULL) { + parent->child->prev = replacement; + } + } item->next = NULL; item->prev = NULL; @@ -2149,15 +2263,15 @@ cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, return true; } -CJSON_PUBLIC(void) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) { if (which < 0) { - return; + return false; } - cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), - newitem); + return cJSON_ReplaceItemViaPointer( + array, get_array_item(array, (size_t)which), newitem); } static cJSON_bool @@ -2175,25 +2289,27 @@ replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, } replacement->string = (char *)cJSON_strdup((const unsigned char *)string, &global_hooks); + if (replacement->string == NULL) { + return false; + } + replacement->type &= ~cJSON_StringIsConst; - cJSON_ReplaceItemViaPointer( + return cJSON_ReplaceItemViaPointer( object, get_object_item(object, string, case_sensitive), replacement); - - return true; } -CJSON_PUBLIC(void) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) { - replace_item_in_object(object, string, newitem, false); + return replace_item_in_object(object, string, newitem, false); } -CJSON_PUBLIC(void) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) { - replace_item_in_object(object, string, newitem, true); + return replace_item_in_object(object, string, newitem, true); } /* Create basic types: */ @@ -2227,11 +2343,11 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) return item; } -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) { cJSON *item = cJSON_New_Item(&global_hooks); if (item) { - item->type = b ? cJSON_True : cJSON_False; + item->type = boolean ? cJSON_True : cJSON_False; } return item; @@ -2357,6 +2473,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) } a = cJSON_CreateArray(); + for (i = 0; a && (i < (size_t)count); i++) { n = cJSON_CreateNumber(numbers[i]); if (!n) { @@ -2372,6 +2489,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) p = n; } + if (a && a->child) { + a->child->prev = n; + } + return a; } @@ -2403,6 +2524,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) p = n; } + if (a && a->child) { + a->child->prev = n; + } + return a; } @@ -2434,10 +2559,15 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) p = n; } + if (a && a->child) { + a->child->prev = n; + } + return a; } -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +CJSON_PUBLIC(cJSON *) +cJSON_CreateStringArray(const char *const *strings, int count) { size_t i = 0; cJSON *n = NULL; @@ -2465,6 +2595,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) p = n; } + if (a && a->child) { + a->child->prev = n; + } + return a; } @@ -2532,6 +2666,9 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) } child = child->next; } + if (newitem && newitem->child) { + newitem->child->prev = newchild; + } return newitem; @@ -2543,55 +2680,93 @@ fail: return NULL; } +static void +skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void +skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) { + if (((*input)[0] == '*') && ((*input)[1] == '/')) { + *input += static_strlen("*/"); + return; + } + } +} + +static void +minify_string(char **input, char **output) +{ + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } + else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + CJSON_PUBLIC(void) cJSON_Minify(char *json) { - unsigned char *into = (unsigned char *)json; + char *into = json; if (json == NULL) { return; } - while (*json) { - if (*json == ' ') { - json++; - } - else if (*json == '\t') { - /* Whitespace characters. */ - json++; - } - else if (*json == '\r') { - json++; - } - else if (*json == '\n') { - json++; - } - else if ((*json == '/') && (json[1] == '/')) { - /* double-slash comments, to end of line. */ - while (*json && (*json != '\n')) { + while (json[0] != '\0') { + switch (json[0]) { + case ' ': + case '\t': + case '\r': + case '\n': json++; - } - } - else if ((*json == '/') && (json[1] == '*')) { - /* multiline comments. */ - while (*json && !((*json == '*') && (json[1] == '/'))) { - json++; - } - json += 2; - } - else if (*json == '\"') { - /* string literals, which are \" sensitive. */ - *into++ = (unsigned char)*json++; - while (*json && (*json != '\"')) { - if (*json == '\\') { - *into++ = (unsigned char)*json++; + break; + + case '/': + if (json[1] == '/') { + skip_oneline_comment(&json); } - *into++ = (unsigned char)*json++; - } - *into++ = (unsigned char)*json++; - } - else { - /* All other characters. */ - *into++ = (unsigned char)*json++; + else if (json[1] == '*') { + skip_multiline_comment(&json); + } + else { + json++; + } + break; + + case '\"': + minify_string(&json, (char **)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; } } @@ -2692,8 +2867,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive) { - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) - || cJSON_IsInvalid(a)) { + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) { return false; } @@ -2726,7 +2900,7 @@ cJSON_Compare(const cJSON *const a, const cJSON *const b, return true; case cJSON_Number: - if (a->valuedouble == b->valuedouble) { + if (compare_double(a->valuedouble, b->valuedouble)) { return true; } return false; diff --git a/test-tools/host-tool/external/cJSON/cJSON.h b/test-tools/host-tool/external/cJSON/cJSON.h index d437196a..2cafdcf5 100644 --- a/test-tools/host-tool/external/cJSON/cJSON.h +++ b/test-tools/host-tool/external/cJSON/cJSON.h @@ -1,24 +1,24 @@ /* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ #ifndef cJSON__h #define cJSON__h @@ -35,30 +35,34 @@ extern "C" { #ifdef __WINDOWS__ -/** - * When compiling for windows, we specify a specific calling convention to avoid - * issues where we are being called from a project with a different default - * calling convention. For windows you have 3 define options: - * CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever - * dllexport symbols - * CJSON_EXPORT_SYMBOLS - Define this on library build when you want to - * dllexport symbols (default) - * CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol - * - * For *nix builds that support visibility attribute, you can define similar - * behavior by setting default visibility to hidden by adding - * -fvisibility=hidden (for gcc) - * or - * -xldscope=hidden (for sun cc) - * to CFLAGS, then using the CJSON_API_VISIBILITY flag to "export" the same - * symbols the way CJSON_EXPORT_SYMBOLS does - */ +/* When compiling for windows, we specify a specific calling convention to avoid +issues where we are being called from a project with a different default calling +convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever +dllexport symbols CJSON_EXPORT_SYMBOLS - Define this on library build when you +want to dllexport symbols (default) CJSON_IMPORT_SYMBOLS - Define this if you +want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar +behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way +CJSON_EXPORT_SYMBOLS does + +*/ #define CJSON_CDECL __cdecl #define CJSON_STDCALL __stdcall /* export symbols by default, this is necessary for copy pasting the C and - header file */ + * header file */ #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) \ && !defined(CJSON_EXPORT_SYMBOLS) #define CJSON_EXPORT_SYMBOLS @@ -86,7 +90,7 @@ extern "C" { /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 10 +#define CJSON_VERSION_PATCH 16 #include @@ -107,11 +111,11 @@ extern "C" { /* The cJSON structure: */ typedef struct cJSON { /* next/prev allow you to walk array/object chains. Alternatively, use - GetArraySize/GetArrayItem/GetObjectItem */ + * GetArraySize/GetArrayItem/GetObjectItem */ struct cJSON *next; struct cJSON *prev; /* An array or object item will have a child pointer pointing to a chain of - the items in the array/object. */ + * the items in the array/object. */ struct cJSON *child; /* The type of the item, as above. */ @@ -125,7 +129,7 @@ typedef struct cJSON { double valuedouble; /* The item's name string, if this item is the child of, or is in the list - of subitems of an object. */ + * of subitems of an object. */ char *string; } cJSON; @@ -140,7 +144,7 @@ typedef struct cJSON_Hooks { typedef int cJSON_bool; /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse - them. This is to prevent stack overflows. */ + * them. This is to prevent stack overflows. */ #ifndef CJSON_NESTING_LIMIT #define CJSON_NESTING_LIMIT 1000 #endif @@ -159,6 +163,8 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks *hooks); /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +CJSON_PUBLIC(cJSON *) +cJSON_ParseWithLength(const char *value, size_t buffer_length); /* ParseWithOpts allows you to require (and check) that the JSON is null * terminated, and to retrieve the pointer to the final byte parsed. */ /* If you supply a ptr in return_parse_end and parsing fails, then @@ -167,6 +173,10 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); +CJSON_PUBLIC(cJSON *) +cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, + const char **return_parse_end, + cJSON_bool require_null_terminated); /* Render a cJSON entity to text for transfer/storage. */ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); @@ -185,7 +195,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); /* Delete a cJSON entity and all subentities. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); /* Returns the number of items in an array (or object). */ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); @@ -205,8 +215,9 @@ cJSON_HasObjectItem(const cJSON *object, const char *string); * when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); -/* Check if the item is a string and return its valuestring */ -CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); +/* Check item type and return its value */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item); +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item); /* These functions check the type of an item */ CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON *const item); @@ -233,18 +244,21 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); /* Create a string where valuestring references a string so - it will not be freed by cJSON_Delete */ + * it will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); -/* Create an object/arrray that only references it's elements so - they will not be freed by cJSON_Delete */ +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); -/* These utilities create an Array of count items. */ +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the + * number array, otherwise array access will be out of bounds.*/ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); +CJSON_PUBLIC(cJSON *) +cJSON_CreateStringArray(const char *const *strings, int count); /* Append item to the specified array/object. */ CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); @@ -264,7 +278,7 @@ cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); -/* Remove/Detatch items from Arrays/Objects. */ +/* Remove/Detach items from Arrays/Objects. */ CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); @@ -286,32 +300,35 @@ cJSON_InsertItemInArray( CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, cJSON *replacement); -CJSON_PUBLIC(void) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); -CJSON_PUBLIC(void) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem); -CJSON_PUBLIC(void) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem); /* Duplicate a cJSON item */ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); /* Duplicate will create a new, identical cJSON item to the one you pass, in new - memory that will need to be released. With recurse!=0, it will duplicate any - children connected to the item. The item->next and ->prev pointers are always - zero on return from Duplicate. */ + * memory that will need to be released. With recurse!=0, it will duplicate any + * children connected to the item. The item->next and ->prev pointers are always + * zero on return from Duplicate. */ /* Recursively compare two cJSON items for equality. If either a or b is NULL or - * invalid, they will be considered unequal. - * case_sensitive determines if object keys are treated case sensitive (1) or - * case insensitive (0) */ + * invalid, they will be considered unequal. case_sensitive determines if object + * keys are treated case sensitive (1) or case insensitive (0) */ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive); +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from + * strings. The input pointer json cannot point to a read-only address area, + * such as a string constant, but should point to a readable and writable + * address area. */ CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Helper functions for creating and adding items to an object at the same time. - They return the added item or NULL on failure. */ + * They return the added item or NULL on failure. */ CJSON_PUBLIC(cJSON *) cJSON_AddNullToObject(cJSON *const object, const char *const name); CJSON_PUBLIC(cJSON *) @@ -336,7 +353,7 @@ CJSON_PUBLIC(cJSON *) cJSON_AddArrayToObject(cJSON *const object, const char *const name); /* When assigning an integer value, it needs to be propagated to valuedouble - too. */ + * too. */ #define cJSON_SetIntValue(object, number) \ ((object) ? (object)->valueint = (object)->valuedouble = (number) \ : (number)) @@ -345,6 +362,18 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); #define cJSON_SetNumberValue(object, number) \ ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) \ : (number)) +/* Change the valuestring of a cJSON_String object, only takes effect when type + * of object is cJSON_String */ +CJSON_PUBLIC(char *) +cJSON_SetValuestring(cJSON *object, const char *valuestring); + +/* If the object is not a boolean type this does nothing and returns + * cJSON_Invalid else it returns the new type*/ +#define cJSON_SetBoolValue(object, boolValue) \ + ((object != NULL && ((object)->type & (cJSON_False | cJSON_True))) \ + ? (object)->type = ((object)->type & (~(cJSON_False | cJSON_True))) \ + | ((boolValue) ? cJSON_True : cJSON_False) \ + : cJSON_Invalid) /* Macro for iterating over an array or object */ #define cJSON_ArrayForEach(element, array) \ @@ -352,7 +381,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); element = element->next) /* malloc/free objects using the malloc/free functions that have been set with - cJSON_InitHooks */ + * cJSON_InitHooks */ CJSON_PUBLIC(void *) cJSON_malloc(size_t size); CJSON_PUBLIC(void) cJSON_free(void *object); From edea32b6291c2b39b21db210149e5f414faf46c9 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 31 Jul 2023 18:20:11 +0800 Subject: [PATCH 17/30] Fix result arity check on select_t opcode (#2406) Typed select must have exactly one result. Reported in issue #2402. --- core/iwasm/interpreter/wasm_loader.c | 3 ++- core/iwasm/interpreter/wasm_mini_loader.c | 3 ++- .../spec-test-script/ignore_cases.patch | 20 ------------------- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index f1a71a8a..08441ec3 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -8066,7 +8066,8 @@ re_scan: uint8 vec_len, ref_type; read_leb_uint32(p, p_end, vec_len); - if (!vec_len) { + if (vec_len != 1) { + /* typed select must have exactly one result */ set_error_buf(error_buf, error_buf_size, "invalid result arity"); goto fail; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index fc637a5a..0aba1462 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -6235,7 +6235,8 @@ re_scan: uint8 vec_len, ref_type; read_leb_uint32(p, p_end, vec_len); - if (!vec_len) { + if (vec_len != 1) { + /* typed select must have exactly one result */ set_error_buf(error_buf, error_buf_size, "invalid result arity"); goto fail; diff --git a/tests/wamr-test-suites/spec-test-script/ignore_cases.patch b/tests/wamr-test-suites/spec-test-script/ignore_cases.patch index 1d94d91a..bfb4383f 100644 --- a/tests/wamr-test-suites/spec-test-script/ignore_cases.patch +++ b/tests/wamr-test-suites/spec-test-script/ignore_cases.patch @@ -343,26 +343,6 @@ index adb5cb7..590f626 100644 (func $g (param $x i32) (result i32) (i32.add (local.get $x) (i32.const 1)) ) -diff --git a/test/core/select.wast b/test/core/select.wast -index 046e6fe..b677023 100644 ---- a/test/core/select.wast -+++ b/test/core/select.wast -@@ -324,6 +324,7 @@ - (module (func $arity-0 (select (result) (nop) (nop) (i32.const 1)))) - "invalid result arity" - ) -+(; - (assert_invalid - (module (func $arity-2 (result i32 i32) - (select (result i32 i32) -@@ -334,6 +335,7 @@ - )) - "invalid result arity" - ) -+;) - - - (assert_invalid diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index 380e84e..f37e745 100644 --- a/test/core/table_copy.wast From 84ecf1532224a52c2db74355289aadead7890d49 Mon Sep 17 00:00:00 2001 From: Cengizhan Pasaoglu Date: Mon, 31 Jul 2023 13:32:20 +0300 Subject: [PATCH 18/30] Update libuv version to v1.46.0 (#2405) --- ATTRIBUTIONS.md | 2 +- core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index ef788bf7..c772b969 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -31,7 +31,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the | wasmtime | unspecified | v0.26.0 | https://github.com/bytecodealliance/wasmtime | | | zephyr | unspecified | v2.5.0 | https://www.zephyrproject.org/ | https://www.cvedetails.com/vendor/19255/Zephyrproject.html | | WebAssembly debugging patch for LLDB | unspecified | unspecified | https://reviews.llvm.org/D78801 | | -| libuv | v1.42.0 | v1.44.1 | https://github.com/libuv/libuv | https://www.cvedetails.com/vendor/15402/Libuv-Project.html | +| libuv | v1.46.0 | v1.46.0 | https://github.com/libuv/libuv | https://www.cvedetails.com/vendor/15402/Libuv-Project.html | | uvwasi | unspecified | v0.0.12 | https://github.com/nodejs/uvwasi | | | asmjit | unspecified | unspecified | https://github.com/asmjit/asmjit | | | zydis | unspecified | e14a07895136182a5b53e181eec3b1c6e0b434de | https://github.com/zyantific/zydis | | diff --git a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake index 6614df50..7a3bfbdc 100644 --- a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake +++ b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake @@ -3,7 +3,7 @@ set (LIBC_WASI_DIR ${CMAKE_CURRENT_LIST_DIR}) -set (LIBUV_VERSION v1.44.2) +set (LIBUV_VERSION v1.46.0) add_definitions (-DWASM_ENABLE_LIBC_WASI=1 -DWASM_ENABLE_UVWASI=1) From 851819705324419376a63c23fe2e5acb17ce9d8c Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Mon, 31 Jul 2023 20:14:44 +0900 Subject: [PATCH 19/30] Remove a few unused functions (#2409) They have been unused since commit 5fc48e3584baa05514878997b6949e365626f977 --- core/iwasm/common/wasm_memory.c | 36 --------------------------------- core/iwasm/common/wasm_memory.h | 10 --------- 2 files changed, 46 deletions(-) diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index b2ec2a89..9db7fa14 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -782,39 +782,3 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) return ret; } - -#if !defined(OS_ENABLE_HW_BOUND_CHECK) \ - || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ - || WASM_ENABLE_BULK_MEMORY != 0 -uint32 -wasm_get_num_bytes_per_page(WASMMemoryInstance *memory, void *node) -{ - uint32 num_bytes_per_page; -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (node) - os_mutex_lock(&((WASMSharedMemNode *)node)->shared_mem_lock); -#endif - num_bytes_per_page = memory->num_bytes_per_page; -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (node) - os_mutex_unlock(&((WASMSharedMemNode *)node)->shared_mem_lock); -#endif - return num_bytes_per_page; -} - -uint32 -wasm_get_linear_memory_size(WASMMemoryInstance *memory, void *node) -{ - uint32 linear_mem_size; -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (node) - os_mutex_lock(&((WASMSharedMemNode *)node)->shared_mem_lock); -#endif - linear_mem_size = memory->num_bytes_per_page * memory->cur_page_count; -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (node) - os_mutex_unlock(&((WASMSharedMemNode *)node)->shared_mem_lock); -#endif - return linear_mem_size; -} -#endif diff --git a/core/iwasm/common/wasm_memory.h b/core/iwasm/common/wasm_memory.h index 1324742f..516ee849 100644 --- a/core/iwasm/common/wasm_memory.h +++ b/core/iwasm/common/wasm_memory.h @@ -24,16 +24,6 @@ wasm_runtime_memory_destroy(); unsigned wasm_runtime_memory_pool_size(); -#if !defined(OS_ENABLE_HW_BOUND_CHECK) \ - || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ - || WASM_ENABLE_BULK_MEMORY != 0 -uint32 -wasm_get_num_bytes_per_page(WASMMemoryInstance *memory, void *node); - -uint32 -wasm_get_linear_memory_size(WASMMemoryInstance *memory, void *node); -#endif - #ifdef __cplusplus } #endif From 4b1f027690bba0069c825807d7f9493c53fa83ca Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Tue, 1 Aug 2023 17:28:57 +0800 Subject: [PATCH 20/30] Re-organize intrinsics in aot_reloc_riscv.c to fix some FPU issues (#2414) --- core/iwasm/aot/arch/aot_reloc_riscv.c | 34 ++++++++++++--------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/core/iwasm/aot/arch/aot_reloc_riscv.c b/core/iwasm/aot/arch/aot_reloc_riscv.c index 21931902..7798d55c 100644 --- a/core/iwasm/aot/arch/aot_reloc_riscv.c +++ b/core/iwasm/aot/arch/aot_reloc_riscv.c @@ -78,6 +78,13 @@ static SymbolMap target_sym_map[] = { REG_SYM(__addsf3), REG_SYM(__divdf3), REG_SYM(__divsf3), + REG_SYM(__eqdf2), + REG_SYM(__eqsf2), + REG_SYM(__extendsfdf2), + REG_SYM(__fixunsdfdi), + REG_SYM(__fixunsdfsi), + REG_SYM(__fixunssfdi), + REG_SYM(__fixunssfsi), REG_SYM(__gedf2), REG_SYM(__gesf2), REG_SYM(__gtdf2), @@ -89,44 +96,33 @@ static SymbolMap target_sym_map[] = { REG_SYM(__muldf3), REG_SYM(__nedf2), REG_SYM(__nesf2), - REG_SYM(__eqsf2), - REG_SYM(__eqdf2), - REG_SYM(__extendsfdf2), - REG_SYM(__fixunsdfdi), - REG_SYM(__fixunsdfsi), - REG_SYM(__fixunssfsi), REG_SYM(__subdf3), REG_SYM(__subsf3), REG_SYM(__truncdfsf2), REG_SYM(__unorddf2), REG_SYM(__unordsf2), -#endif - REG_SYM(__divdi3), - REG_SYM(__divsi3), #if __riscv_xlen == 32 REG_SYM(__fixdfdi), REG_SYM(__fixdfsi), REG_SYM(__fixsfdi), REG_SYM(__fixsfsi), -#endif - REG_SYM(__fixunssfdi), -#if __riscv_xlen == 32 REG_SYM(__floatdidf), REG_SYM(__floatdisf), - REG_SYM(__floatsisf), REG_SYM(__floatsidf), + REG_SYM(__floatsisf), REG_SYM(__floatundidf), REG_SYM(__floatundisf), - REG_SYM(__floatunsisf), REG_SYM(__floatunsidf), -#endif - REG_SYM(__moddi3), - REG_SYM(__modsi3), - REG_SYM(__muldi3), -#if __riscv_xlen == 32 + REG_SYM(__floatunsisf), REG_SYM(__mulsf3), REG_SYM(__mulsi3), #endif +#endif + REG_SYM(__divdi3), + REG_SYM(__divsi3), + REG_SYM(__moddi3), + REG_SYM(__modsi3), + REG_SYM(__muldi3), REG_SYM(__udivdi3), REG_SYM(__udivsi3), REG_SYM(__umoddi3), From b88f2c06c66a24eb40e12508ce3ea9cc2754b035 Mon Sep 17 00:00:00 2001 From: Maks Litskevich Date: Tue, 1 Aug 2023 10:38:37 +0100 Subject: [PATCH 21/30] Add initial stress test (#2364) We need to make a test that runs longer than the tests we had before to check some problems that might happen after running for some time (e.g. memory corruption or something else). --- .../compilation_on_android_ubuntu.yml | 4 +- .github/workflows/nightly_run.yml | 4 +- .../libraries/lib-wasi-threads/test/build.sh | 5 +- .../lib-wasi-threads/test/manifest.json | 3 + .../libraries/lib-wasi-threads/test/skip.json | 5 + .../lib-wasi-threads/test/spawn_stress_test.c | 114 ++++++++++++++++++ .../wasi-test-script/run_wasi_tests.sh | 40 ++++-- 7 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 core/iwasm/libraries/lib-wasi-threads/test/manifest.json create mode 100644 core/iwasm/libraries/lib-wasi-threads/test/skip.json create mode 100644 core/iwasm/libraries/lib-wasi-threads/test/spawn_stress_test.c diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index f965d200..5a0939b7 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -527,7 +527,7 @@ jobs: working-directory: ./core/iwasm/libraries/lib-socket/test/ - name: run tests - timeout-minutes: 10 + timeout-minutes: 20 run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} working-directory: ./tests/wamr-test-suites @@ -543,7 +543,7 @@ jobs: sudo apt install -y g++-multilib lib32gcc-9-dev - name: run tests x86_32 - timeout-minutes: 10 + timeout-minutes: 20 if: env.TEST_ON_X86_32 == 'true' run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }} working-directory: ./tests/wamr-test-suites diff --git a/.github/workflows/nightly_run.yml b/.github/workflows/nightly_run.yml index 4664ad63..cea5dccb 100644 --- a/.github/workflows/nightly_run.yml +++ b/.github/workflows/nightly_run.yml @@ -595,7 +595,7 @@ jobs: working-directory: ./core/iwasm/libraries/lib-socket/test/ - name: run tests - timeout-minutes: 10 + timeout-minutes: 20 run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} working-directory: ./tests/wamr-test-suites @@ -611,7 +611,7 @@ jobs: sudo apt install -y g++-multilib lib32gcc-9-dev - name: run tests x86_32 - timeout-minutes: 10 + timeout-minutes: 20 if: env.TEST_ON_X86_32 == 'true' run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }} working-directory: ./tests/wamr-test-suites \ No newline at end of file diff --git a/core/iwasm/libraries/lib-wasi-threads/test/build.sh b/core/iwasm/libraries/lib-wasi-threads/test/build.sh index 32586c20..611a3bd4 100755 --- a/core/iwasm/libraries/lib-wasi-threads/test/build.sh +++ b/core/iwasm/libraries/lib-wasi-threads/test/build.sh @@ -9,10 +9,13 @@ set -eo pipefail CC=${CC:=/opt/wasi-sdk/bin/clang} WAMR_DIR=../../../../.. +# Stress tests names +thread_start_file_exclusions=("spawn_stress_test.wasm" "linear_memory_size_update.wasm") + for test_c in *.c; do test_wasm="$(basename $test_c .c).wasm" - if [ $test_wasm = "linear_memory_size_update.wasm" ]; then + if [[ " ${thread_start_file_exclusions[@]} " =~ " ${test_wasm} " ]] ; then thread_start_file="" else thread_start_file=$WAMR_DIR/samples/wasi-threads/wasm-apps/wasi_thread_start.S diff --git a/core/iwasm/libraries/lib-wasi-threads/test/manifest.json b/core/iwasm/libraries/lib-wasi-threads/test/manifest.json new file mode 100644 index 00000000..cd2cc763 --- /dev/null +++ b/core/iwasm/libraries/lib-wasi-threads/test/manifest.json @@ -0,0 +1,3 @@ +{ + "name": "lib-wasi-threads tests" +} diff --git a/core/iwasm/libraries/lib-wasi-threads/test/skip.json b/core/iwasm/libraries/lib-wasi-threads/test/skip.json new file mode 100644 index 00000000..87db7667 --- /dev/null +++ b/core/iwasm/libraries/lib-wasi-threads/test/skip.json @@ -0,0 +1,5 @@ +{ + "lib-wasi-threads tests": { + "spawn_stress_test": "Stress tests are incompatible with the other part and executed differently" + } +} diff --git a/core/iwasm/libraries/lib-wasi-threads/test/spawn_stress_test.c b/core/iwasm/libraries/lib-wasi-threads/test/spawn_stress_test.c new file mode 100644 index 00000000..35175fc3 --- /dev/null +++ b/core/iwasm/libraries/lib-wasi-threads/test/spawn_stress_test.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +enum CONSTANTS { + NUM_ITER = 100000, + NUM_RETRY = 5, + MAX_NUM_THREADS = 8, +}; + +unsigned prime_numbers_count = 0; + +bool +is_prime(unsigned int num) +{ + for (unsigned int i = 2; i <= (unsigned int)(sqrt(num)); ++i) { + if (num % i == 0) { + return false; + } + } + + return true; +} + +void * +check_if_prime(void *value) +{ + unsigned int *num = (unsigned int *)(value); + usleep(10000); + if (is_prime(*num)) { + __atomic_fetch_add(&prime_numbers_count, 1, __ATOMIC_SEQ_CST); + } + return NULL; +} + +unsigned int +validate() +{ + unsigned int counter = 0; + for (unsigned int i = 2; i <= NUM_ITER; ++i) { + counter += is_prime(i); + } + + return counter; +} + +void +spawn_thread(pthread_t *thread, unsigned int *arg) +{ + int status_code = -1; + for (int tries = 0; status_code != 0 && tries < NUM_RETRY; ++tries) { + status_code = pthread_create(thread, NULL, &check_if_prime, arg); + assert(status_code == 0 || status_code == EAGAIN); + if (status_code == EAGAIN) { + usleep(2000); + } + } + + assert(status_code == 0 && "Thread creation should succeed"); +} + +int +main(int argc, char **argv) +{ + pthread_t threads[MAX_NUM_THREADS]; + unsigned int args[MAX_NUM_THREADS]; + double percentage = 0.1; + + for (unsigned int factorised_number = 2; factorised_number < NUM_ITER; + ++factorised_number) { + if (factorised_number > NUM_ITER * percentage) { + fprintf(stderr, "Stress test is %d%% finished\n", + (unsigned int)(percentage * 100)); + percentage += 0.1; + } + + unsigned int thread_num = factorised_number % MAX_NUM_THREADS; + if (threads[thread_num] != 0) { + assert(pthread_join(threads[thread_num], NULL) == 0); + } + + args[thread_num] = factorised_number; + + usleep(2000); + spawn_thread(&threads[thread_num], &args[thread_num]); + assert(threads[thread_num] != 0); + } + + for (int i = 0; i < MAX_NUM_THREADS; ++i) { + assert(threads[i] == 0 || pthread_join(threads[i], NULL) == 0); + } + + // Check the test results + assert( + prime_numbers_count == validate() + && "Answer mismatch between tested code and reference implementation"); + + fprintf(stderr, "Stress test finished successfully\n"); + return 0; +} diff --git a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh index 7738b508..9f13ee08 100755 --- a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh +++ b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh @@ -14,6 +14,7 @@ readonly WAMR_DIR="${WORK_DIR}/../../../.." readonly IWASM_CMD="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm \ --allow-resolve=google-public-dns-a.google.com \ --addr-pool=::1/128,127.0.0.1/32" +readonly IWASM_CMD_STRESS="${IWASM_CMD} --max-threads=8" readonly WAMRC_CMD="${WORK_DIR}/../../../../wamr-compiler/build/wamrc" readonly C_TESTS="tests/c/testsuite/" readonly ASSEMBLYSCRIPT_TESTS="tests/assemblyscript/testsuite/" @@ -24,6 +25,11 @@ readonly LIB_SOCKET_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-socket/test/" run_aot_tests () { local tests=("$@") for test_wasm in ${tests[@]}; do + local extra_stress_flags="" + if [[ "$test_wasm" =~ "stress" ]]; then + extra_stress_flags="--max-threads=8" + fi + test_aot="${test_wasm%.wasm}.aot" test_json="${test_wasm%.wasm}.json" @@ -41,7 +47,7 @@ run_aot_tests () { expected=$(jq .exit_code ${test_json}) fi - ${IWASM_CMD} $test_aot + ${IWASM_CMD} $extra_stress_flags $test_aot ret=${PIPESTATUS[0]} @@ -55,15 +61,31 @@ run_aot_tests () { if [[ $MODE != "aot" ]];then python3 -m venv wasi-env && source wasi-env/bin/activate python3 -m pip install -r test-runner/requirements.txt + + # Stress test requires max-threads=8 so it's run separately + if [[ -e "${THREAD_INTERNAL_TESTS}spawn_stress_test.wasm" ]]; then + ${IWASM_CMD_STRESS} ${THREAD_INTERNAL_TESTS}spawn_stress_test.wasm + ret=${PIPESTATUS[0]} + if [ "${ret}" -ne 0 ]; then + echo "Stress test spawn_stress_test FAILED with code " ${ret} + exit_code=${ret} + fi + fi + TEST_RUNTIME_EXE="${IWASM_CMD}" python3 test-runner/wasi_test_runner.py \ - -r adapters/wasm-micro-runtime.py \ - -t \ - ${C_TESTS} \ - ${ASSEMBLYSCRIPT_TESTS} \ - ${THREAD_PROPOSAL_TESTS} \ - ${THREAD_INTERNAL_TESTS} \ - ${LIB_SOCKET_TESTS} - exit_code=${PIPESTATUS[0]} + -r adapters/wasm-micro-runtime.py \ + -t \ + ${C_TESTS} \ + ${ASSEMBLYSCRIPT_TESTS} \ + ${THREAD_PROPOSAL_TESTS} \ + ${THREAD_INTERNAL_TESTS} \ + ${LIB_SOCKET_TESTS} \ + --exclude-filter "${THREAD_INTERNAL_TESTS}skip.json" + + ret=${PIPESTATUS[0]} + if [ "${ret}" -ne 0 ]; then + exit_code=${ret} + fi deactivate else target_option="" From cb6d85069ece487d50a64cf08b4f82e5b3deeba9 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 1 Aug 2023 18:11:58 +0800 Subject: [PATCH 22/30] Fix lib-pthread issues (#2410) - Avoid destroying module instance repeatedly in pthread_exit_wrapper and wasm_thread_cluster_exit. - Wait enough time in pthread_join_wrapper for target thread to exit and destroy its resources. --- .../libraries/lib-pthread/lib_pthread_wrapper.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 8876d51b..1a41fe9d 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -691,6 +691,14 @@ pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread, bh_assert(node->joinable); join_ret = 0; ret = node->u.ret; + + /* The target thread changes the node's status before calling + wasm_cluster_exit_thread to exit, so here its resources may + haven't been destroyed yet, we wait enough time to ensure that + they are actually destroyed to avoid unexpected behavior. */ + os_mutex_lock(&exec_env->wait_lock); + os_cond_reltimedwait(&exec_env->wait_cond, &exec_env->wait_lock, 1000); + os_mutex_unlock(&exec_env->wait_lock); } if (retval_offset != 0) @@ -758,7 +766,6 @@ __pthread_self_wrapper(wasm_exec_env_t exec_env) static void pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) { - wasm_module_inst_t module_inst = get_module_inst(exec_env); ThreadRoutineArgs *args = get_thread_arg(exec_env); /* Currently exit main thread is not allowed */ if (!args) @@ -776,9 +783,6 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) /* destroy pthread key values */ call_key_destructor(exec_env); - /* routine exit, destroy instance */ - wasm_runtime_deinstantiate_internal(module_inst, true); - if (!args->info_node->joinable) { delete_thread_info_node(args->info_node); } @@ -790,6 +794,8 @@ pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) wasm_runtime_free(args); + /* Don't destroy exec_env->module_inst in this functuntion since + it will be destroyed in wasm_cluster_exit_thread */ wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset); } From ecd4fccc964653b006515153ab5df81f1618cb40 Mon Sep 17 00:00:00 2001 From: "liang.he" Date: Tue, 1 Aug 2023 19:13:00 +0800 Subject: [PATCH 23/30] Upgrade XNNPACK workload (#2394) - Sync source code to b9d4073a6913891ce9cbd8965c8d506075d2a45a, which is referred by tensorflow - Upgrade emscripten to 3.1.44 - CMake outputs are .wasm files and .aot files --- samples/workload/XNNPACK/CMakeLists.txt | 315 ++++++++++++++---------- samples/workload/XNNPACK/README.md | 51 ++-- samples/workload/XNNPACK/xnnpack.patch | 193 +++++++-------- 3 files changed, 304 insertions(+), 255 deletions(-) diff --git a/samples/workload/XNNPACK/CMakeLists.txt b/samples/workload/XNNPACK/CMakeLists.txt index aef138d5..93181cd9 100644 --- a/samples/workload/XNNPACK/CMakeLists.txt +++ b/samples/workload/XNNPACK/CMakeLists.txt @@ -1,147 +1,198 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 3.0) +cmake_minimum_required (VERSION 3.14) project(xnnpack_wasm) ################ EMCC ################ include(ExternalProject) -ExternalProject_Add(xnnpack +# grep xnnpack_benchmark -A 1 BUILD.bazel \ +# | grep "name =" \ +# | awk '{print $3}' \ +# | sed -e 's/\"//g; s/,//g; s/^/\"/g; s/$/\"/g' +list(APPEND NATIVE_BENCHMARKS + "qs8_dwconv_bench" + "qs8_f32_vcvt_bench" + "qs8_gemm_bench" + "qs8_requantization_bench" + "qs8_vadd_bench" + "qs8_vaddc_bench" + "qs8_vcvt_bench" + "qs16_qs8_vcvt_bench" + "qs8_vlrelu_bench" + "qs8_vmul_bench" + "qs8_vmulc_bench" + "qu8_f32_vcvt_bench" + "qu8_gemm_bench" + "qu8_requantization_bench" + "qu8_vadd_bench" + "qu8_vaddc_bench" + "qu8_vcvt_bench" + "qu8_vlrelu_bench" + "qu8_vmul_bench" + "qu8_vmulc_bench" + "bf16_gemm_bench" + "f16_f32acc_igemm_bench" + "f16_igemm_bench" + "f16_f32acc_gemm_bench" + "f16_gemm_bench" + "f16_raddstoreexpminusmax_bench" + "f16_spmm_bench" + "f16_vsigmoid_bench" + "f16_vtanh_bench" + "f16_f32_vcvt_bench" + "f32_igemm_bench" + "f32_conv_hwc_bench" + "f16_conv_hwc2chw_bench" +# "f16_gavgpool_cw_bench" +# "f32_gavgpool_cw_bench" + "f32_conv_hwc2chw_bench" + "f16_dwconv_bench" + "f32_dwconv_bench" + "f32_dwconv2d_chw_bench" + "f16_dwconv2d_chw_bench" + "f32_f16_vcvt_bench" + "xx_transpose_bench" + "x8_transpose_bench" + "x16_transpose_bench" + "x24_transpose_bench" + "x32_transpose_bench" + "x64_transpose_bench" + "f32_bgemm_bench" + "f32_gemm_bench" + "f32_qs8_vcvt_bench" + "f32_qu8_vcvt_bench" + "f32_raddexpminusmax_bench" + "f32_raddextexp_bench" + "f32_raddstoreexpminusmax_bench" + "f32_rmax_bench" + "f32_spmm_bench" + "f32_softmax_bench" + "f16_velu_bench" + "f32_velu_bench" + "f32_vhswish_bench" + "f32_vlrelu_bench" + "f32_vrelu_bench" + "f32_vscaleexpminusmax_bench" + "f32_vscaleextexp_bench" + "f32_vsigmoid_bench" + "f16_vsqrt_bench" + "f32_vsqrt_bench" + "f32_vtanh_bench" + "f32_im2col_gemm_bench" + "rounding_bench" + "s16_rmaxabs_bench" + "s16_window_bench" + "u32_filterbank_accumulate_bench" + "u32_filterbank_subtract_bench" + "u32_vlog_bench" + "u64_u32_vsqrtshift_bench" + "i16_vlshift_bench" + "cs16_vsquareabs_bench" + "cs16_bfly4_bench" + "cs16_fftr_bench" + "x8_lut_bench" + "x32_packw_bench" + "x16_packw_bench" + "abs_bench" + "average_pooling_bench" + "bankers_rounding_bench" + "ceiling_bench" + "channel_shuffle_bench" + "convert_bench" + "convolution_bench" + "deconvolution_bench" + "elu_bench" + "floor_bench" + "global_average_pooling_bench" + "hardswish_bench" + "leaky_relu_bench" + "max_pooling_bench" + "negate_bench" + "prelu_bench" + "sigmoid_bench" + "softmax_bench" + "square_bench" + "square_root_bench" + "tanh_bench" + "truncation_bench" + "f16_dwconv_e2e_bench" + "f16_gemm_e2e_bench" + "f32_dwconv_e2e_bench" + "f32_gemm_e2e_bench" + "qs8_dwconv_e2e_bench" + "qs8_gemm_e2e_bench" + "qu8_gemm_e2e_bench" + "qu8_dwconv_e2e_bench" +# "end2end_bench" + "f16_exp_ulp_eval" + "f16_expminus_ulp_eval" + "f16_expm1minus_ulp_eval" + "f16_sigmoid_ulp_eval" + "f16_sqrt_ulp_eval" + "f16_tanh_ulp_eval" + "f32_exp_ulp_eval" + "f32_expminus_ulp_eval" + "f32_expm1minus_ulp_eval" + "f32_extexp_ulp_eval" + "f32_sigmoid_ulp_eval" + "f32_sqrt_ulp_eval" + "f32_tanh_ulp_eval" +) + +# Only Download +ExternalProject_Add(xnnpack-download PREFIX xnnpack GIT_REPOSITORY https://github.com/google/XNNPACK.git - GIT_TAG 4570a7151aa4f3e57eca14a575eeff6bb13e26be + GIT_TAG b9d4073a6913891ce9cbd8965c8d506075d2a45a GIT_PROGRESS ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack - UPDATE_COMMAND git restore . - && cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/google3/third_party/XNNPACK/microkernels.bzl - ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/ - && git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch + UPDATE_COMMAND "" + PATCH_COMMAND git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch CONFIGURE_COMMAND "" - # grep xnnpack_benchmark -A 1 BUILD.bazel \ - # | grep "name =" \ - # | awk '{print $3}' \ - # | sed -e 's/\"//g' -e 's/,//g' -e 's/^/\/\/:/g' - BUILD_COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack - && bazel --output_user_root=build-user-output build -c opt --config=wasm - //:qs8_dwconv_bench.wasm - //:qs8_f32_vcvt_bench.wasm - //:qs8_gemm_bench.wasm - //:qs8_requantization_bench.wasm - //:qs8_vadd_bench.wasm - //:qs8_vaddc_bench.wasm - //:qs8_vcvt_bench.wasm - //:qs8_vlrelu_bench.wasm - //:qs8_vmul_bench.wasm - //:qs8_vmulc_bench.wasm - //:qu8_f32_vcvt_bench.wasm - //:qu8_gemm_bench.wasm - //:qu8_requantization_bench.wasm - //:qu8_vadd_bench.wasm - //:qu8_vaddc_bench.wasm - //:qu8_vcvt_bench.wasm - //:qu8_vlrelu_bench.wasm - //:qu8_vmul_bench.wasm - //:qu8_vmulc_bench.wasm - //:bf16_gemm_bench.wasm - //:f16_igemm_bench.wasm - //:f16_gemm_bench.wasm - //:f16_raddstoreexpminusmax_bench.wasm - //:f16_spmm_bench.wasm - //:f16_vsigmoid_bench.wasm - //:f16_f32_vcvt_bench.wasm - //:f32_igemm_bench.wasm - //:f32_conv_hwc_bench.wasm - //:f16_conv_hwc2chw_bench.wasm - //:f16_gavgpool_cw_bench.wasm - //:f32_gavgpool_cw_bench.wasm - //:f32_conv_hwc2chw_bench.wasm - //:f16_dwconv_bench.wasm - //:f32_dwconv_bench.wasm - //:f32_dwconv2d_chw_bench.wasm - //:f16_dwconv2d_chw_bench.wasm - //:f32_f16_vcvt_bench.wasm - //:xx_transpose_bench.wasm - //:x8_transpose_bench.wasm - //:x16_transpose_bench.wasm - //:x24_transpose_bench.wasm - //:x32_transpose_bench.wasm - //:x64_transpose_bench.wasm - //:f32_gemm_bench.wasm - //:f32_qs8_vcvt_bench.wasm - //:f32_qu8_vcvt_bench.wasm - //:f32_raddexpminusmax_bench.wasm - //:f32_raddextexp_bench.wasm - //:f32_raddstoreexpminusmax_bench.wasm - //:f32_rmax_bench.wasm - //:f32_spmm_bench.wasm - //:f32_softmax_bench.wasm - //:f16_velu_bench.wasm - //:f32_velu_bench.wasm - //:f32_vhswish_bench.wasm - //:f32_vlrelu_bench.wasm - //:f32_vrelu_bench.wasm - //:f32_vscaleexpminusmax_bench.wasm - //:f32_vscaleextexp_bench.wasm - //:f32_vsigmoid_bench.wasm - //:f16_vsqrt_bench.wasm - //:f32_vsqrt_bench.wasm - //:f32_im2col_gemm_bench.wasm - //:rounding_bench.wasm - //:s16_rmaxabs_bench.wasm - //:s16_window_bench.wasm - //:u32_filterbank_accumulate_bench.wasm - //:u32_filterbank_subtract_bench.wasm - //:u32_vlog_bench.wasm - //:u64_u32_vsqrtshift_bench.wasm - //:i16_vlshift_bench.wasm - //:cs16_vsquareabs_bench.wasm - //:cs16_bfly4_bench.wasm - //:cs16_fftr_bench.wasm - //:x8_lut_bench.wasm - //:abs_bench.wasm - //:average_pooling_bench.wasm - //:bankers_rounding_bench.wasm - //:ceiling_bench.wasm - //:channel_shuffle_bench.wasm - //:convert_bench.wasm - //:convolution_bench.wasm - //:deconvolution_bench.wasm - //:elu_bench.wasm - //:floor_bench.wasm - //:global_average_pooling_bench.wasm - //:hardswish_bench.wasm - //:leaky_relu_bench.wasm - //:max_pooling_bench.wasm - //:negate_bench.wasm - //:sigmoid_bench.wasm - //:prelu_bench.wasm - //:softmax_bench.wasm - //:square_bench.wasm - //:square_root_bench.wasm - //:truncation_bench.wasm - //:f16_gemm_e2e_bench.wasm - //:f32_dwconv_e2e_bench.wasm - //:f32_gemm_e2e_bench.wasm - //:qs8_dwconv_e2e_bench.wasm - //:qs8_gemm_e2e_bench.wasm - //:qu8_gemm_e2e_bench.wasm - //:qu8_dwconv_e2e_bench.wasm - //:end2end_bench.wasm - //:f16_exp_ulp_eval.wasm - //:f16_expminus_ulp_eval.wasm - //:f16_expm1minus_ulp_eval.wasm - //:f16_sigmoid_ulp_eval.wasm - //:f16_sqrt_ulp_eval.wasm - //:f32_exp_ulp_eval.wasm - //:f32_expminus_ulp_eval.wasm - //:f32_expm1minus_ulp_eval.wasm - //:f32_extexp_ulp_eval.wasm - //:f32_sigmoid_ulp_eval.wasm - //:f32_sqrt_ulp_eval.wasm - //:f32_tanh_ulp_eval.wasm - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/bazel-out/wasm-opt/bin/ - ${CMAKE_BINARY_DIR}/wasm-opt + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" ) + +set(WAMRC "${CMAKE_CURRENT_SOURCE_DIR}/../../../wamr-compiler/build/wamrc") +if(EXISTS ${WAMRC}) + message("-- Will generate .aot") +else() + message("Will generate .wasm") +endif() + +foreach(BENCHMARK IN LISTS NATIVE_BENCHMARKS) + string(CONCAT WASM_BENCHMARK "//:" ${BENCHMARK} "-wasm") + string(CONCAT WASM_OUTPUT ${BENCHMARK} ".wasm") + + add_custom_command( + OUTPUT ${WASM_OUTPUT} + COMMAND bazel --output_user_root=build-user-output build -c opt --config=wasm ${WASM_BENCHMARK} + && ${CMAKE_COMMAND} -E copy_if_different ./bazel-bin/${WASM_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${WASM_OUTPUT} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack + DEPENDS xnnpack-download + COMMENT "Generating ${WASM_OUTPUT} ..." + ) + + set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${CMAKE_CURRENT_BINARY_DIR}/${WASM_OUTPUT}) + + if(EXISTS ${WAMRC}) + string(CONCAT AOT_OUTPUT ${BENCHMARK} ".aot") + + add_custom_command( + OUTPUT ${AOT_OUTPUT} + COMMAND ${WAMRC} -o ${AOT_OUTPUT} ${WASM_OUTPUT} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${WASM_OUTPUT} + COMMENT "Generating ${AOT_OUTPUT} ..." + ) + + add_custom_target(${BENCHMARK} ALL DEPENDS ${AOT_OUTPUT}) + else() + add_custom_target(${BENCHMARK} ALL DEPENDS ${WASM_OUTPUT}) + endif() +endforeach() + diff --git a/samples/workload/XNNPACK/README.md b/samples/workload/XNNPACK/README.md index 7984d9ce..c4cd5221 100644 --- a/samples/workload/XNNPACK/README.md +++ b/samples/workload/XNNPACK/README.md @@ -9,26 +9,7 @@ please refer to [installation instructions](../README.md). ## Build XNNPACK -```bash -cd /samples/workload/XNNPACK -mkdir build -cd build -cmake .. -``` -The wasm files are generated under folder samples/workload/XNNPACK/xnnpack/bazel-bin. - -## Run benchmarks - -Firstly please build iwasm with simd, libc-emcc and lib-pthread support: - -``` bash -$ cd /product-mini/platforms/linux/ -$ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1 -$ make -``` - -And please build wamrc: +please build wamrc: ``` bash cd /wamr-compiler @@ -38,11 +19,31 @@ cmake .. make ``` -Then compile wasm file to aot file and run: +And then build xnnpack standalone wasm files -``` shell -$ cd /samples/workload/XNNPACK/xnnpack/bazel-bin -$ wamrc -o average_pooling_bench.aot average_pooling_bench.wasm (or other wasm files) -$ iwasm average_pooling_bench.aot +```bash +$ cd /samples/workload/XNNPACK +$ cmake -S . -B build +$ cmake --build build +``` + +Generated .wasm(and .aot) files are under *samples/workload/XNNPACK/build*. + +## Run benchmarks + +Firstly please build iwasm with simd, libc-emcc and lib-pthread supporting: + +``` bash +$ cd /product-mini/platforms/linux/ +$ mkdir build && cd build +$ cmake .. -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1 +$ make +``` + +Then run: + +``` shell +$ cd /samples/workload/XNNPACK/build +$ iwasm averag_pooling_bench.aot # (or other aot files) ``` diff --git a/samples/workload/XNNPACK/xnnpack.patch b/samples/workload/XNNPACK/xnnpack.patch index 3fb6b230..d7680d34 100644 --- a/samples/workload/XNNPACK/xnnpack.patch +++ b/samples/workload/XNNPACK/xnnpack.patch @@ -1,141 +1,138 @@ diff --git a/.bazelrc b/.bazelrc -index 688279da1..376996885 100644 +index fcaff1063..e61d53337 100644 --- a/.bazelrc +++ b/.bazelrc -@@ -53,4 +53,9 @@ build:ios_fat --watchos_cpus=armv7k - build:macos --apple_platform_type=macos +@@ -1,6 +1,7 @@ + # Basic build settings + build --jobs 128 + build --cxxopt='-std=gnu++14' ++build --incompatible_enable_cc_toolchain_resolution + + # Sets the default Apple platform to macOS. + build --apple_platform_type=macos +@@ -55,3 +56,10 @@ build:macos --apple_platform_type=macos build:macos_arm64 --config=macos --build:macos_arm64 --cpu=darwin_arm64 -\ No newline at end of file -+build:macos_arm64 --cpu=darwin_arm64 + build:macos_arm64 --cpu=darwin_arm64 + ++# Emscripten configs ++build:wasm --copt="-Wno-unused" ++build:wasm --copt="-Wno-unused-function" ++build:wasm --copt="-Wno-unused-but-set-variable" +build:wasm --cpu=wasm +build:wasm --features=wasm_simd -+build:wasm --crosstool_top=@emsdk//emscripten_toolchain:everything -+build:wasm --host_crosstool_top=@bazel_tools//tools/cpp:toolchain diff --git a/WORKSPACE b/WORKSPACE -index cd8960ffa..787e03ca8 100644 +index 2e568088b..3961371ca 100644 --- a/WORKSPACE +++ b/WORKSPACE -@@ -29,8 +29,9 @@ http_archive( - # Google Benchmark library, used in micro-benchmarks. - http_archive( - name = "com_google_benchmark", -- strip_prefix = "benchmark-main", -- urls = ["https://github.com/google/benchmark/archive/main.zip"], -+ sha256 = "1ba14374fddcd9623f126b1a60945e4deac4cdc4fb25a5f25e7f779e36f2db52", -+ strip_prefix = "benchmark-d2a8a4ee41b923876c034afb939c4fc03598e622", -+ urls = ["https://github.com/google/benchmark/archive/d2a8a4ee41b923876c034afb939c4fc03598e622.zip"], +@@ -83,7 +83,23 @@ http_archive( ) - # FP16 library, used for half-precision conversions -@@ -92,8 +93,25 @@ http_archive( - ], - ) + # Android NDK location and version is auto-detected from $ANDROID_NDK_HOME environment variable +-android_ndk_repository(name = "androidndk") ++# android_ndk_repository(name = "androidndk") -+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + # Android SDK location and API is auto-detected from $ANDROID_HOME environment variable +-android_sdk_repository(name = "androidsdk") ++# android_sdk_repository(name = "androidsdk") ++ +http_archive( + name = "emsdk", -+ # Use emsdk-3.0.0 since the larger version may: -+ # - compress the wasm file into a tar file but not directly generate wasm file -+ # - generate incomplete implementation of libc API, e.g. throw exception in getentropy -+ strip_prefix = "emsdk-3.0.0/bazel", -+ url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/3.0.0.tar.gz", -+ sha256 = "a41dccfd15be9e85f923efaa0ac21943cbab77ec8d39e52f25eca1ec61a9ac9e" ++ sha256 = "5fa6f5eb45a4d50264610c4c9e1c155535359b63bfaad69b4e5101d16c1e7e32", ++ strip_prefix = "emsdk-a896e3d066448b3530dbcaa48869fafefd738f57/bazel", ++ url = "https://github.com/emscripten-core/emsdk/archive/a896e3d066448b3530dbcaa48869fafefd738f57.tar.gz", +) + +load("@emsdk//:deps.bzl", emsdk_deps = "deps") +emsdk_deps() + +load("@emsdk//:emscripten_deps.bzl", emsdk_emscripten_deps = "emscripten_deps") -+emsdk_emscripten_deps() ++emsdk_emscripten_deps(emscripten_version = "3.1.44") + - # Android NDK location and version is auto-detected from $ANDROID_NDK_HOME environment variable --android_ndk_repository(name = "androidndk") -+#android_ndk_repository(name = "androidndk") ++load("@emsdk//:toolchains.bzl", "register_emscripten_toolchains") ++register_emscripten_toolchains() +diff --git a/bench/utils.cc b/bench/utils.cc +index 3b32503a7..656845336 100644 +--- a/bench/utils.cc ++++ b/bench/utils.cc +@@ -456,3 +456,13 @@ CodeMemoryHelper::~CodeMemoryHelper() { - # Android SDK location and API is auto-detected from $ANDROID_HOME environment variable --android_sdk_repository(name = "androidsdk") -+#android_sdk_repository(name = "androidsdk") + } // namespace utils + } // namespace benchmark ++ ++ ++extern "C" ++__attribute__((import_module("env"), import_name("getentropy"))) int import_getentropy(void* buffer, size_t length); ++ ++extern "C" ++int getentropy(void* buffer, size_t length) ++{ ++ return import_getentropy(buffer, length); ++} diff --git a/build_defs.bzl b/build_defs.bzl -index b8217a18d..6f2d1675e 100644 +index 01b436eb7..2738fd50a 100644 --- a/build_defs.bzl +++ b/build_defs.bzl -@@ -380,7 +380,7 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []): - explicitly specified. - """ - native.cc_binary( -- name = name, -+ name = name + ".wasm", - srcs = srcs, - copts = xnnpack_std_cxxopts() + [ - "-Iinclude", -@@ -405,5 +405,5 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []): +@@ -1,6 +1,7 @@ + """Build definitions and rules for XNNPACK.""" + +-load(":emscripten.bzl", "xnnpack_emscripten_benchmark_linkopts", "xnnpack_emscripten_deps", "xnnpack_emscripten_minimal_linkopts", "xnnpack_emscripten_test_linkopts") ++load(":emscripten.bzl", "xnnpack_emscripten_benchmark_linkopts", "xnnpack_emscripten_deps", "xnnpack_emscripten_minimal_linkopts", "xnnpack_emscripten_test_linkopts", "xnnpack_emscripten_standalone_benchmark_linkopts") ++load("@emsdk//emscripten_toolchain:wasm_rules.bzl", "wasm_cc_binary") + + def xnnpack_visibility(): + """Visibility of :XNNPACK target. +@@ -393,7 +394,8 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []): + "//conditions:default": ["-Wno-unused-function"], + }) + copts, + linkopts = select({ +- ":emscripten": xnnpack_emscripten_benchmark_linkopts(), ++ ":emscripten": xnnpack_emscripten_standalone_benchmark_linkopts(), ++ ":emscripten_wasmsimd": xnnpack_emscripten_standalone_benchmark_linkopts(), + ":windows_x86_64_mingw": ["-lshlwapi"], + ":windows_x86_64_msys": ["-lshlwapi"], + "//conditions:default": [], +@@ -405,5 +407,16 @@ def xnnpack_benchmark(name, srcs, copts = [], deps = [], tags = []): ":emscripten": xnnpack_emscripten_deps(), "//conditions:default": [], }), - tags = tags, -+ tags = tags, ++ tags = tags, ++ ) ++ ++ wasm_cc_binary( ++ name = name + "-wasm", ++ cc_target = ":" + name, ++ threads = "off", ++ simd = True, ++ standalone= True, ++ outputs = [ ++ name + ".wasm", ++ ] ) diff --git a/emscripten.bzl b/emscripten.bzl -index f1557a7b1..7f964a094 100644 +index f1557a7b1..a3c4f93b9 100644 --- a/emscripten.bzl +++ b/emscripten.bzl -@@ -25,12 +25,19 @@ def xnnpack_emscripten_benchmark_linkopts(): - """Emscripten-specific linkopts for benchmarks.""" - return [ - "-s ASSERTIONS=1", -- "-s ENVIRONMENT=node,shell,web", -- "-s ERROR_ON_UNDEFINED_SYMBOLS=1", -- "-s EXIT_RUNTIME=1", +@@ -33,6 +33,21 @@ def xnnpack_emscripten_benchmark_linkopts(): + "--pre-js $(location :preamble.js.lds)", + ] + ++def xnnpack_emscripten_standalone_benchmark_linkopts(): ++ return [ ++ "-s ASSERTIONS=1", + "-s ERROR_ON_UNDEFINED_SYMBOLS=0", - "-s ALLOW_MEMORY_GROWTH=1", - "-s TOTAL_MEMORY=536870912", # 512M -- "--pre-js $(location :preamble.js.lds)", ++ "-s ALLOW_MEMORY_GROWTH=1", ++ "-s TOTAL_MEMORY=536870912", # 512M + "-s USE_PTHREADS=0", + "-s STANDALONE_WASM=1", -+ "-Wno-unused", -+ "-Wno-unused-variable", -+ "-Wno-unused-command-line-argument", + "-Wl,--export=__heap_base", + "-Wl,--export=__data_end", + "-Wl,--export=malloc", + "-Wl,--export=free", -+ "--oformat=wasm", - ] - ++ ] ++ ++ def xnnpack_emscripten_deps(): -diff --git a/src/log.c b/src/log.c -index 5715f2f85..4b3e4261b 100644 ---- a/src/log.c -+++ b/src/log.c -@@ -55,7 +55,7 @@ - #endif - - #if XNN_LOG_TO_STDIO --static void xnn_vlog(int output_handle, const char* prefix, size_t prefix_length, const char* format, va_list args) { -+void xnn_vlog(int output_handle, const char* prefix, size_t prefix_length, const char* format, va_list args) { - char stack_buffer[XNN_LOG_STACK_BUFFER_SIZE]; - char* heap_buffer = NULL; - char* out_buffer = &stack_buffer[0]; -diff --git a/third_party/cpuinfo.BUILD b/third_party/cpuinfo.BUILD -index 1997f4e3a..5e03c43af 100644 ---- a/third_party/cpuinfo.BUILD -+++ b/third_party/cpuinfo.BUILD -@@ -150,7 +150,7 @@ cc_library( - "src/arm/midr.h", - ], - deps = [ -- "@clog", -+ "//deps/clog" - ], - ) - -@@ -352,5 +352,5 @@ config_setting( - - config_setting( - name = "emscripten", -- values = {"crosstool_top": "//toolchain:emscripten"}, -+ values = {"crosstool_top": "@emsdk//emscripten_toolchain:everything"}, - ) + """Emscripten-specific dependencies for unit tests and benchmarks.""" + return [ From 43a3cbf2ce0791e56ee12127c653e1736058a180 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 3 Aug 2023 08:39:22 +0800 Subject: [PATCH 24/30] Build more benchmarks in workload XNNPACK (#2417) Build 3 more benchmarks in workload XNNPACK and fix a typo. --- samples/workload/XNNPACK/CMakeLists.txt | 6 +++--- samples/workload/XNNPACK/README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/workload/XNNPACK/CMakeLists.txt b/samples/workload/XNNPACK/CMakeLists.txt index 93181cd9..41cdd583 100644 --- a/samples/workload/XNNPACK/CMakeLists.txt +++ b/samples/workload/XNNPACK/CMakeLists.txt @@ -46,8 +46,8 @@ list(APPEND NATIVE_BENCHMARKS "f32_igemm_bench" "f32_conv_hwc_bench" "f16_conv_hwc2chw_bench" -# "f16_gavgpool_cw_bench" -# "f32_gavgpool_cw_bench" + "f16_gavgpool_cw_bench" + "f32_gavgpool_cw_bench" "f32_conv_hwc2chw_bench" "f16_dwconv_bench" "f32_dwconv_bench" @@ -126,7 +126,7 @@ list(APPEND NATIVE_BENCHMARKS "qs8_gemm_e2e_bench" "qu8_gemm_e2e_bench" "qu8_dwconv_e2e_bench" -# "end2end_bench" + "end2end_bench" "f16_exp_ulp_eval" "f16_expminus_ulp_eval" "f16_expm1minus_ulp_eval" diff --git a/samples/workload/XNNPACK/README.md b/samples/workload/XNNPACK/README.md index c4cd5221..625ef7f7 100644 --- a/samples/workload/XNNPACK/README.md +++ b/samples/workload/XNNPACK/README.md @@ -44,6 +44,6 @@ Then run: ``` shell $ cd /samples/workload/XNNPACK/build -$ iwasm averag_pooling_bench.aot # (or other aot files) +$ iwasm average_pooling_bench.aot # (or other aot files) ``` From 28125ec538c86de90d2b9be332d50760e7dd42bc Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Thu, 3 Aug 2023 09:46:56 +0900 Subject: [PATCH 25/30] Move wasm_runtime_destroy_wasi and wasi_nn_destroy calls together (#2418) And remove obsolete comment. --- core/iwasm/aot/aot_runtime.c | 16 +++++----------- core/iwasm/interpreter/wasm_runtime.c | 16 +++++----------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index e0d56a69..a7d6ef2d 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1264,16 +1264,6 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) wasm_exec_env_destroy((WASMExecEnv *)module_inst->exec_env_singleton); } -#if WASM_ENABLE_LIBC_WASI != 0 - /* Destroy wasi resource before freeing app heap, since some fields of - wasi contex are allocated from app heap, and if app heap is freed, - these fields will be set to NULL, we cannot free their internal data - which may allocated from global heap. */ - /* Only destroy wasi ctx in the main module instance */ - if (!is_sub_inst) - wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst); -#endif - #if WASM_ENABLE_PERF_PROFILING != 0 if (module_inst->func_perf_profilings) wasm_runtime_free(module_inst->func_perf_profilings); @@ -1306,10 +1296,14 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) wasm_runtime_free( ((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports); + if (!is_sub_inst) { +#if WASM_ENABLE_LIBC_WASI != 0 + wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst); +#endif #if WASM_ENABLE_WASI_NN != 0 - if (!is_sub_inst) wasi_nn_destroy(module_inst); #endif + } wasm_runtime_free(module_inst); } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 84155a05..497e6b19 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -2216,16 +2216,6 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) sub_module_deinstantiate(module_inst); #endif -#if WASM_ENABLE_LIBC_WASI != 0 - /* Destroy wasi resource before freeing app heap, since some fields of - wasi contex are allocated from app heap, and if app heap is freed, - these fields will be set to NULL, we cannot free their internal data - which may allocated from global heap. */ - /* Only destroy wasi ctx in the main module instance */ - if (!is_sub_inst) - wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst); -#endif - if (module_inst->memory_count > 0) memories_deinstantiate(module_inst, module_inst->memories, module_inst->memory_count); @@ -2258,10 +2248,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) if (module_inst->e->c_api_func_imports) wasm_runtime_free(module_inst->e->c_api_func_imports); + if (!is_sub_inst) { +#if WASM_ENABLE_LIBC_WASI != 0 + wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst); +#endif #if WASM_ENABLE_WASI_NN != 0 - if (!is_sub_inst) wasi_nn_destroy(module_inst); #endif + } wasm_runtime_free(module_inst); } From bdd99137a4f2ae8c05839d4611d7b0a497cae74c Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Fri, 4 Aug 2023 10:28:30 +0900 Subject: [PATCH 26/30] embed_wamr.md: Improvements about threads (#2420) - Some more clarifications - Mention wasi-threads - Fix a confusing indentation --- doc/embed_wamr.md | 99 +++++++++++++++++++------------------ doc/embed_wamr_spawn_api.md | 38 ++++++++++++++ 2 files changed, 88 insertions(+), 49 deletions(-) create mode 100644 doc/embed_wamr_spawn_api.md diff --git a/doc/embed_wamr.md b/doc/embed_wamr.md index 05038402..b8381758 100644 --- a/doc/embed_wamr.md +++ b/doc/embed_wamr.md @@ -258,68 +258,69 @@ We can't pass structure data or class objects through the pointer since the memo ## Execute wasm functions in multiple threads -The `exec_env` is not thread safety, it will cause unexpected behavior if the same `exec_env` is used in multiple threads. However, we've provided two ways to execute wasm functions concurrently: +It isn't safe to use an `exec_env` object in multiple threads concurrently. +To run a multi-threaded application, you basically need a separate `exec_env` +for each threads. -- You can use `pthread` APIs in your wasm application, see [pthread library](./pthread_library.md) for more details. +### Approaches to manage `exec_env` objects and threads -- The `spawn exec_env` and `spawn thread` APIs are available, you can use these APIs to manage the threads in native: +WAMR supports two approaches to manage `exec_env` and threads as described +below. While they are not exclusive, you usually only need to use one of +them. - *spawn exec_env:* +#### Make your WASM application manage threads - `spawn exec_env` API spawns a `new_exec_env` base on the original `exec_env`, use can use it in other threads: + You can make your WASM application spawn threads by itself, + typically using `pthread` APIs like `pthread_create`. + See [pthread library](./pthread_library.md) and + [pthread implementations](./pthread_impls.md) for more details. + In this case, WAMR manages `exec_env` for the spawned threads. + +#### Make your embedder manage threads + + The `spawn exec_env` and `spawn thread` APIs are available for the embedder. + You can use these APIs to manage the threads. + See [Thread related embedder API](./embed_wamr_spawn_api.md) for details. + +### Other notes about threads + +* You can manage the maximum number of threads ```C - new_exec_env = wasm_runtime_spawn_exec_env(exec_env); - - /* Then you can use new_exec_env in your new thread */ - module_inst = wasm_runtime_get_module_inst(new_exec_env); - func_inst = wasm_runtime_lookup_function(module_inst, ...); - wasm_runtime_call_wasm(new_exec_env, func_inst, ...); - - /* you need to use this API to manually destroy the spawned exec_env */ - wasm_runtime_destroy_spawned_exec_env(new_exec_env); + init_args.max_thread_num = THREAD_NUM; + /* If this init argument is not set, the default maximum thread number is 4 */ ``` - *spawn thread:* +* To share memory among threads, you need to build your WASM application with shared memory - You can also use `spawn thread` API to avoid manually manage the spawned exec_env: - - ```C - wasm_thread_t wasm_tid; - void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg) - { - module_inst = wasm_runtime_get_module_inst(exec_env); - func_inst = wasm_runtime_lookup_function(module_inst, ...); - wasm_runtime_call_wasm(exec_env, func_inst, ...); - } - wasm_runtime_spawn_thread(exec_env, &wasm_tid, wamr_thread_cb, NULL); - /* Use wasm_runtime_join_thread to join the spawned thread */ - wasm_runtime_join_thread(wasm_tid, NULL); - ``` - -**Note1: You can manage the maximum number of threads can be created:** - -```C -init_args.max_thread_num = THREAD_NUM; -/* If this init argument is not set, the default maximum thread number is 4 */ -``` - -**Note2: The wasm application should be built with `--shared-memory` and `-pthread` enabled:** - -```bash - /opt/wasi-sdk/bin/clang -o test.wasm test.c -nostdlib -pthread \ - -Wl,--shared-memory,--max-memory=131072 \ - -Wl,--no-entry,--export=__heap_base,--export=__data_end \ - -Wl,--export=__wasm_call_ctors,--export=${your_func_name} -``` - - **Note3: The pthread library feature should be enabled while building the runtime:** + For example, it can be done with `--shared-memory` and `-pthread`. ```bash - cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 + /opt/wasi-sdk/bin/clang -o test.wasm test.c -nostdlib -pthread \ + -Wl,--shared-memory,--max-memory=131072 \ + -Wl,--no-entry,--export=__heap_base,--export=__data_end \ + -Wl,--export=__wasm_call_ctors,--export=${your_func_name} ``` -[Here](../samples/spawn-thread) is a sample to show how to use these APIs. +* The corresponding threading feature should be enabled while building the runtime + + - WAMR lib-pthread (legacy) + + ```bash + cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 + ``` + + - wasi-threads + + ```bash + cmake .. -DWAMR_BUILD_LIB_WASI_THREADS=1 + ``` + + - `wasm_runtime_spawn_exec_env` and `wasm_runtime_spawn_thread` + + ```bash + cmake .. -DWAMR_BUILD_THREAD_MGR=1 -DWAMR_BUILD_SHARED_MEMORY=1 + ``` ## The deinitialization procedure diff --git a/doc/embed_wamr_spawn_api.md b/doc/embed_wamr_spawn_api.md new file mode 100644 index 00000000..f0e637f3 --- /dev/null +++ b/doc/embed_wamr_spawn_api.md @@ -0,0 +1,38 @@ +# Thread related embedder API + +This document explains `wasm_runtime_spawn_exec_env` and +`wasm_runtime_spawn_thread`. +[Here](../samples/spawn-thread) is a sample to show how to use these APIs. + + * spawn exec_env + + `spawn exec_env` API creates a new `exec_env` based on the original `exec_env`. You can use it in other threads. It's up to the embedder how to manage host threads to run the new `exec_env`. + + ```C + new_exec_env = wasm_runtime_spawn_exec_env(exec_env); + + /* Then you can use new_exec_env in your new thread */ + module_inst = wasm_runtime_get_module_inst(new_exec_env); + func_inst = wasm_runtime_lookup_function(module_inst, ...); + wasm_runtime_call_wasm(new_exec_env, func_inst, ...); + + /* you need to use this API to manually destroy the spawned exec_env */ + wasm_runtime_destroy_spawned_exec_env(new_exec_env); + ``` + + * spawn thread + + Alternatively, you can use `spawn thread` API to avoid managing the extra exec_env and the corresponding host thread manually: + + ```C + wasm_thread_t wasm_tid; + void *wamr_thread_cb(wasm_exec_env_t exec_env, void *arg) + { + module_inst = wasm_runtime_get_module_inst(exec_env); + func_inst = wasm_runtime_lookup_function(module_inst, ...); + wasm_runtime_call_wasm(exec_env, func_inst, ...); + } + wasm_runtime_spawn_thread(exec_env, &wasm_tid, wamr_thread_cb, NULL); + /* Use wasm_runtime_join_thread to join the spawned thread */ + wasm_runtime_join_thread(wasm_tid, NULL); + ``` From 29761c72167589f9c3ee230668248102eae930ed Mon Sep 17 00:00:00 2001 From: Maks Litskevich Date: Fri, 4 Aug 2023 02:41:25 +0100 Subject: [PATCH 27/30] Fix typo in test_wamr.sh (#2421) Change `ORC_EAGER_JIT_COMPILE_FLAGS` to `ORC_LAZY_JIT_COMPILE_FLAGS` --- tests/wamr-test-suites/test_wamr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index e263e5ab..1448e3e1 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -824,7 +824,7 @@ function trigger() collect_coverage llvm-jit echo "work in orc jit lazy compilation mode" - BUILD_FLAGS="$ORC_EAGER_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" + BUILD_FLAGS="$ORC_LAZY_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" build_iwasm_with_cfg $BUILD_FLAGS for suite in "${TEST_CASE_ARR[@]}"; do $suite"_test" jit From 91592429f43c0ea22ead5a031adada101db24592 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Fri, 4 Aug 2023 11:18:13 +0900 Subject: [PATCH 28/30] Fix memory sharing (#2415) - Inherit shared memory from the parent instance, instead of trying to look it up by the underlying module. The old method works correctly only when every cluster uses different module. - Use reference count in WASMMemoryInstance/AOTMemoryInstance to mark whether the memory is shared or not - Retire WASMSharedMemNode - For atomic opcode implementations in the interpreters, use a global lock for now - Update the internal API users (wasi-threads, lib-pthread, wasm_runtime_spawn_thread) Fixes https://github.com/bytecodealliance/wasm-micro-runtime/issues/1962 --- core/iwasm/aot/aot_runtime.c | 67 ++---- core/iwasm/aot/aot_runtime.h | 8 +- core/iwasm/common/wasm_memory.c | 12 +- core/iwasm/common/wasm_runtime_common.c | 33 ++- core/iwasm/common/wasm_runtime_common.h | 3 +- core/iwasm/common/wasm_shared_memory.c | 197 ++++++++---------- core/iwasm/common/wasm_shared_memory.h | 44 ++-- core/iwasm/interpreter/wasm_interp_classic.c | 116 +++++------ core/iwasm/interpreter/wasm_interp_fast.c | 116 +++++------ core/iwasm/interpreter/wasm_runtime.c | 72 +++---- core/iwasm/interpreter/wasm_runtime.h | 5 +- .../lib-pthread/lib_pthread_wrapper.c | 2 +- .../lib_wasi_threads_wrapper.c | 2 +- .../libraries/thread-mgr/thread_manager.c | 22 +- 14 files changed, 298 insertions(+), 401 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index a7d6ef2d..3e6371f4 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -339,11 +339,8 @@ memories_deinstantiate(AOTModuleInstance *module_inst) memory_inst = module_inst->memories[i]; if (memory_inst) { #if WASM_ENABLE_SHARED_MEMORY != 0 - if (memory_inst->is_shared) { - int32 ref_count = shared_memory_dec_reference( - (WASMModuleCommon *)module_inst->module); - bh_assert(ref_count >= 0); - + if (shared_memory_is_shared(memory_inst)) { + uint32 ref_count = shared_memory_dec_reference(memory_inst); /* if the reference count is not zero, don't free the memory */ if (ref_count > 0) @@ -373,9 +370,10 @@ memories_deinstantiate(AOTModuleInstance *module_inst) } static AOTMemoryInstance * -memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, - AOTMemoryInstance *memory_inst, AOTMemory *memory, - uint32 heap_size, char *error_buf, uint32 error_buf_size) +memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, + AOTModule *module, AOTMemoryInstance *memory_inst, + AOTMemory *memory, uint32 memory_idx, uint32 heap_size, + char *error_buf, uint32 error_buf_size) { void *heap_handle; uint32 num_bytes_per_page = memory->num_bytes_per_page; @@ -396,23 +394,13 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, bool is_shared_memory = memory->memory_flags & 0x02 ? true : false; /* Shared memory */ - if (is_shared_memory) { + if (is_shared_memory && parent != NULL) { AOTMemoryInstance *shared_memory_instance; - WASMSharedMemNode *node = - wasm_module_get_shared_memory((WASMModuleCommon *)module); - /* If the memory of this module has been instantiated, - return the memory instance directly */ - if (node) { - uint32 ref_count; - ref_count = shared_memory_inc_reference((WASMModuleCommon *)module); - bh_assert(ref_count > 0); - shared_memory_instance = - (AOTMemoryInstance *)shared_memory_get_memory_inst(node); - bh_assert(shared_memory_instance); - - (void)ref_count; - return shared_memory_instance; - } + bh_assert(memory_idx == 0); + bh_assert(parent->memory_count > memory_idx); + shared_memory_instance = parent->memories[memory_idx]; + shared_memory_inc_reference(shared_memory_instance); + return shared_memory_instance; } #endif @@ -609,23 +597,12 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, #if WASM_ENABLE_SHARED_MEMORY != 0 if (is_shared_memory) { - memory_inst->is_shared = true; - if (!shared_memory_set_memory_inst( - (WASMModuleCommon *)module, - (WASMMemoryInstanceCommon *)memory_inst)) { - set_error_buf(error_buf, error_buf_size, "allocate memory failed"); - goto fail3; - } + memory_inst->ref_count = 1; } #endif return memory_inst; -#if WASM_ENABLE_SHARED_MEMORY != 0 -fail3: - if (heap_size > 0) - mem_allocator_destroy(memory_inst->heap_handle); -#endif fail2: if (heap_size > 0) wasm_runtime_free(memory_inst->heap_handle); @@ -654,8 +631,9 @@ aot_get_default_memory(AOTModuleInstance *module_inst) } static bool -memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, - uint32 heap_size, char *error_buf, uint32 error_buf_size) +memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, + AOTModule *module, uint32 heap_size, char *error_buf, + uint32 error_buf_size) { uint32 global_index, global_data_offset, base_offset, length; uint32 i, memory_count = module->memory_count; @@ -672,8 +650,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, memories = module_inst->global_table_data.memory_instances; for (i = 0; i < memory_count; i++, memories++) { - memory_inst = memory_instantiate(module_inst, module, memories, - &module->memories[i], heap_size, + memory_inst = memory_instantiate(module_inst, parent, module, memories, + &module->memories[i], i, heap_size, error_buf, error_buf_size); if (!memory_inst) { return false; @@ -1100,9 +1078,9 @@ check_linked_symbol(AOTModule *module, char *error_buf, uint32 error_buf_size) } AOTModuleInstance * -aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main, - uint32 stack_size, uint32 heap_size, char *error_buf, - uint32 error_buf_size) +aot_instantiate(AOTModule *module, AOTModuleInstance *parent, + WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size, + char *error_buf, uint32 error_buf_size) { AOTModuleInstance *module_inst; const uint32 module_inst_struct_size = @@ -1112,6 +1090,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main, uint64 total_size, table_size = 0; uint8 *p; uint32 i, extra_info_offset; + const bool is_sub_inst = parent != NULL; /* Check heap size */ heap_size = align_uint(heap_size, 8); @@ -1171,7 +1150,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main, goto fail; /* Initialize memory space */ - if (!memories_instantiate(module_inst, module, heap_size, error_buf, + if (!memories_instantiate(module_inst, parent, module, heap_size, error_buf, error_buf_size)) goto fail; diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 8d679d55..2dea832b 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -406,7 +406,7 @@ aot_unload(AOTModule *module); * Instantiate a AOT module. * * @param module the AOT module to instantiate - * @param is_sub_inst the flag of sub instance + * @param parent the parent module instance * @param heap_size the default heap size of the module instance, a heap will * be created besides the app memory space. Both wasm app and native * function can allocate memory from the heap. If heap_size is 0, the @@ -417,9 +417,9 @@ aot_unload(AOTModule *module); * @return return the instantiated AOT module instance, NULL if failed */ AOTModuleInstance * -aot_instantiate(AOTModule *module, bool is_sub_inst, WASMExecEnv *exec_env_main, - uint32 stack_size, uint32 heap_size, char *error_buf, - uint32 error_buf_size); +aot_instantiate(AOTModule *module, AOTModuleInstance *parent, + WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size, + char *error_buf, uint32 error_buf_size); /** * Deinstantiate a AOT module instance, destroy the resources. diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index 9db7fa14..7d5cb435 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -608,7 +608,7 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) } #if WASM_ENABLE_SHARED_MEMORY != 0 - if (memory->is_shared) { + if (shared_memory_is_shared(memory)) { memory->num_bytes_per_page = num_bytes_per_page; memory->cur_page_count = total_page_count; memory->max_page_count = max_page_count; @@ -769,15 +769,13 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) bool ret = false; #if WASM_ENABLE_SHARED_MEMORY != 0 - WASMSharedMemNode *node = - wasm_module_get_shared_memory((WASMModuleCommon *)module->module); - if (node) - os_mutex_lock(&node->shared_mem_lock); + if (module->memory_count > 0) + shared_memory_lock(module->memories[0]); #endif ret = wasm_enlarge_memory_internal(module, inc_page_count); #if WASM_ENABLE_SHARED_MEMORY != 0 - if (node) - os_mutex_unlock(&node->shared_mem_lock); + if (module->memory_count > 0) + shared_memory_unlock(module->memories[0]); #endif return ret; diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 5467065f..8e793379 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1196,7 +1196,8 @@ wasm_runtime_unload(WASMModuleCommon *module) } WASMModuleInstanceCommon * -wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst, +wasm_runtime_instantiate_internal(WASMModuleCommon *module, + WASMModuleInstanceCommon *parent, WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size) @@ -1204,14 +1205,14 @@ wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst, #if WASM_ENABLE_INTERP != 0 if (module->module_type == Wasm_Module_Bytecode) return (WASMModuleInstanceCommon *)wasm_instantiate( - (WASMModule *)module, is_sub_inst, exec_env_main, stack_size, - heap_size, error_buf, error_buf_size); + (WASMModule *)module, (WASMModuleInstance *)parent, exec_env_main, + stack_size, heap_size, error_buf, error_buf_size); #endif #if WASM_ENABLE_AOT != 0 if (module->module_type == Wasm_Module_AoT) return (WASMModuleInstanceCommon *)aot_instantiate( - (AOTModule *)module, is_sub_inst, exec_env_main, stack_size, - heap_size, error_buf, error_buf_size); + (AOTModule *)module, (AOTModuleInstance *)parent, exec_env_main, + stack_size, heap_size, error_buf, error_buf_size); #endif set_error_buf(error_buf, error_buf_size, "Instantiate module failed, invalid module type"); @@ -1224,7 +1225,7 @@ wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size, uint32 error_buf_size) { return wasm_runtime_instantiate_internal( - module, false, NULL, stack_size, heap_size, error_buf, error_buf_size); + module, NULL, NULL, stack_size, heap_size, error_buf, error_buf_size); } void @@ -2310,10 +2311,8 @@ wasm_set_exception(WASMModuleInstance *module_inst, const char *exception) WASMExecEnv *exec_env = NULL; #if WASM_ENABLE_SHARED_MEMORY != 0 - WASMSharedMemNode *node = - wasm_module_get_shared_memory((WASMModuleCommon *)module_inst->module); - if (node) - os_mutex_lock(&node->shared_mem_lock); + if (module_inst->memory_count > 0) + shared_memory_lock(module_inst->memories[0]); #endif if (exception) { snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception), @@ -2323,8 +2322,8 @@ wasm_set_exception(WASMModuleInstance *module_inst, const char *exception) module_inst->cur_exception[0] = '\0'; } #if WASM_ENABLE_SHARED_MEMORY != 0 - if (node) - os_mutex_unlock(&node->shared_mem_lock); + if (module_inst->memory_count > 0) + shared_memory_unlock(module_inst->memories[0]); #endif #if WASM_ENABLE_THREAD_MGR != 0 @@ -2386,10 +2385,8 @@ wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf) bool has_exception = false; #if WASM_ENABLE_SHARED_MEMORY != 0 - WASMSharedMemNode *node = - wasm_module_get_shared_memory((WASMModuleCommon *)module_inst->module); - if (node) - os_mutex_lock(&node->shared_mem_lock); + if (module_inst->memory_count > 0) + shared_memory_lock(module_inst->memories[0]); #endif if (module_inst->cur_exception[0] != '\0') { /* NULL is passed if the caller is not interested in getting the @@ -2403,8 +2400,8 @@ wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf) has_exception = true; } #if WASM_ENABLE_SHARED_MEMORY != 0 - if (node) - os_mutex_unlock(&node->shared_mem_lock); + if (module_inst->memory_count > 0) + shared_memory_unlock(module_inst->memories[0]); #endif return has_exception; diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 60a32cb8..f631defb 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -498,7 +498,8 @@ wasm_runtime_unload(WASMModuleCommon *module); /* Internal API */ WASMModuleInstanceCommon * -wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst, +wasm_runtime_instantiate_internal(WASMModuleCommon *module, + WASMModuleInstanceCommon *parent, WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size); diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 314938d6..c95d4b7e 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -9,9 +9,16 @@ #include "../libraries/thread-mgr/thread_manager.h" #endif -static bh_list shared_memory_list_head; -static bh_list *const shared_memory_list = &shared_memory_list_head; -static korp_mutex shared_memory_list_lock; +/* + * Note: this lock can be per memory. + * + * For now, just use a global because: + * - it's a bit cumbersome to extend WASMMemoryInstance w/o breaking + * the AOT ABI. + * - If you care performance, it's better to make the interpreters + * use atomic ops. + */ +static korp_mutex _shared_memory_lock; /* clang-format off */ enum { @@ -48,17 +55,15 @@ destroy_wait_info(void *wait_info); bool wasm_shared_memory_init() { - if (os_mutex_init(&shared_memory_list_lock) != 0) + if (os_mutex_init(&_shared_memory_lock) != 0) return false; - /* wait map not exists, create new map */ if (!(wait_map = bh_hash_map_create(32, true, (HashFunc)wait_address_hash, (KeyEqualFunc)wait_address_equal, NULL, destroy_wait_info))) { - os_mutex_destroy(&shared_memory_list_lock); + os_mutex_destroy(&_shared_memory_lock); return false; } - return true; } @@ -66,110 +71,79 @@ void wasm_shared_memory_destroy() { bh_hash_map_destroy(wait_map); - os_mutex_destroy(&shared_memory_list_lock); + os_mutex_destroy(&_shared_memory_lock); } -static WASMSharedMemNode * -search_module(WASMModuleCommon *module) +uint32 +shared_memory_inc_reference(WASMMemoryInstance *memory) { - WASMSharedMemNode *node; - - os_mutex_lock(&shared_memory_list_lock); - node = bh_list_first_elem(shared_memory_list); - - while (node) { - if (module == node->module) { - os_mutex_unlock(&shared_memory_list_lock); - return node; - } - node = bh_list_elem_next(node); - } - - os_mutex_unlock(&shared_memory_list_lock); - return NULL; + bh_assert(shared_memory_is_shared(memory)); + uint32 old; +#if BH_ATOMIC_32_IS_ATOMIC == 0 + os_mutex_lock(&_shared_memory_lock); +#endif + old = BH_ATOMIC_32_FETCH_ADD(memory->ref_count, 1); +#if BH_ATOMIC_32_IS_ATOMIC == 0 + os_mutex_unlock(&_shared_memory_lock); +#endif + bh_assert(old >= 1); + bh_assert(old < UINT32_MAX); + return old + 1; } -WASMSharedMemNode * -wasm_module_get_shared_memory(WASMModuleCommon *module) +uint32 +shared_memory_dec_reference(WASMMemoryInstance *memory) { - return search_module(module); + bh_assert(shared_memory_is_shared(memory)); + uint32 old; +#if BH_ATOMIC_32_IS_ATOMIC == 0 + os_mutex_lock(&_shared_memory_lock); +#endif + old = BH_ATOMIC_32_FETCH_SUB(memory->ref_count, 1); +#if BH_ATOMIC_32_IS_ATOMIC == 0 + os_mutex_unlock(&_shared_memory_lock); +#endif + bh_assert(old > 0); + return old - 1; } -int32 -shared_memory_inc_reference(WASMModuleCommon *module) +bool +shared_memory_is_shared(WASMMemoryInstance *memory) { - WASMSharedMemNode *node = search_module(module); - uint32 ref_count = -1; - if (node) { - os_mutex_lock(&node->lock); - ref_count = ++node->ref_count; - os_mutex_unlock(&node->lock); - } - return ref_count; + uint32 old; +#if BH_ATOMIC_32_IS_ATOMIC == 0 + os_mutex_lock(&_shared_memory_lock); +#endif + old = BH_ATOMIC_32_LOAD(memory->ref_count); +#if BH_ATOMIC_32_IS_ATOMIC == 0 + os_mutex_unlock(&_shared_memory_lock); +#endif + return old > 0; } -int32 -shared_memory_dec_reference(WASMModuleCommon *module) +static korp_mutex * +shared_memory_get_lock_pointer(WASMMemoryInstance *memory) { - WASMSharedMemNode *node = search_module(module); - uint32 ref_count = 0; - if (node) { - os_mutex_lock(&node->lock); - ref_count = --node->ref_count; - os_mutex_unlock(&node->lock); - if (ref_count == 0) { - os_mutex_lock(&shared_memory_list_lock); - bh_list_remove(shared_memory_list, node); - os_mutex_unlock(&shared_memory_list_lock); - - os_mutex_destroy(&node->shared_mem_lock); - os_mutex_destroy(&node->lock); - wasm_runtime_free(node); - } - return ref_count; - } - - return -1; + bh_assert(memory != NULL); + return &_shared_memory_lock; } -WASMMemoryInstanceCommon * -shared_memory_get_memory_inst(WASMSharedMemNode *node) +void +shared_memory_lock(WASMMemoryInstance *memory) { - return node->memory_inst; + /* + * Note: exception logic is currently abusing this lock. + * cf. https://github.com/bytecodealliance/wasm-micro-runtime/issues/2407 + */ + bh_assert(memory != NULL); + os_mutex_lock(&_shared_memory_lock); } -WASMSharedMemNode * -shared_memory_set_memory_inst(WASMModuleCommon *module, - WASMMemoryInstanceCommon *memory) +void +shared_memory_unlock(WASMMemoryInstance *memory) { - WASMSharedMemNode *node; - bh_list_status ret; - - if (!(node = wasm_runtime_malloc(sizeof(WASMSharedMemNode)))) - return NULL; - - node->module = module; - node->memory_inst = memory; - node->ref_count = 1; - - if (os_mutex_init(&node->shared_mem_lock) != 0) { - wasm_runtime_free(node); - return NULL; - } - - if (os_mutex_init(&node->lock) != 0) { - os_mutex_destroy(&node->shared_mem_lock); - wasm_runtime_free(node); - return NULL; - } - - os_mutex_lock(&shared_memory_list_lock); - ret = bh_list_insert(shared_memory_list, node); - bh_assert(ret == BH_LIST_SUCCESS); - os_mutex_unlock(&shared_memory_list_lock); - - (void)ret; - return node; + bh_assert(memory != NULL); + os_mutex_unlock(&_shared_memory_lock); } /* Atomics wait && notify APIs */ @@ -307,7 +281,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, WASMModuleInstance *module_inst = (WASMModuleInstance *)module; AtomicWaitInfo *wait_info; AtomicWaitNode *wait_node; - WASMSharedMemNode *node; + korp_mutex *lock; #if WASM_ENABLE_THREAD_MGR != 0 WASMExecEnv *exec_env; #endif @@ -322,7 +296,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, } /* Currently we have only one memory instance */ - if (!module_inst->memories[0]->is_shared) { + if (!shared_memory_is_shared(module_inst->memories[0])) { wasm_runtime_set_exception(module, "expected shared memory"); return -1; } @@ -340,30 +314,29 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, bh_assert(exec_env); #endif - node = search_module((WASMModuleCommon *)module_inst->module); - bh_assert(node); + lock = shared_memory_get_lock_pointer(module_inst->memories[0]); /* Lock the shared_mem_lock for the whole atomic wait process, and use it to os_cond_reltimedwait */ - os_mutex_lock(&node->shared_mem_lock); + os_mutex_lock(lock); no_wait = (!wait64 && *(uint32 *)address != (uint32)expect) || (wait64 && *(uint64 *)address != expect); if (no_wait) { - os_mutex_unlock(&node->shared_mem_lock); + os_mutex_unlock(lock); return 1; } if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) { - os_mutex_unlock(&node->shared_mem_lock); + os_mutex_unlock(lock); wasm_runtime_set_exception(module, "failed to create wait node"); return -1; } memset(wait_node, 0, sizeof(AtomicWaitNode)); if (0 != os_cond_init(&wait_node->wait_cond)) { - os_mutex_unlock(&node->shared_mem_lock); + os_mutex_unlock(lock); wasm_runtime_free(wait_node); wasm_runtime_set_exception(module, "failed to init wait cond"); return -1; @@ -375,7 +348,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, wait_info = acquire_wait_info(address, wait_node); if (!wait_info) { - os_mutex_unlock(&node->shared_mem_lock); + os_mutex_unlock(lock); os_cond_destroy(&wait_node->wait_cond); wasm_runtime_free(wait_node); wasm_runtime_set_exception(module, "failed to acquire wait_info"); @@ -390,7 +363,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, if (timeout < 0) { /* wait forever until it is notified or terminatied here we keep waiting and checking every second */ - os_cond_reltimedwait(&wait_node->wait_cond, &node->shared_mem_lock, + os_cond_reltimedwait(&wait_node->wait_cond, lock, (uint64)timeout_1sec); if (wait_node->status == S_NOTIFIED /* notified by atomic.notify */ #if WASM_ENABLE_THREAD_MGR != 0 @@ -404,8 +377,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, else { timeout_wait = timeout_left < timeout_1sec ? timeout_left : timeout_1sec; - os_cond_reltimedwait(&wait_node->wait_cond, &node->shared_mem_lock, - timeout_wait); + os_cond_reltimedwait(&wait_node->wait_cond, lock, timeout_wait); if (wait_node->status == S_NOTIFIED /* notified by atomic.notify */ || timeout_left <= timeout_wait /* time out */ #if WASM_ENABLE_THREAD_MGR != 0 @@ -433,7 +405,7 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, /* Release wait info if no wait nodes are attached */ map_try_release_wait_info(wait_map, wait_info, address); - os_mutex_unlock(&node->shared_mem_lock); + os_mutex_unlock(lock); return is_timeout ? 2 : 0; } @@ -445,7 +417,7 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, WASMModuleInstance *module_inst = (WASMModuleInstance *)module; uint32 notify_result; AtomicWaitInfo *wait_info; - WASMSharedMemNode *node; + korp_mutex *lock; bool out_of_bounds; bh_assert(module->module_type == Wasm_Module_Bytecode @@ -461,31 +433,30 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, } /* Currently we have only one memory instance */ - if (!module_inst->memories[0]->is_shared) { + if (!shared_memory_is_shared(module_inst->memories[0])) { /* Always return 0 for ushared linear memory since there is no way to create a waiter on it */ return 0; } - node = search_module((WASMModuleCommon *)module_inst->module); - bh_assert(node); + lock = shared_memory_get_lock_pointer(module_inst->memories[0]); /* Lock the shared_mem_lock for the whole atomic notify process, and use it to os_cond_signal */ - os_mutex_lock(&node->shared_mem_lock); + os_mutex_lock(lock); wait_info = acquire_wait_info(address, NULL); /* Nobody wait on this address */ if (!wait_info) { - os_mutex_unlock(&node->shared_mem_lock); + os_mutex_unlock(lock); return 0; } /* Notify each wait node in the wait list */ notify_result = notify_wait_list(wait_info->wait_list, count); - os_mutex_unlock(&node->shared_mem_lock); + os_mutex_unlock(lock); return notify_result; } diff --git a/core/iwasm/common/wasm_shared_memory.h b/core/iwasm/common/wasm_shared_memory.h index 6c1c4921..6a6538d2 100644 --- a/core/iwasm/common/wasm_shared_memory.h +++ b/core/iwasm/common/wasm_shared_memory.h @@ -7,53 +7,33 @@ #define _WASM_SHARED_MEMORY_H #include "bh_common.h" -#if WASM_ENABLE_INTERP != 0 -#include "wasm_runtime.h" -#endif -#if WASM_ENABLE_AOT != 0 -#include "aot_runtime.h" -#endif +#include "../interpreter/wasm_runtime.h" +#include "wasm_runtime_common.h" #ifdef __cplusplus extern "C" { #endif -typedef struct WASMSharedMemNode { - bh_list_link l; - /* Lock */ - korp_mutex lock; - /* The module reference */ - WASMModuleCommon *module; - /* The memory information */ - WASMMemoryInstanceCommon *memory_inst; - /* Lock used for atomic operations */ - korp_mutex shared_mem_lock; - - /* reference count */ - uint32 ref_count; -} WASMSharedMemNode; - bool wasm_shared_memory_init(); void wasm_shared_memory_destroy(); -WASMSharedMemNode * -wasm_module_get_shared_memory(WASMModuleCommon *module); +uint32 +shared_memory_inc_reference(WASMMemoryInstance *memory); -int32 -shared_memory_inc_reference(WASMModuleCommon *module); +uint32 +shared_memory_dec_reference(WASMMemoryInstance *memory); -int32 -shared_memory_dec_reference(WASMModuleCommon *module); +bool +shared_memory_is_shared(WASMMemoryInstance *memory); -WASMMemoryInstanceCommon * -shared_memory_get_memory_inst(WASMSharedMemNode *node); +void +shared_memory_lock(WASMMemoryInstance *memory); -WASMSharedMemNode * -shared_memory_set_memory_inst(WASMModuleCommon *module, - WASMMemoryInstanceCommon *memory); +void +shared_memory_unlock(WASMMemoryInstance *memory); uint32 wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 23e165be..94990095 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -710,28 +710,28 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint32)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint32)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = LOAD_I32(maddr); \ STORE_U32(maddr, readv op sval); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ PUSH_I32(readv); \ break; \ @@ -750,39 +750,39 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint64)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint64)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint64)LOAD_U32(maddr); \ STORE_U32(maddr, (uint32)(readv op sval)); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else { \ uint64 op_result; \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint64)LOAD_I64(maddr); \ op_result = readv op sval; \ STORE_I64(maddr, op_result); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ PUSH_I64(readv); \ break; \ @@ -1156,10 +1156,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMFunctionInstance *cur_func, WASMInterpFrame *prev_frame) { -#if WASM_ENABLE_SHARED_MEMORY != 0 - WASMSharedMemNode *node = - wasm_module_get_shared_memory((WASMModuleCommon *)module->module); -#endif WASMMemoryInstance *memory = wasm_get_default_memory(module); #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ @@ -3526,23 +3522,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint32)(*(uint8 *)maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint32)LOAD_U16(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = LOAD_I32(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } PUSH_I32(readv); @@ -3561,30 +3557,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)(*(uint8 *)maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_U16(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_U32(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = LOAD_I64(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } PUSH_I64(readv); @@ -3603,23 +3599,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I32_STORE8) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I32_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); STORE_U32(maddr, sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } break; } @@ -3637,30 +3633,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I64_STORE8) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I64_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I64_STORE32) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); STORE_U32(maddr, (uint32)sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); PUT_I64_TO_ADDR((uint32 *)maddr, sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } break; } @@ -3680,32 +3676,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint8)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint32)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint16)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint32)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = LOAD_I32(maddr); if (readv == expect) STORE_U32(maddr, sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } PUSH_I32(readv); break; @@ -3726,43 +3722,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint8)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint16)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint32)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_U32(maddr); if (readv == expect) STORE_U32(maddr, (uint32)(sval)); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_I64(maddr); if (readv == expect) STORE_I64(maddr, sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } PUSH_I64(readv); break; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 458eb2e4..729d4c60 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -482,28 +482,28 @@ LOAD_PTR(void *addr) CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(1); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint32)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##16_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(2); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint32)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(4); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = LOAD_I32(maddr); \ STORE_U32(maddr, readv op sval); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ PUSH_I32(readv); \ break; \ @@ -522,39 +522,39 @@ LOAD_PTR(void *addr) CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(1); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint64)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##16_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(2); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint64)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##32_U) { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(4); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint64)LOAD_U32(maddr); \ STORE_U32(maddr, (uint32)(readv op sval)); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ else { \ uint64 op_result; \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(8); \ \ - os_mutex_lock(&node->shared_mem_lock); \ + shared_memory_lock(memory); \ readv = (uint64)LOAD_I64(maddr); \ op_result = readv op sval; \ STORE_I64(maddr, op_result); \ - os_mutex_unlock(&node->shared_mem_lock); \ + shared_memory_unlock(memory); \ } \ PUSH_I64(readv); \ break; \ @@ -1166,10 +1166,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMFunctionInstance *cur_func, WASMInterpFrame *prev_frame) { -#if WASM_ENABLE_SHARED_MEMORY != 0 - WASMSharedMemNode *node = - wasm_module_get_shared_memory((WASMModuleCommon *)module->module); -#endif WASMMemoryInstance *memory = wasm_get_default_memory(module); #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ @@ -3353,23 +3349,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint32)(*(uint8 *)maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint32)LOAD_U16(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = LOAD_I32(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } PUSH_I32(readv); @@ -3388,30 +3384,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)(*(uint8 *)maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_U16(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_U32(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(8); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = LOAD_I64(maddr); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } PUSH_I64(readv); @@ -3429,23 +3425,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I32_STORE8) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I32_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); STORE_U32(maddr, sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } break; } @@ -3463,30 +3459,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode == WASM_OP_ATOMIC_I64_STORE8) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I64_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_I64_STORE32) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); STORE_U32(maddr, (uint32)sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(8); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); STORE_I64(maddr, sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } break; } @@ -3506,32 +3502,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(1); expect = (uint8)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint32)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); expect = (uint16)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint32)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = LOAD_I32(maddr); if (readv == expect) STORE_U32(maddr, sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } PUSH_I32(readv); break; @@ -3552,43 +3548,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(1); expect = (uint8)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); expect = (uint16)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); expect = (uint32)expect; - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_U32(maddr); if (readv == expect) STORE_U32(maddr, (uint32)(sval)); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(8); - os_mutex_lock(&node->shared_mem_lock); + shared_memory_lock(memory); readv = (uint64)LOAD_I64(maddr); if (readv == expect) STORE_I64(maddr, sval); - os_mutex_unlock(&node->shared_mem_lock); + shared_memory_unlock(memory); } PUSH_I64(readv); break; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 497e6b19..eef2e368 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -122,11 +122,8 @@ memories_deinstantiate(WASMModuleInstance *module_inst, } #endif #if WASM_ENABLE_SHARED_MEMORY != 0 - if (memories[i]->is_shared) { - int32 ref_count = shared_memory_dec_reference( - (WASMModuleCommon *)module_inst->module); - bh_assert(ref_count >= 0); - + if (shared_memory_is_shared(memories[i])) { + uint32 ref_count = shared_memory_dec_reference(memories[i]); /* if the reference count is not zero, don't free the memory */ if (ref_count > 0) @@ -159,7 +156,8 @@ memories_deinstantiate(WASMModuleInstance *module_inst, } static WASMMemoryInstance * -memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory, +memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, + WASMMemoryInstance *memory, uint32 memory_idx, uint32 num_bytes_per_page, uint32 init_page_count, uint32 max_page_count, uint32 heap_size, uint32 flags, char *error_buf, uint32 error_buf_size) @@ -180,22 +178,11 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory, bool is_shared_memory = flags & 0x02 ? true : false; /* shared memory */ - if (is_shared_memory) { - WASMSharedMemNode *node = wasm_module_get_shared_memory( - (WASMModuleCommon *)module_inst->module); - /* If the memory of this module has been instantiated, - return the memory instance directly */ - if (node) { - uint32 ref_count; - ref_count = shared_memory_inc_reference( - (WASMModuleCommon *)module_inst->module); - bh_assert(ref_count > 0); - memory = (WASMMemoryInstance *)shared_memory_get_memory_inst(node); - bh_assert(memory); - - (void)ref_count; - return memory; - } + if (is_shared_memory && parent != NULL) { + bh_assert(parent->memory_count > memory_idx); + memory = parent->memories[memory_idx]; + shared_memory_inc_reference(memory); + return memory; } #endif /* end of WASM_ENABLE_SHARED_MEMORY */ @@ -388,24 +375,13 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory, #if WASM_ENABLE_SHARED_MEMORY != 0 if (is_shared_memory) { - memory->is_shared = true; - if (!shared_memory_set_memory_inst( - (WASMModuleCommon *)module_inst->module, - (WASMMemoryInstanceCommon *)memory)) { - set_error_buf(error_buf, error_buf_size, "allocate memory failed"); - goto fail4; - } + memory->ref_count = 1; } #endif LOG_VERBOSE("Memory instantiate success."); return memory; -#if WASM_ENABLE_SHARED_MEMORY != 0 -fail4: - if (heap_size > 0) - mem_allocator_destroy(memory->heap_handle); -#endif fail3: if (heap_size > 0) wasm_runtime_free(memory->heap_handle); @@ -428,7 +404,8 @@ fail1: */ static WASMMemoryInstance ** memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, - uint32 heap_size, char *error_buf, uint32 error_buf_size) + WASMModuleInstance *parent, uint32 heap_size, + char *error_buf, uint32 error_buf_size) { WASMImport *import; uint32 mem_index = 0, i, @@ -474,26 +451,29 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, else #endif { - if (!(memories[mem_index++] = memory_instantiate( - module_inst, memory, num_bytes_per_page, init_page_count, - max_page_count, actual_heap_size, flags, error_buf, - error_buf_size))) { + if (!(memories[mem_index] = memory_instantiate( + module_inst, parent, memory, mem_index, + num_bytes_per_page, init_page_count, max_page_count, + actual_heap_size, flags, error_buf, error_buf_size))) { memories_deinstantiate(module_inst, memories, memory_count); return NULL; } + mem_index++; } } /* instantiate memories from memory section */ for (i = 0; i < module->memory_count; i++, memory++) { - if (!(memories[mem_index++] = memory_instantiate( - module_inst, memory, module->memories[i].num_bytes_per_page, + if (!(memories[mem_index] = memory_instantiate( + module_inst, parent, memory, mem_index, + module->memories[i].num_bytes_per_page, module->memories[i].init_page_count, module->memories[i].max_page_count, heap_size, module->memories[i].flags, error_buf, error_buf_size))) { memories_deinstantiate(module_inst, memories, memory_count); return NULL; } + mem_index++; } bh_assert(mem_index == memory_count); @@ -1301,7 +1281,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, WASMModuleInstance *sub_module_inst = NULL; sub_module_inst = - wasm_instantiate(sub_module, false, NULL, stack_size, heap_size, + wasm_instantiate(sub_module, NULL, NULL, stack_size, heap_size, error_buf, error_buf_size); if (!sub_module_inst) { LOG_DEBUG("instantiate %s failed", @@ -1646,7 +1626,7 @@ wasm_set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode) * Instantiate module */ WASMModuleInstance * -wasm_instantiate(WASMModule *module, bool is_sub_inst, +wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size) { @@ -1663,6 +1643,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, #if WASM_ENABLE_MULTI_MODULE != 0 bool ret = false; #endif + const bool is_sub_inst = parent != NULL; if (!module) return NULL; @@ -1781,8 +1762,9 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, /* Instantiate memories/tables/functions */ if ((module_inst->memory_count > 0 - && !(module_inst->memories = memories_instantiate( - module, module_inst, heap_size, error_buf, error_buf_size))) + && !(module_inst->memories = + memories_instantiate(module, module_inst, parent, heap_size, + error_buf, error_buf_size))) || (module_inst->table_count > 0 && !(module_inst->tables = tables_instantiate(module, module_inst, first_table, diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index d5665c24..6698d0e7 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -7,6 +7,7 @@ #define _WASM_RUNTIME_H #include "wasm.h" +#include "bh_atomic.h" #include "bh_hashmap.h" #include "../common/wasm_runtime_common.h" #include "../common/wasm_exec_env.h" @@ -79,7 +80,7 @@ struct WASMMemoryInstance { /* Module type */ uint32 module_type; /* Shared memory flag */ - bool is_shared; + bh_atomic_32_t ref_count; /* 0: non-shared, > 0: reference count */ /* Number bytes per page */ uint32 num_bytes_per_page; @@ -400,7 +401,7 @@ void wasm_unload(WASMModule *module); WASMModuleInstance * -wasm_instantiate(WASMModule *module, bool is_sub_inst, +wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size); diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 1a41fe9d..b8a64116 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -581,7 +581,7 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, #endif if (!(new_module_inst = wasm_runtime_instantiate_internal( - module, true, exec_env, stack_size, 0, NULL, 0))) + module, module_inst, exec_env, stack_size, 0, NULL, 0))) return -1; /* Set custom_data to new module instance */ diff --git a/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c b/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c index 6b36c907..a5f72986 100644 --- a/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c +++ b/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c @@ -90,7 +90,7 @@ thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg) stack_size = ((WASMModuleInstance *)module_inst)->default_wasm_stack_size; if (!(new_module_inst = wasm_runtime_instantiate_internal( - module, true, exec_env, stack_size, 0, NULL, 0))) + module, module_inst, exec_env, stack_size, 0, NULL, 0))) return -1; wasm_runtime_set_custom_data_internal( diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index fc44652e..4d1da83a 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -509,7 +509,7 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) #endif if (!(new_module_inst = wasm_runtime_instantiate_internal( - module, true, exec_env, stack_size, 0, NULL, 0))) { + module, module_inst, exec_env, stack_size, 0, NULL, 0))) { goto fail1; } @@ -1254,10 +1254,8 @@ set_exception_visitor(void *node, void *user_data) /* Only spread non "wasi proc exit" exception */ #if WASM_ENABLE_SHARED_MEMORY != 0 - WASMSharedMemNode *shared_mem_node = wasm_module_get_shared_memory( - (WASMModuleCommon *)curr_wasm_inst->module); - if (shared_mem_node) - os_mutex_lock(&shared_mem_node->shared_mem_lock); + if (curr_wasm_inst->memory_count > 0) + shared_memory_lock(curr_wasm_inst->memories[0]); #endif if (!strstr(wasm_inst->cur_exception, "wasi proc exit")) { bh_memcpy_s(curr_wasm_inst->cur_exception, @@ -1266,8 +1264,8 @@ set_exception_visitor(void *node, void *user_data) sizeof(wasm_inst->cur_exception)); } #if WASM_ENABLE_SHARED_MEMORY != 0 - if (shared_mem_node) - os_mutex_unlock(&shared_mem_node->shared_mem_lock); + if (curr_wasm_inst->memory_count > 0) + shared_memory_unlock(curr_wasm_inst->memories[0]); #endif /* Terminate the thread so it can exit from dead loops */ @@ -1286,15 +1284,13 @@ clear_exception_visitor(void *node, void *user_data) (WASMModuleInstance *)get_module_inst(curr_exec_env); #if WASM_ENABLE_SHARED_MEMORY != 0 - WASMSharedMemNode *shared_mem_node = wasm_module_get_shared_memory( - (WASMModuleCommon *)curr_wasm_inst->module); - if (shared_mem_node) - os_mutex_lock(&shared_mem_node->shared_mem_lock); + if (curr_wasm_inst->memory_count > 0) + shared_memory_lock(curr_wasm_inst->memories[0]); #endif curr_wasm_inst->cur_exception[0] = '\0'; #if WASM_ENABLE_SHARED_MEMORY != 0 - if (shared_mem_node) - os_mutex_unlock(&shared_mem_node->shared_mem_lock); + if (curr_wasm_inst->memory_count > 0) + shared_memory_unlock(curr_wasm_inst->memories[0]); #endif } } From 8fc621a1b21655df6ffdb43a34b73eda303f69db Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 4 Aug 2023 14:32:04 +0800 Subject: [PATCH 29/30] Add runtime inited checks in Enclave command handlings to improve security (#2416) Call ecall commands arbitrarily from host when enclave's runtime isn't initialized may cause unexpected behavior, for example, load/instantiate wasm module. Add runtime inited status checks in enclave to improve the security. Also fix `wait_map` issue mentioned in https://github.com/bytecodealliance/wasm-micro-runtime/issues/2252#issuecomment-1634940219 --- .../enclave-sample/Enclave/Enclave.cpp | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index 9ed17e1c..164fa0b7 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -92,6 +92,8 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) snprintf(error_buf, error_buf_size, "%s", string); } +static bool runtime_inited = false; + static void handle_cmd_init_runtime(uint64 *args, uint32 argc) { @@ -100,6 +102,12 @@ handle_cmd_init_runtime(uint64 *args, uint32 argc) bh_assert(argc == 1); + /* avoid duplicated init */ + if (runtime_inited) { + args[0] = false; + return; + } + os_set_print_function(enclave_print); max_thread_num = (uint32)args[0]; @@ -122,6 +130,7 @@ handle_cmd_init_runtime(uint64 *args, uint32 argc) return; } + runtime_inited = true; args[0] = true; LOG_VERBOSE("Init runtime environment success.\n"); @@ -130,7 +139,11 @@ handle_cmd_init_runtime(uint64 *args, uint32 argc) static void handle_cmd_destroy_runtime() { + if (!runtime_inited) + return; + wasm_runtime_destroy(); + runtime_inited = false; LOG_VERBOSE("Destroy runtime success.\n"); } @@ -214,6 +227,11 @@ handle_cmd_load_module(uint64 *args, uint32 argc) bh_assert(argc == 4); + if (!runtime_inited) { + *(void **)args_org = NULL; + return; + } + if (!is_xip_file((uint8 *)wasm_file, wasm_file_size)) { if (total_size >= UINT32_MAX || !(enclave_module = (EnclaveModule *)wasm_runtime_malloc( @@ -284,6 +302,10 @@ handle_cmd_unload_module(uint64 *args, uint32 argc) bh_assert(argc == 1); + if (!runtime_inited) { + return; + } + #if WASM_ENABLE_LIB_RATS != 0 /* Remove enclave module from enclave module list */ os_mutex_lock(&enclave_module_list_lock); @@ -354,6 +376,11 @@ handle_cmd_instantiate_module(uint64 *args, uint32 argc) bh_assert(argc == 5); + if (!runtime_inited) { + *(void **)args_org = NULL; + return; + } + if (!(module_inst = wasm_runtime_instantiate(enclave_module->module, stack_size, heap_size, error_buf, error_buf_size))) { @@ -373,6 +400,10 @@ handle_cmd_deinstantiate_module(uint64 *args, uint32 argc) bh_assert(argc == 1); + if (!runtime_inited) { + return; + } + wasm_runtime_deinstantiate(module_inst); LOG_VERBOSE("Deinstantiate module success.\n"); @@ -389,6 +420,11 @@ handle_cmd_get_exception(uint64 *args, uint32 argc) bh_assert(argc == 3); + if (!runtime_inited) { + args_org[0] = false; + return; + } + if ((exception1 = wasm_runtime_get_exception(module_inst))) { snprintf(exception, exception_size, "%s", exception1); args_org[0] = true; @@ -410,6 +446,10 @@ handle_cmd_exec_app_main(uint64 *args, int32 argc) bh_assert(argc >= 3); bh_assert(app_argc >= 1); + if (!runtime_inited) { + return; + } + total_size = sizeof(char *) * (app_argc > 2 ? (uint64)app_argc : 2); if (total_size >= UINT32_MAX @@ -439,6 +479,10 @@ handle_cmd_exec_app_func(uint64 *args, int32 argc) bh_assert(argc == app_argc + 3); + if (!runtime_inited) { + return; + } + total_size = sizeof(char *) * (app_argc > 2 ? (uint64)app_argc : 2); if (total_size >= UINT32_MAX @@ -488,6 +532,11 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc) bh_assert(argc == 10); + if (!runtime_inited) { + *args_org = false; + return; + } + total_size += sizeof(char *) * (uint64)dir_list_size + sizeof(char *) * (uint64)env_list_size + sizeof(char *) * (uint64)addr_pool_list_size @@ -610,6 +659,11 @@ handle_cmd_get_pgo_prof_buf_size(uint64 *args, int32 argc) bh_assert(argc == 1); + if (!runtime_inited) { + args[0] = 0; + return; + } + buf_len = wasm_runtime_get_pgo_prof_data_size(module_inst); args[0] = buf_len; } @@ -625,6 +679,11 @@ handle_cmd_get_pro_prof_buf_data(uint64 *args, int32 argc) bh_assert(argc == 3); + if (!runtime_inited) { + args_org[0] = 0; + return; + } + bytes_dumped = wasm_runtime_dump_pgo_prof_data_to_buf(module_inst, buf, len); args_org[0] = bytes_dumped; @@ -704,6 +763,11 @@ ecall_iwasm_main(uint8_t *wasm_file_buf, uint32_t wasm_file_size) char error_buf[128]; const char *exception; + /* avoid duplicated init */ + if (runtime_inited) { + return; + } + os_set_print_function(enclave_print); memset(&init_args, 0, sizeof(RuntimeInitArgs)); From ebd9466d57b6565e4211c71faefe13076cac2e3c Mon Sep 17 00:00:00 2001 From: dongsheng28849455 <68947925+dongsheng28849455@users.noreply.github.com> Date: Sun, 6 Aug 2023 08:08:11 +0800 Subject: [PATCH 30/30] Add some relocation symbols for xtensa target (#2422) --- core/iwasm/aot/arch/aot_reloc_xtensa.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/iwasm/aot/arch/aot_reloc_xtensa.c b/core/iwasm/aot/arch/aot_reloc_xtensa.c index 6ca6a085..a29c9f2b 100644 --- a/core/iwasm/aot/arch/aot_reloc_xtensa.c +++ b/core/iwasm/aot/arch/aot_reloc_xtensa.c @@ -43,6 +43,11 @@ void __floatdidf(); void __divsf3(); void __fixdfdi(); void __floatundidf(); +void __fixsfdi(); +void __fixunssfdi(); +void __fixunsdfdi(); +void __floatdisf(); +void __floatundisf(); static SymbolMap target_sym_map[] = { @@ -85,6 +90,11 @@ static SymbolMap target_sym_map[] = { REG_SYM(__divsf3), REG_SYM(__fixdfdi), REG_SYM(__floatundidf), + REG_SYM(__fixsfdi), + REG_SYM(__fixunssfdi), + REG_SYM(__fixunsdfdi), + REG_SYM(__floatdisf), + REG_SYM(__floatundisf), }; /* clang-format on */