diff --git a/CMakeLists.txt b/CMakeLists.txt index d77473e037..00c459f9c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required (VERSION 2.8...3.16) project (iwasm) # set (CMAKE_VERBOSE_MAKEFILE 1) -set (WAMR_BUILD_PLATFORM "linux") +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) # Reset default linker flags set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -18,7 +18,7 @@ set (CMAKE_C_STANDARD 99) # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") diff --git a/build-scripts/esp-idf/README.md b/build-scripts/esp-idf/README.md new file mode 100644 index 0000000000..6bec45d1e7 --- /dev/null +++ b/build-scripts/esp-idf/README.md @@ -0,0 +1,31 @@ +# wasm-micro-runtime as ESP-IDF component + +You can build an ESP-IDF project with wasm-micro-runtime as a component: + +- Make sure you have the ESP-IDF properly installed and setup +- In particular have the following paths set: + - `WAMR_PATH` to point to your wasm-micro-runtime repository + - `IDF_PATH` to point to your ESP-IDF + - `source $IDF_PATH/export.sh` +- Create a new project, e.g.: `idf.py create-project wamr-hello` +- In the newly created project folder edit the `CMakeList.txt`: + + ``` + cmake_minimum_required(VERSION 3.5) + + include($ENV{IDF_PATH}/tools/cmake/project.cmake) + + set (COMPONENTS ${IDF_TARGET} main freertos esptool_py wamr) + + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{WAMR_PATH}/build-scripts/esp-idf") + + project(wamr-hello) + ``` +- Develop your project in it's `main` component folder. + +You can find an example [here](../../product-mini/platforms/esp-idf). + +- Set target platform: `idf.py set-target esp32c3` +- Build: `idf.py build` +- Flash: `idf.py flash` +- Check the output: `idf.py monitor` \ No newline at end of file diff --git a/build-scripts/esp-idf/wamr/CMakeLists.txt b/build-scripts/esp-idf/wamr/CMakeLists.txt new file mode 100644 index 0000000000..c7b6100ec8 --- /dev/null +++ b/build-scripts/esp-idf/wamr/CMakeLists.txt @@ -0,0 +1,57 @@ +# Copyright (C) 2021 Intel Corporation and others. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Set WAMR's build options +if("${IDF_TARGET}" STREQUAL "esp32c3") + set(WAMR_BUILD_TARGET "RISCV32") +else() + set(WAMR_BUILD_TARGET "XTENSA") +endif() + +set(WAMR_BUILD_PLATFORM "esp-idf") + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + set (WAMR_BUILD_FAST_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + set (WAMR_BUILD_AOT 1) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +if (NOT DEFINED WAMR_BUILD_APP_FRAMEWORK) + set (WAMR_BUILD_APP_FRAMEWORK 0) +endif () + +if (NOT CMAKE_BUILD_EARLY_EXPANSION) + if (WAMR_BUILD_TARGET STREQUAL "XTENSA") + idf_build_set_property(COMPILE_DEFINITIONS "-DBUILD_TARGET_XTENSA=1" APPEND) + endif () + if (WAMR_BUILD_INTERP) + idf_build_set_property(COMPILE_DEFINITIONS "-DWASM_ENABLE_INTERP=1" APPEND) + endif () + if (WAMR_BUILD_AOT) + idf_build_set_property(COMPILE_DEFINITIONS "-DWASM_ENABLE_AOT=1" APPEND) + endif () + + set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) + include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +endif() + +idf_component_register(SRCS ${WAMR_RUNTIME_LIB_SOURCE} ${PLATFORM_SHARED_SOURCE} + INCLUDE_DIRS ${IWASM_DIR}/include ${UTILS_SHARED_DIR} ${PLATFORM_SHARED_DIR} ${PLATFORM_SHARED_DIR}/../include + REQUIRES pthread +) + + diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 2ef197fc7d..513a0a6c2b 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -34,7 +34,7 @@ endif () # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") diff --git a/ci/Dockerfile b/ci/Dockerfile index f90e4cc7cc..b6e5af48bc 100644 --- a/ci/Dockerfile +++ b/ci/Dockerfile @@ -1,6 +1,8 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# tie the ${VARIANT} and a llvm binary release together +# please find a matched version on https://github.com/llvm/llvm-project/releases ARG VARIANT=focal FROM ubuntu:${VARIANT} @@ -34,6 +36,24 @@ RUN cd /opt/emsdk \ && ./emsdk activate 2.0.26 \ && echo "source /opt/emsdk/emsdk_env.sh" >> /root/.bashrc +# +# install clang and llvm release +ARG CLANG_VER=13.0.0 +RUN wget https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VER}/clang+llvm-${CLANG_VER}-x86_64-linux-gnu-ubuntu-20.04.tar.xz -P /opt +RUN cd /opt \ + && tar xf clang+llvm-${CLANG_VER}-x86_64-linux-gnu-ubuntu-20.04.tar.xz \ + && ln -sf clang+llvm-${CLANG_VER}-x86_64-linux-gnu-ubuntu-20.04 clang-llvm +RUN rm /opt/clang+llvm-${CLANG_VER}-x86_64-linux-gnu-ubuntu-20.04.tar.xz + + +# +# install wasi-sdk +ARG WASI_SDK_VER=14 +RUN wget -c https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt +RUN tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \ + && ln -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk +RUN rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz + # #install wabt ARG WABT_VER=1.0.24 @@ -42,15 +62,6 @@ RUN tar xf /opt/wabt-${WABT_VER}-ubuntu.tar.gz -C /opt \ && ln -fs /opt/wabt-${WABT_VER} /opt/wabt RUN rm /opt/wabt-${WABT_VER}-ubuntu.tar.gz -# -# install binaryen -ARG BINARYEN_VER=version_101 -RUN wget -c https://github.com/WebAssembly/binaryen/releases/download/${BINARYEN_VER}/binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz -P /opt -RUN tar xf /opt/binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz -C /opt \ - && ln -fs /opt/binaryen-${BINARYEN_VER} /opt/binaryen -RUN rm /opt/binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz - - # # install bazelisk ARG BAZELISK_VER=1.10.1 @@ -59,8 +70,13 @@ RUN wget -c https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK RUN chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \ && ln -fs /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazel +# +# install +RUN apt update && apt install -y clang-format + # set path -RUN echo "PATH=/opt/clang_llvm/bin:/opt/wasi-sdk/bin:/opt/wabt/bin:/opt/binaryen/bin:/opt/bazelisk:${PATH}" >> /root/.bashrc +ENV PATH "$PATH:/opt/wasi-sdk/bin:/opt/wabt/bin:/opt/binaryen/bin:/opt/bazelisk:/opt/clang-llvm/bin" +RUN echo "export PATH=/opt/wasi-sdk/bin:/opt/wabt/bin:/opt/binaryen/bin:/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" >> /root/.bashrc # # PS @@ -72,5 +88,5 @@ RUN apt-get autoremove -y \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* -VOLUME workspace -WORKDIR workspace +VOLUME /workspace +WORKDIR /workspace diff --git a/ci/build_wamr.sh b/ci/build_wamr.sh index 9b944662e6..b7e6c049d3 100755 --- a/ci/build_wamr.sh +++ b/ci/build_wamr.sh @@ -8,26 +8,27 @@ readonly ROOT=$(realpath "${CURRENT_PATH}/..") readonly VARIANT=$(lsb_release -c | awk '{print $2}') docker build \ - --build-arg VARIANT=${VARIANT} \ - --memory=4G --cpu-quota=50000 \ - -t wamr_dev_${VARIANT}:0.1 -f "${CURRENT_PATH}"/Dockerfile "${CURRENT_PATH}" && - docker run --rm -it \ - --cpus=".5" \ - --memory=4G \ - --name wamr_build_env \ - --mount type=bind,src="${ROOT}",dst=/workspace \ - wamr_dev_${VARIANT}:0.1 \ - /bin/bash -c "\ - pwd \ - && pushd product-mini/platforms/linux \ - && rm -rf build \ - && mkdir build \ - && pushd build \ - && cmake .. \ - && make \ - && popd \ - && popd \ - && echo 'Copying the binary ...' \ - && rm -rf build_out \ - && mkdir build_out \ - && cp product-mini/platforms/linux/build/iwasm build_out/iwasm" + --memory=4G --cpu-quota=50000 \ + -t wamr_dev_${VARIANT}:0.1 -f "${CURRENT_PATH}"/Dockerfile "${CURRENT_PATH}" \ + && docker run --rm -it \ + --cap-add=SYS_PTRACE \ + --cpus=".5" \ + --memory=4G \ + --mount type=bind,src="${ROOT}",dst=/workspace \ + --name wamr_build_env \ + --security-opt=seccomp=unconfined \ + wamr_dev_${VARIANT}:0.1 \ + /bin/bash -c "\ + pwd \ + && pushd product-mini/platforms/linux \ + && rm -rf build \ + && mkdir build \ + && pushd build \ + && cmake .. \ + && make \ + && popd \ + && popd \ + && echo 'Copying the binary ...' \ + && rm -rf build_out \ + && mkdir build_out \ + && cp product-mini/platforms/linux/build/iwasm build_out/iwasm" diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index f8766ddee7..bac3b476b9 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -90,7 +90,8 @@ static bool check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length, char *error_buf, uint32 error_buf_size) { - if (buf + length < buf || buf + length > buf_end) { + if ((uintptr_t)buf + length < (uintptr_t)buf + || (uintptr_t)buf + length > (uintptr_t)buf_end) { set_error_buf(error_buf, error_buf_size, "unexpect end"); return false; } @@ -853,6 +854,7 @@ load_import_table_list(const uint8 **p_buf, const uint8 *buf_end, /* keep sync with aot_emit_table_info() aot_emit_aot_file */ for (i = 0; i < module->import_table_count; i++, import_table++) { + read_uint32(buf, buf_end, import_table->elem_type); read_uint32(buf, buf_end, import_table->table_init_size); read_uint32(buf, buf_end, import_table->table_max_size); read_uint32(buf, buf_end, possible_grow); @@ -1575,8 +1577,10 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module, #if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) if (module->func_count > 0) { + uint32 plt_table_size = + module->is_indirect_mode ? 0 : get_plt_table_size(); rtl_func_table[module->func_count - 1].EndAddress = - (DWORD)(module->code_size - get_plt_table_size()); + (DWORD)(module->code_size - plt_table_size); if (!RtlAddFunctionTable(rtl_func_table, module->func_count, (DWORD64)(uintptr_t)module->code)) { @@ -2113,19 +2117,29 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, memcpy(group_name_buf, group_name, group_name_len); memcpy(symbol_name_buf, symbol_name, symbol_name_len); - if (group_name_len == strlen(".text") + if ((group_name_len == strlen(".text") + || (module->is_indirect_mode + && group_name_len == strlen(".text") + 1)) && !strncmp(group_name, ".text", strlen(".text"))) { - if (symbol_name_len == strlen(XMM_PLT_PREFIX) + 32 + if ((symbol_name_len == strlen(XMM_PLT_PREFIX) + 32 + || (module->is_indirect_mode + && symbol_name_len == strlen(XMM_PLT_PREFIX) + 32 + 1)) && !strncmp(symbol_name, XMM_PLT_PREFIX, strlen(XMM_PLT_PREFIX))) { module->xmm_plt_count++; } - else if (symbol_name_len == strlen(REAL_PLT_PREFIX) + 16 + else if ((symbol_name_len == strlen(REAL_PLT_PREFIX) + 16 + || (module->is_indirect_mode + && symbol_name_len + == strlen(REAL_PLT_PREFIX) + 16 + 1)) && !strncmp(symbol_name, REAL_PLT_PREFIX, strlen(REAL_PLT_PREFIX))) { module->real_plt_count++; } - else if (symbol_name_len == strlen(REAL_PLT_PREFIX) + 8 + else if ((symbol_name_len >= strlen(REAL_PLT_PREFIX) + 8 + || (module->is_indirect_mode + && symbol_name_len + == strlen(REAL_PLT_PREFIX) + 8 + 1)) && !strncmp(symbol_name, REAL_PLT_PREFIX, strlen(REAL_PLT_PREFIX))) { module->float_plt_count++; @@ -2230,7 +2244,7 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, #endif ) { #if !defined(BH_PLATFORM_LINUX) && !defined(BH_PLATFORM_LINUX_SGX) \ - && !defined(BH_PLATFORM_DARWIN) + && !defined(BH_PLATFORM_DARWIN) && !defined(BH_PLATFORM_WINDOWS) if (module->is_indirect_mode) { set_error_buf(error_buf, error_buf_size, "cannot apply relocation to text section " diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 7cad5d3be4..6a78e1dc97 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -85,7 +85,7 @@ init_global_data(uint8 *global_data, uint8 type, WASMValue *initial_value) switch (type) { case VALUE_TYPE_I32: case VALUE_TYPE_F32: -#if WASM_ENABLE_REF_TYPES +#if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: case VALUE_TYPE_EXTERNREF: #endif @@ -460,6 +460,8 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, LOG_VERBOSE("Memory instantiate:"); LOG_VERBOSE(" page bytes: %u, init pages: %u, max pages: %u", num_bytes_per_page, init_page_count, max_page_count); + LOG_VERBOSE(" data offset: %u, stack size: %d", module->aux_data_end, + module->aux_stack_size); LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size); total_size = (uint64)num_bytes_per_page * init_page_count; @@ -1260,6 +1262,11 @@ aot_exception_handler(EXCEPTION_POINTERS *exce_info) return EXCEPTION_CONTINUE_EXECUTION; } } + + os_printf("Unhandled exception thrown: exception code: 0x%lx, " + "exception address: %p, exception information: %p\n", + ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionAddress, + sig_addr); return EXCEPTION_CONTINUE_SEARCH; } #endif /* end of BH_PLATFORM_WINDOWS */ @@ -1565,16 +1572,8 @@ aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, } } -#if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_prepare_call_function(exec_env, func); -#endif - ret = aot_call_function(exec_env, func, argc, argv); -#if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_finalize_call_function(exec_env, func, ret, argv); -#endif - /* don't destroy the exec_env if it's searched from the cluster */ if (!existing_exec_env) wasm_exec_env_destroy(exec_env); diff --git a/core/iwasm/aot/arch/aot_reloc_xtensa.c b/core/iwasm/aot/arch/aot_reloc_xtensa.c index 26c60358ef..5e1a34c4e7 100644 --- a/core/iwasm/aot/arch/aot_reloc_xtensa.c +++ b/core/iwasm/aot/arch/aot_reloc_xtensa.c @@ -112,7 +112,7 @@ put_imm16_to_addr(int16 imm16, int16 *addr) if ((intptr_t)addr % 4 != 3) { *(int32 *)bytes = *addr_aligned1; *(int16 *)(bytes + ((intptr_t)addr % 4)) = imm16; - memcpy(addr_aligned1, bytes, 4); + *addr_aligned1 = *(int32 *)bytes; } else { addr_aligned2 = (int32 *)(((intptr_t)addr + 3) & ~3); diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 3555c9aab8..fcbeb30e29 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -82,6 +82,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, { WASMFunctionInstanceCommon *func; WASMType *func_type = NULL; + WASMExecEnv *exec_env = NULL; uint32 argc1 = 0, argv1[2] = { 0 }; uint32 total_argv_size = 0; uint64 total_size; @@ -91,14 +92,20 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, uint32 *argv_offsets, module_type; bool ret, is_import_func = true; + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (!exec_env) { + wasm_runtime_set_exception(module_inst, + "create singleton exec_env failed"); + return false; + } + #if WASM_ENABLE_LIBC_WASI != 0 /* In wasi mode, we should call the function named "_start" which initializes the wasi envrionment and then calls the actual main function. Directly calling main function may cause exception thrown. */ if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) { - return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, 0, - NULL); + return wasm_runtime_call_wasm(exec_env, func, 0, NULL); } #endif /* end of WASM_ENABLE_LIBC_WASI */ @@ -179,8 +186,7 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, (uint32)wasm_runtime_addr_native_to_app(module_inst, argv_offsets); } - ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, argc1, - argv1); + ret = wasm_runtime_call_wasm(exec_env, func, argc1, argv1); if (ret && func_type->result_count > 0 && argc > 0 && argv) /* copy the return value */ *(int *)argv = (int)argv1[0]; @@ -345,7 +351,11 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *target_func; WASMModuleInstanceCommon *target_inst; WASMType *type = NULL; + WASMExecEnv *exec_env = NULL; uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 param_size_in_double_world = 0, result_size_in_double_world = 0; +#endif int32 i, p, module_type; uint64 total_size; const char *exception; @@ -373,8 +383,23 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, goto fail; } +#if WASM_ENABLE_REF_TYPES != 0 + for (i = 0; i < type->param_count; i++) { + param_size_in_double_world += + wasm_value_type_cell_num_outside(type->types[i]); + } + for (i = 0; i < type->result_count; i++) { + result_size_in_double_world += wasm_value_type_cell_num_outside( + type->types[type->param_count + i]); + } + argc1 = param_size_in_double_world; + cell_num = (param_size_in_double_world >= result_size_in_double_world) + ? param_size_in_double_world + : result_size_in_double_world; +#else argc1 = type->param_cell_num; cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num; +#endif total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2); if ((!(argv1 = runtime_malloc((uint32)total_size, target_inst, NULL, 0)))) { @@ -487,9 +512,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: { - if (strncmp(argv[i], "null", 4) == 0 - || strncmp(argv[i], "NULL", 4) == 0) { - argv1[p++] = NULL_REF; + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = (uint32)-1; } else { argv1[p++] = (uint32)strtoul(argv[i], &endptr, 0); @@ -498,23 +522,27 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } case VALUE_TYPE_EXTERNREF: { - if (strncmp(argv[i], "null", 4) == 0 - || strncmp(argv[i], "NULL", 4) == 0) { - argv1[p++] = NULL_REF; +#if UINTPTR_MAX == UINT32_MAX + if (strncasecmp(argv[i], "null", 4) == 0) { + argv1[p++] = (uint32)-1; } else { - uint64 val = strtoull(argv[i], &endptr, 0); - void *extern_obj = (void *)(uintptr_t)val; - uint32 externref_idx; - - if (!wasm_externref_obj2ref(target_inst, extern_obj, - &externref_idx)) { - wasm_runtime_set_exception( - module_inst, "map extern object to ref failed"); - goto fail; - } - argv1[p++] = externref_idx; + argv1[p++] = strtoul(argv[i], &endptr, 0); + } +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + if (strncasecmp(argv[i], "null", 4) == 0) { + u.val = (uintptr_t)-1LL; + } + else { + u.val = strtoull(argv[i], &endptr, 0); } + argv1[p++] = u.parts[0]; + argv1[p++] = u.parts[1]; +#endif break; } #endif /* WASM_ENABLE_REF_TYPES */ @@ -529,11 +557,20 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, goto fail; } } - bh_assert(p == (int32)argc1); wasm_runtime_set_exception(module_inst, NULL); - if (!wasm_runtime_create_exec_env_and_call_wasm(target_inst, target_func, - argc1, argv1)) { +#if WASM_ENABLE_REF_TYPES == 0 + bh_assert(p == (int32)argc1); +#endif + + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (!exec_env) { + wasm_runtime_set_exception(module_inst, + "create singleton exec_env failed"); + goto fail; + } + + if (!wasm_runtime_call_wasm(exec_env, target_func, argc1, argv1)) { goto fail; } @@ -576,7 +613,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, os_printf("%.7g:f64", u.val); break; } -#if WASM_ENABLE_REF_TYPES +#if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: { if (argv1[k] != NULL_REF) @@ -588,16 +625,25 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, } case VALUE_TYPE_EXTERNREF: { - if (argv1[k] != NULL_REF) { - void *extern_obj = NULL; - bool ret = wasm_externref_ref2obj(argv1[k], &extern_obj); - bh_assert(ret); - (void)ret; - os_printf("%p:ref.extern", extern_obj); - } +#if UINTPTR_MAX == UINT32_MAX + if (argv1[k] != 0 && argv1[k] != (uint32)-1) + os_printf("%p:ref.extern", (void *)argv1[k]); else os_printf("extern:ref.null"); k++; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + u.parts[0] = argv1[k]; + u.parts[1] = argv1[k + 1]; + k += 2; + if (u.val && u.val != (uintptr_t)-1LL) + os_printf("%p:ref.extern", (void *)u.val); + else + os_printf("extern:ref.null"); +#endif break; } #endif diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 9bffeb6620..fb799de19d 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -1235,9 +1235,8 @@ wasm_exporttype_type(const wasm_exporttype_t *export_type) void wasm_val_delete(wasm_val_t *v) { - if (v) { + if (v) wasm_runtime_free(v); - } } void @@ -1562,19 +1561,13 @@ wasm_trap_new_internal(WASMModuleInstanceCommon *inst_comm_rt, #if WASM_ENABLE_INTERP != 0 if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { - if (!(error_info = - wasm_get_exception((WASMModuleInstance *)inst_comm_rt))) { - return NULL; - } + error_info = wasm_get_exception((WASMModuleInstance *)inst_comm_rt); } #endif #if WASM_ENABLE_AOT != 0 if (inst_comm_rt->module_type == Wasm_Module_AoT) { - if (!(error_info = - aot_get_exception((AOTModuleInstance *)inst_comm_rt))) { - return NULL; - } + error_info = aot_get_exception((AOTModuleInstance *)inst_comm_rt); } #endif @@ -2160,7 +2153,7 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) - import_memory_count); module_name_rt = import->module_name; field_name_rt = import->table_name; - elem_type_rt = VALUE_TYPE_FUNCREF; + elem_type_rt = import->elem_type; min_size = import->table_init_size; max_size = import->table_max_size; } @@ -2563,151 +2556,127 @@ wasm_func_type(const wasm_func_t *func) return wasm_functype_copy(func->type); } -static uint32 -params_to_argv(WASMModuleInstanceCommon *inst_comm_rt, const wasm_val_t *params, - const wasm_valtype_vec_t *param_defs, size_t param_arity, - uint32 *out) +static bool +params_to_argv(const wasm_val_vec_t *params, + const wasm_valtype_vec_t *param_defs, uint32 *argv, + uint32 *ptr_argc) { size_t i = 0; - uint32 argc = 0; - const wasm_val_t *param = NULL; - if (!param_arity) { - return 0; + if (!param_defs->num_elems) { + return true; } - bh_assert(params && param_defs && out); - bh_assert(param_defs->num_elems == param_arity); + if (!params || !params->num_elems || !params->size || !params->data) { + return false; + } - for (i = 0; out && i < param_arity; ++i) { - param = params + i; + *ptr_argc = 0; + for (i = 0; i < param_defs->num_elems; ++i) { + const wasm_val_t *param = params->data + i; bh_assert((*(param_defs->data + i))->kind == param->kind); switch (param->kind) { case WASM_I32: - *(int32 *)out = param->of.i32; - out += 1; - argc += 1; + *(int32 *)argv = param->of.i32; + argv += 1; + *ptr_argc += 1; break; case WASM_I64: - *(int64 *)out = param->of.i64; - out += 2; - argc += 2; + *(int64 *)argv = param->of.i64; + argv += 2; + *ptr_argc += 2; break; case WASM_F32: - *(float32 *)out = param->of.f32; - out += 1; - argc += 1; + *(float32 *)argv = param->of.f32; + argv += 1; + *ptr_argc += 1; break; case WASM_F64: - *(float64 *)out = param->of.f64; - out += 2; - argc += 2; + *(float64 *)argv = param->of.f64; + argv += 2; + *ptr_argc += 2; break; #if WASM_ENABLE_REF_TYPES != 0 case WASM_ANYREF: - if (!wasm_externref_obj2ref(inst_comm_rt, param->of.ref, out)) { - goto failed; - } - - out += 1; - argc += 1; + *(uintptr_t *)argv = (uintptr_t)param->of.ref; + argv += sizeof(uintptr_t) / sizeof(uint32); + *ptr_argc += 1; break; #endif default: LOG_WARNING("unexpected parameter val type %d", param->kind); - goto failed; + return false; } } - return argc; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return 0; + return true; } -static uint32 -argv_to_results(const uint32 *results, const wasm_valtype_vec_t *result_defs, - size_t result_arity, wasm_val_t *out) +static bool +argv_to_results(const uint32 *argv, const wasm_valtype_vec_t *result_defs, + wasm_val_vec_t *results) { - size_t i = 0; - uint32 argc = 0; - const uint32 *result = results; - const wasm_valtype_t *def = NULL; + size_t i = 0, argv_i = 0; + wasm_val_t *result; - if (!result_arity) { - return 0; + if (!result_defs->num_elems) { + return true; } - bh_assert(results && result_defs && out); - bh_assert(result_arity == result_defs->num_elems); - - for (i = 0; out && i < result_arity; i++) { - def = *(result_defs->data + i); + if (!results || !results->num_elems || !results->size || !results->data) { + return false; + } - switch (def->kind) { + for (i = 0, result = results->data, argv_i = 0; i < result_defs->num_elems; + i++, result++) { + switch (result_defs->data[i]->kind) { case WASM_I32: { - out->kind = WASM_I32; - out->of.i32 = *(int32 *)result; - result += 1; + result->kind = WASM_I32; + result->of.i32 = *(int32 *)(argv + argv_i); + argv_i += 1; break; } case WASM_I64: { - out->kind = WASM_I64; - out->of.i64 = *(int64 *)result; - result += 2; + result->kind = WASM_I64; + result->of.i64 = *(int64 *)(argv + argv_i); + argv_i += 2; break; } case WASM_F32: { - out->kind = WASM_F32; - out->of.f32 = *(float32 *)result; - result += 1; + result->kind = WASM_F32; + result->of.f32 = *(float32 *)(argv + argv_i); + argv_i += 1; break; } case WASM_F64: { - out->kind = WASM_F64; - out->of.f64 = *(float64 *)result; - result += 2; + result->kind = WASM_F64; + result->of.f64 = *(float64 *)(argv + argv_i); + argv_i += 2; break; } #if WASM_ENABLE_REF_TYPES != 0 case WASM_ANYREF: { - out->kind = WASM_ANYREF; - - if (NULL_REF == *(uint32 *)result) { - out->of.ref = NULL; - } - else { - if (!wasm_externref_ref2obj(*(uint32 *)result, - (void **)&out->of.ref)) { - goto failed; - } - } - - result += 1; + result->kind = WASM_ANYREF; + result->of.ref = + (struct wasm_ref_t *)(*(uintptr_t *)(argv + argv_i)); + argv_i += sizeof(uintptr_t) / sizeof(uint32); break; } #endif default: LOG_WARNING("%s meets unsupported type: %d", __FUNCTION__, - def->kind); - goto failed; + result_defs->data[i]->kind); + return false; } - out++; - argc++; } - return argc; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return 0; + return true; } wasm_trap_t * @@ -2718,7 +2687,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, /* a int64 or float64 parameter means 2 */ uint32 argc = 0; /* a parameter list and a return value list */ - uint32 argv_buf[32], *argv = argv_buf; + uint32 argv_buf[32] = { 0 }, *argv = argv_buf; WASMFunctionInstanceCommon *func_comm_rt = NULL; WASMExecEnv *exec_env = NULL; size_t param_count, result_count, alloc_count; @@ -2776,10 +2745,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, /* copy parametes */ if (param_count - && (!params - || !(argc = params_to_argv(func->inst_comm_rt, params->data, - wasm_functype_params(func->type), - param_count, argv)))) { + && !params_to_argv(params, wasm_functype_params(func->type), argv, + &argc)) { goto failed; } @@ -2798,9 +2765,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, /* copy results */ if (result_count) { - if (!results - || !(argc = argv_to_results(argv, wasm_functype_results(func->type), - result_count, results->data))) { + if (!argv_to_results(argv, wasm_functype_results(func->type), + results)) { goto failed; } results->num_elems = result_count; @@ -3265,7 +3231,7 @@ wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, if (table_idx_rt < module_aot->import_table_count) { AOTImportTable *table_aot = module_aot->import_tables + table_idx_rt; - val_type_rt = VALUE_TYPE_FUNCREF; + val_type_rt = table_aot->elem_type; init_size = table_aot->table_init_size; max_size = table_aot->table_max_size; } @@ -3273,7 +3239,7 @@ wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, AOTTable *table_aot = module_aot->tables + (table_idx_rt - module_aot->import_table_count); - val_type_rt = VALUE_TYPE_FUNCREF; + val_type_rt = table_aot->elem_type; init_size = table_aot->table_init_size; max_size = table_aot->table_max_size; } @@ -3360,13 +3326,12 @@ wasm_table_type(const wasm_table_t *table) own wasm_ref_t * wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) { - uint32 func_idx_rt = NULL_REF; + uint32 ref_idx = NULL_REF; if (!table) { return NULL; } - /* index -> func_idx_rt */ #if WASM_ENABLE_INTERP != 0 if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMTableInstance *table_interp = @@ -3375,7 +3340,7 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) if (index >= table_interp->cur_size) { return NULL; } - func_idx_rt = ((uint32 *)table_interp->base_addr)[index]; + ref_idx = ((uint32 *)table_interp->base_addr)[index]; } #endif @@ -3387,7 +3352,7 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) if (index >= table_aot->cur_size) { return NULL; } - func_idx_rt = table_aot->data[index]; + ref_idx = table_aot->data[index]; } #endif @@ -3395,35 +3360,48 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) * a wrong combination of module filetype and compilation flags * also leads to below branch */ - if (func_idx_rt == NULL_REF) { + if (ref_idx == NULL_REF) { return NULL; } - return wasm_ref_new_internal(table->store, WASM_REF_func, func_idx_rt, - table->inst_comm_rt); +#if WASM_ENABLE_REF_TYPES != 0 + if (table->type->val_type->kind == WASM_ANYREF) { + void *externref_obj; + if (!wasm_externref_ref2obj(ref_idx, &externref_obj)) { + return NULL; + } + + return externref_obj; + } + else +#endif + { + return wasm_ref_new_internal(table->store, WASM_REF_func, ref_idx, + table->inst_comm_rt); + } } bool wasm_table_set(wasm_table_t *table, wasm_table_size_t index, - own wasm_ref_t *func_ref) + own wasm_ref_t *ref) { - uint32 *p_func_idx_rt = NULL; - uint32 function_count = 0, ref_idx_rt = NULL_REF; + uint32 *p_ref_idx = NULL; + uint32 function_count = 0; if (!table) { return false; } - if (func_ref && func_ref->kind != WASM_REF_func) { + if (ref +#if WASM_ENABLE_REF_TYPES != 0 + && !(WASM_REF_foreign == ref->kind + && WASM_ANYREF == table->type->val_type->kind) +#endif + && !(WASM_REF_func == ref->kind + && WASM_FUNCREF == table->type->val_type->kind)) { return false; } - if (func_ref) { - ref_idx_rt = func_ref->ref_idx_rt; - wasm_ref_delete(func_ref); - } - - /* index -> *p_func_idx_rt */ #if WASM_ENABLE_INTERP != 0 if (table->inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMTableInstance *table_interp = @@ -3434,7 +3412,7 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, return false; } - p_func_idx_rt = ((uint32 *)table_interp->base_addr) + index; + p_ref_idx = ((uint32 *)table_interp->base_addr) + index; function_count = ((WASMModuleInstance *)table->inst_comm_rt)->function_count; } @@ -3451,7 +3429,7 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, return false; } - p_func_idx_rt = table_aot->data + index; + p_ref_idx = table_aot->data + index; function_count = module_aot->func_count; } #endif @@ -3460,17 +3438,31 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, * a wrong combination of module filetype and compilation flags * leads to below branch */ - if (!p_func_idx_rt) { + if (!p_ref_idx) { return false; } - if (NULL_REF != ref_idx_rt) { - if (ref_idx_rt >= function_count) { - return false; +#if WASM_ENABLE_REF_TYPES != 0 + if (table->type->val_type->kind == WASM_ANYREF) { + return wasm_externref_obj2ref(table->inst_comm_rt, ref, p_ref_idx); + } + else +#endif + { + if (ref) { + if (NULL_REF != ref->ref_idx_rt) { + if (ref->ref_idx_rt >= function_count) { + return false; + } + } + *p_ref_idx = ref->ref_idx_rt; + wasm_ref_delete(ref); + } + else { + *p_ref_idx = NULL_REF; } } - *p_func_idx_rt = ref_idx_rt; return true; } diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h index 919d1524fc..d80bd0d680 100644 --- a/core/iwasm/common/wasm_c_api_internal.h +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -56,7 +56,6 @@ struct wasm_globaltype_t { struct wasm_tabletype_t { uint32 extern_kind; - /* always be WASM_FUNCREF */ wasm_valtype_t *val_type; wasm_limits_t limits; }; diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index ea2fafd680..b3e2a0524f 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -98,6 +98,8 @@ typedef struct WASMExecEnv { /* used to support debugger */ korp_mutex wait_lock; korp_cond wait_cond; + /* the count of threads which are joining current thread */ + uint32 wait_count; #endif #if WASM_ENABLE_DEBUG_INTERP != 0 @@ -123,10 +125,6 @@ typedef struct WASMExecEnv { WASMJmpBuf *jmpbuf_stack_top; #endif -#if WASM_ENABLE_REF_TYPES != 0 - uint16 nested_calling_depth; -#endif - #if WASM_ENABLE_MEMORY_PROFILING != 0 uint32 max_wasm_stack_used; #endif diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 15cb0e5c61..bbef1def46 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -53,11 +53,30 @@ get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis); uint32 get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis); +static bool +compare_type_with_signautre(uint8 type, const char signature) +{ + const char num_sig_map[] = { 'F', 'f', 'I', 'i' }; + + if (VALUE_TYPE_F64 <= type && type <= VALUE_TYPE_I32 + && signature == num_sig_map[type - VALUE_TYPE_F64]) { + return true; + } + +#if WASM_ENABLE_REF_TYPES != 0 + if ('r' == signature && type == VALUE_TYPE_EXTERNREF) + return true; +#endif + + /* TODO: a v128 parameter */ + return false; +} + static bool check_symbol_signature(const WASMType *type, const char *signature) { const char *p = signature, *p_end; - char sig_map[] = { 'F', 'f', 'I', 'i' }, sig; + char sig; uint32 i = 0; if (!p || strlen(p) < 2) @@ -74,16 +93,12 @@ check_symbol_signature(const WASMType *type, const char *signature) for (i = 0; i < type->param_count; i++) { sig = *p++; - if ((type->types[i] >= VALUE_TYPE_F64 - && type->types[i] <= VALUE_TYPE_I32 - && sig == sig_map[type->types[i] - VALUE_TYPE_F64]) -#if WASM_ENABLE_REF_TYPES != 0 - || (sig == 'i' && type->types[i] == VALUE_TYPE_EXTERNREF) -#endif - ) - /* normal parameter */ + + /* a f64/f32/i64/i32/externref parameter */ + if (compare_type_with_signautre(type->types[i], sig)) continue; + /* a pointer/string paramter */ if (type->types[i] != VALUE_TYPE_I32) /* pointer and string must be i32 type */ return false; @@ -112,8 +127,12 @@ check_symbol_signature(const WASMType *type, const char *signature) if (type->result_count) { if (p >= p_end) return false; - if (*p++ != sig_map[type->types[i] - VALUE_TYPE_F64]) + + /* result types includes: f64,f32,i64,i32,externref */ + if (!compare_type_with_signautre(type->types[i], *p)) return false; + + p++; } if (*p != '\0') diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index af2f59300f..79668cc1e9 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -305,10 +305,11 @@ align_ptr(const uint8 *p, uint32 b) return (uint8 *)((v + m) & ~m); } -#define CHECK_BUF(buf, buf_end, length) \ - do { \ - if (buf + length < buf || buf + length > buf_end) \ - return false; \ +#define CHECK_BUF(buf, buf_end, length) \ + do { \ + if ((uintptr_t)buf + length < (uintptr_t)buf \ + || (uintptr_t)buf + length > (uintptr_t)buf_end) \ + return false; \ } while (0) #define read_uint16(p, p_end, res) \ @@ -347,9 +348,7 @@ wasm_runtime_is_xip_file(const uint8 *buf, uint32 size) if (section_type == AOT_SECTION_TYPE_TARGET_INFO) { p += 4; read_uint16(p, p_end, e_type); - if (e_type == E_TYPE_XIP) { - return true; - } + return (e_type == E_TYPE_XIP) ? true : false; } else if (section_type >= AOT_SECTION_TYPE_SIGANATURE) { return false; @@ -1200,46 +1199,163 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst, } #if WASM_ENABLE_REF_TYPES != 0 -static void -wasm_runtime_reclaim_externref(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function, - uint32 *argv) -{ - uint32 i = 0, cell_num = 0; +/* (uintptr_t)externref -> (uint32_t)index */ +/* argv -> *ret_argv */ +static bool +wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, + WASMFunctionInstanceCommon *function, + uint32 *argv, uint32 argc, uint32 **ret_argv, + uint32 *ret_argc_param, + uint32 *ret_argc_result) +{ + uint32 *new_argv = NULL, argv_i = 0, new_argv_i = 0, param_i = 0, + result_i = 0; + bool need_param_transform = false, need_result_transform = false; + uint64 size = 0; WASMType *func_type = wasm_runtime_get_function_type( function, exec_env->module_inst->module_type); + bh_assert(func_type); - while (i < func_type->result_count) { - uint8 result_type = func_type->types[func_type->param_count + i]; - if (result_type == VALUE_TYPE_EXTERNREF && argv[i] != NULL_REF) { - /* Retain the externref returned to runtime embedder */ - (void)wasm_externref_retain(argv[i]); + *ret_argc_param = func_type->param_cell_num; + *ret_argc_result = func_type->ret_cell_num; + for (param_i = 0; param_i < func_type->param_count; param_i++) { + if (VALUE_TYPE_EXTERNREF == func_type->types[param_i]) { + need_param_transform = true; } + } - cell_num += wasm_value_type_cell_num(result_type); - i++; + for (result_i = 0; result_i < func_type->result_count; result_i++) { + if (VALUE_TYPE_EXTERNREF + == func_type->types[func_type->param_count + result_i]) { + need_result_transform = true; + } } - wasm_externref_reclaim(exec_env->module_inst); -} + if (!need_param_transform && !need_result_transform) { + *ret_argv = argv; + return true; + } -void -wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function) -{ - exec_env->nested_calling_depth++; + if (func_type->param_cell_num >= func_type->ret_cell_num) { + size = sizeof(uint32) * func_type->param_cell_num; + } + else { + size = sizeof(uint32) * func_type->ret_cell_num; + } + + if (!(new_argv = runtime_malloc(size, exec_env->module_inst, NULL, 0))) { + return false; + } + + if (!need_param_transform) { + bh_memcpy_s(new_argv, size, argv, size); + } + else { + for (param_i = 0; param_i < func_type->param_count && argv_i < argc + && new_argv_i < func_type->param_cell_num; + param_i++) { + uint8 param_type = func_type->types[param_i]; + if (VALUE_TYPE_EXTERNREF == param_type) { + void *externref_obj; + uint32 externref_index; + +#if UINTPTR_MAX == UINT32_MAX + externref_obj = (void *)argv[argv_i]; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + + u.parts[0] = argv[argv_i]; + u.parts[1] = argv[argv_i + 1]; + externref_obj = (void *)u.val; +#endif + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_index)) { + wasm_runtime_free(new_argv); + return false; + } + + new_argv[new_argv_i] = externref_index; + argv_i += sizeof(uintptr_t) / sizeof(uint32); + new_argv_i++; + } + else { + uint16 param_cell_num = wasm_value_type_cell_num(param_type); + uint32 param_size = sizeof(uint32) * param_cell_num; + bh_memcpy_s(new_argv + new_argv_i, param_size, argv + argv_i, + param_size); + argv_i += param_cell_num; + new_argv_i += param_cell_num; + } + } + } + + *ret_argv = new_argv; + return true; } -void +/* (uintptr_t)externref <- (uint32_t)index */ +/* argv <- new_argv */ +static bool wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, - bool ret, uint32 *argv) + uint32 *argv, uint32 argc, uint32 *ret_argv) { - exec_env->nested_calling_depth--; - if (!exec_env->nested_calling_depth && ret) { - wasm_runtime_reclaim_externref(exec_env, function, argv); + uint32 argv_i = 0, result_i = 0, ret_argv_i = 0; + WASMType *func_type; + + bh_assert(argv && ret_argv); + + if (argv == ret_argv) { + return true; } + + func_type = wasm_runtime_get_function_type( + function, exec_env->module_inst->module_type); + bh_assert(func_type); + + for (result_i = 0; result_i < func_type->result_count && argv_i < argc; + result_i++) { + uint8 result_type = func_type->types[func_type->param_count + result_i]; + if (result_type == VALUE_TYPE_EXTERNREF) { + void *externref_obj; +#if UINTPTR_MAX != UINT32_MAX + union { + uintptr_t val; + uint32 parts[2]; + } u; +#endif + + if (!wasm_externref_ref2obj(argv[argv_i], &externref_obj)) { + wasm_runtime_free(argv); + return false; + } + +#if UINTPTR_MAX == UINT32_MAX + ret_argv[ret_argv_i] = (uintptr_t)externref_obj; +#else + u.val = (uintptr_t)externref_obj; + ret_argv[ret_argv_i] = u.parts[0]; + ret_argv[ret_argv_i + 1] = u.parts[1]; +#endif + argv_i += 1; + ret_argv_i += sizeof(uintptr_t) / sizeof(uint32); + } + else { + uint16 result_cell_num = wasm_value_type_cell_num(result_type); + uint32 result_size = sizeof(uint32) * result_cell_num; + bh_memcpy_s(ret_argv + ret_argv_i, result_size, argv + argv_i, + result_size); + argv_i += result_cell_num; + ret_argv_i += result_cell_num; + } + } + + wasm_runtime_free(argv); + return true; } #endif @@ -1249,6 +1365,10 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, uint32 argv[]) { bool ret = false; + uint32 *new_argv = NULL, param_argc; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 result_argc = 0; +#endif if (!wasm_runtime_exec_env_check(exec_env)) { LOG_ERROR("Invalid exec env stack info."); @@ -1256,34 +1376,53 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, } #if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_prepare_call_function(exec_env, function); + if (!wasm_runtime_prepare_call_function(exec_env, function, argv, argc, + &new_argv, ¶m_argc, + &result_argc)) { + wasm_runtime_set_exception(exec_env->module_inst, + "the arguments conversion is failed"); + return false; + } +#else + new_argv = argv; + param_argc = argc; #endif #if WASM_ENABLE_INTERP != 0 if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) ret = wasm_call_function(exec_env, (WASMFunctionInstance *)function, - argc, argv); + param_argc, new_argv); #endif #if WASM_ENABLE_AOT != 0 if (exec_env->module_inst->module_type == Wasm_Module_AoT) - ret = aot_call_function(exec_env, (AOTFunctionInstance *)function, argc, - argv); + ret = aot_call_function(exec_env, (AOTFunctionInstance *)function, + param_argc, new_argv); #endif + if (!ret) { + if (new_argv != argv) { + wasm_runtime_free(new_argv); + } + return false; + } #if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_finalize_call_function(exec_env, function, ret, argv); + if (!wasm_runtime_finalize_call_function(exec_env, function, new_argv, + result_argc, argv)) { + wasm_runtime_set_exception(exec_env->module_inst, + "the result conversion is failed"); + return false; + } #endif return ret; } -static uint32 -parse_args_to_uint32_array(WASMType *type, uint32 num_args, wasm_val_t *args, - uint32 *out_argv) +static void +parse_args_to_uint32_array(WASMType *type, wasm_val_t *args, uint32 *out_argv) { uint32 i, p; - for (i = 0, p = 0; i < num_args; i++) { + for (i = 0, p = 0; i < type->param_count; i++) { switch (args[i].kind) { case WASM_I32: out_argv[p++] = args[i].of.i32; @@ -1320,16 +1459,38 @@ parse_args_to_uint32_array(WASMType *type, uint32 num_args, wasm_val_t *args, out_argv[p++] = u.parts[1]; break; } +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_FUNCREF: + { + out_argv[p++] = args[i].of.i32; + break; + } + case WASM_ANYREF: + { +#if UINTPTR_MAX == UINT32_MAX + out_argv[p++] = args[i].of.foreign; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + + u.val = (uintptr_t)args[i].of.foreign; + out_argv[p++] = u.parts[0]; + out_argv[p++] = u.parts[1]; +#endif + break; + } +#endif default: bh_assert(0); break; } } - return p; } -static uint32 -parse_uint32_array_to_results(WASMType *type, uint32 argc, uint32 *argv, +static void +parse_uint32_array_to_results(WASMType *type, uint32 *argv, wasm_val_t *out_results) { uint32 i, p; @@ -1375,13 +1536,36 @@ parse_uint32_array_to_results(WASMType *type, uint32 argc, uint32 *argv, out_results[i].of.f64 = u.val; break; } +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + out_results[i].kind = WASM_I32; + out_results[i].of.i32 = (int32)argv[p++]; + break; + } + case VALUE_TYPE_EXTERNREF: + { +#if UINTPTR_MAX == UINT32_MAX + out_results[i].kind = WASM_ANYREF; + out_results[i].of.foreign = (uintptr_t)argv[p++]; +#else + union { + uintptr_t val; + uint32 parts[2]; + } u; + u.parts[0] = argv[p++]; + u.parts[1] = argv[p++]; + out_results[i].kind = WASM_ANYREF; + out_results[i].of.foreign = u.val; +#endif + break; + } +#endif default: bh_assert(0); break; } } - bh_assert(argc == p); - return type->result_count; } bool @@ -1390,7 +1574,10 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, uint32 num_results, wasm_val_t results[], uint32 num_args, wasm_val_t args[]) { - uint32 argc, *argv, ret_num, cell_num, total_size, module_type; + uint32 argc, *argv, cell_num, total_size, module_type; +#if WASM_ENABLE_REF_TYPES != 0 + uint32 i, param_size_in_double_world = 0, result_size_in_double_world = 0; +#endif WASMType *type; bool ret = false; @@ -1403,8 +1590,23 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, goto fail1; } +#if WASM_ENABLE_REF_TYPES != 0 + for (i = 0; i < type->param_count; i++) { + param_size_in_double_world += + wasm_value_type_cell_num_outside(type->types[i]); + } + for (i = 0; i < type->result_count; i++) { + result_size_in_double_world += wasm_value_type_cell_num_outside( + type->types[type->param_count + i]); + } + argc = param_size_in_double_world; + cell_num = (argc >= result_size_in_double_world) + ? argc + : result_size_in_double_world; +#else argc = type->param_cell_num; cell_num = (argc > type->ret_cell_num) ? argc : type->ret_cell_num; +#endif if (num_results != type->result_count) { LOG_ERROR( @@ -1426,14 +1628,11 @@ wasm_runtime_call_wasm_a(WASMExecEnv *exec_env, goto fail1; } - argc = parse_args_to_uint32_array(type, num_args, args, argv); - if (!(ret = wasm_runtime_call_wasm(exec_env, function, argc, argv))) + parse_args_to_uint32_array(type, args, argv); + if (!(ret = wasm_runtime_call_wasm(exec_env, function, num_args, argv))) goto fail2; - ret_num = - parse_uint32_array_to_results(type, type->ret_cell_num, argv, results); - bh_assert(ret_num == num_results); - (void)ret_num; + parse_uint32_array_to_results(type, argv, results); fail2: wasm_runtime_free(argv); @@ -1493,6 +1692,20 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, args[i].kind = WASM_F64; args[i].of.f64 = va_arg(vargs, float64); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + { + args[i].kind = WASM_FUNCREF; + args[i].of.i32 = va_arg(vargs, uint32); + break; + } + case VALUE_TYPE_EXTERNREF: + { + args[i].kind = WASM_ANYREF; + args[i].of.foreign = va_arg(vargs, uintptr_t); + break; + } +#endif default: bh_assert(0); break; @@ -1548,13 +1761,21 @@ WASMExecEnv * wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst) { #if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) + if (module_inst->module_type == Wasm_Module_Bytecode) { + if (!((WASMModuleInstance *)module_inst)->exec_env_singleton) { + wasm_create_exec_env_singleton((WASMModuleInstance *)module_inst); + } return ((WASMModuleInstance *)module_inst)->exec_env_singleton; + } #endif #if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) + if (module_inst->module_type == Wasm_Module_AoT) { + if (!((AOTModuleInstance *)module_inst)->exec_env_singleton.ptr) { + aot_create_exec_env_singleton((AOTModuleInstance *)module_inst); + } return (WASMExecEnv *)((AOTModuleInstance *)module_inst) ->exec_env_singleton.ptr; + } #endif return NULL; } @@ -2498,6 +2719,9 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++, argv_dst++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif { *(uint32 *)argv_dst = arg_i32 = *argv_src++; if (signature) { @@ -2541,10 +2765,19 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, *(float32 *)argv_dst = *(float32 *)argv_src++; break; #if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: case VALUE_TYPE_EXTERNREF: - *(uint32 *)argv_dst = *argv_src++; + { + uint32 externref_idx = *argv_src++; + + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + bh_memcpy_s(argv_dst, sizeof(uintptr_t), argv_src, + sizeof(uintptr_t)); break; + } #endif default: bh_assert(0); @@ -2561,7 +2794,6 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: #endif argv_ret[0] = *(uint32 *)argv1; break; @@ -2573,6 +2805,23 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, bh_memcpy_s(argv_ret, sizeof(uint32) * 2, argv1, sizeof(uint64)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx; + uint64 externref_obj; + + bh_memcpy_s(&externref_obj, sizeof(uint64), argv1, + sizeof(uint64)); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + (void *)(uintptr_t)externref_obj, + &externref_idx)) + goto fail; + argv_ret[0] = externref_idx; + break; + } +#endif default: bh_assert(0); break; @@ -2635,6 +2884,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 result_count = func_type->result_count; uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif #if !defined(BUILD_TARGET_RISCV32_ILP32) && !defined(BUILD_TARGET_ARC) uint32 *fps; int n_fps = 0; @@ -2793,6 +3045,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif { arg_i32 = *argv_src++; @@ -2830,17 +3085,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, stacks[n_stacks++] = arg_i32; break; } -#if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: - { - if (n_ints < MAX_REG_INTS) - ints[n_ints++] = *argv_src++; - else - stacks[n_stacks++] = *argv_src++; - break; - } -#endif case VALUE_TYPE_I64: { if (n_ints < MAX_REG_INTS - 1) { @@ -2960,6 +3204,31 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; } #endif /* BUILD_TARGET_RISCV32_ILP32D */ +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + uint32 externref_idx = *argv_src++; + + if (is_aot_func) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = externref_idx; + else + stacks[n_stacks++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = (uintptr_t)externref_obj; + else + stacks[n_stacks++] = (uintptr_t)externref_obj; + } + break; + } +#endif default: bh_assert(0); break; @@ -2983,7 +3252,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: #endif argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks); @@ -3000,6 +3268,30 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, PUT_F64_TO_ADDR( argv_ret, invokeNative_Float64(func_ptr, argv1, n_stacks)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + uint32 externref_idx = + (uint32)invokeNative_Int32(func_ptr, argv1, argc1); + argv_ret[0] = externref_idx; + } + else { + uint32 externref_idx; + void *externref_obj; + + externref_obj = (void *)(uintptr_t)invokeNative_Int32( + func_ptr, argv1, argc1); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + + argv_ret[0] = externref_idx; + } + break; + } +#endif default: bh_assert(0); break; @@ -3061,6 +3353,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; uint64 size; bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif #if defined(BUILD_TARGET_X86_32) argc1 = argc + ext_ret_count + 2; @@ -3084,6 +3379,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif { arg_i32 = *argv++; @@ -3130,12 +3428,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, argv1[j++] = *argv++; break; case VALUE_TYPE_F32: + argv1[j++] = *argv++; + break; #if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: case VALUE_TYPE_EXTERNREF: -#endif - argv1[j++] = *argv++; + { + uint32 externref_idx = *argv++; + if (is_aot_func) { + argv1[j++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + argv1[j++] = (uintptr_t)externref_obj; + } break; + } +#endif default: bh_assert(0); break; @@ -3155,7 +3467,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: #endif argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, argc1); @@ -3172,6 +3483,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, PUT_F64_TO_ADDR(argv_ret, invokeNative_Float64(func_ptr, argv1, argc1)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + uint32 externref_idx = + (uint32)invokeNative_Int32(func_ptr, argv1, argc1); + argv_ret[0] = externref_idx; + } + else { + void *externref_obj = (void *)(uintptr_t)invokeNative_Int32( + func_ptr, argv1, argc1); + uint32 externref_idx; + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + argv_ret[0] = externref_idx; + } + break; + } +#endif default: bh_assert(0); break; @@ -3227,8 +3558,19 @@ typedef uint32x4_t __m128i; #endif /* end of WASM_ENABLE_SIMD != 0 */ typedef void (*GenericFunctionPointer)(); +#if defined(__APPLE__) || defined(__MACH__) +/** + * Define the return type as 'void' in MacOS, since after converting + * 'int64 invokeNative' into 'float64 invokeNative_Float64', the + * return value passing might be invalid, the caller reads the return + * value from register rax but not xmm0. + */ +void +invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks); +#else int64 invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks); +#endif typedef float64 (*Float64FuncPtr)(GenericFunctionPointer, uint64 *, uint64); typedef float32 (*Float32FuncPtr)(GenericFunctionPointer, uint64 *, uint64); @@ -3271,12 +3613,16 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 *argv_ret) { WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); - uint64 argv_buf[32], *argv1 = argv_buf, *ints, *stacks, size, arg_i64; + uint64 argv_buf[32] = { 0 }, *argv1 = argv_buf, *ints, *stacks, size, + arg_i64; uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; uint32 arg_i32, ptr_len; uint32 result_count = func_type->result_count; uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; bool ret = false; +#if WASM_ENABLE_REF_TYPES != 0 + bool is_aot_func = (NULL == signature); +#endif #ifndef BUILD_TARGET_RISCV64_LP64 #if WASM_ENABLE_SIMD == 0 uint64 *fps; @@ -3326,6 +3672,9 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, for (i = 0; i < func_type->param_count; i++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: +#endif { arg_i32 = *argv_src++; arg_i64 = arg_i32; @@ -3387,13 +3736,28 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, argv_src += 2; break; #if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_FUNCREF: case VALUE_TYPE_EXTERNREF: - if (n_ints < MAX_REG_INTS) - ints[n_ints++] = *argv_src++; - else - stacks[n_stacks++] = *argv_src++; + { + uint32 externref_idx = *argv_src++; + if (is_aot_func) { + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = externref_idx; + else + stacks[n_stacks++] = externref_idx; + } + else { + void *externref_obj; + + if (!wasm_externref_ref2obj(externref_idx, &externref_obj)) + goto fail; + + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = (uintptr_t)externref_obj; + else + stacks[n_stacks++] = (uintptr_t)externref_obj; + } break; + } #endif #if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: @@ -3432,7 +3796,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: #endif argv_ret[0] = (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks); @@ -3449,6 +3812,26 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, PUT_F64_TO_ADDR( argv_ret, invokeNative_Float64(func_ptr, argv1, n_stacks)); break; +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + { + if (is_aot_func) { + argv_ret[0] = invokeNative_Int32(func_ptr, argv1, n_stacks); + } + else { + uint32 externref_idx; + void *externref_obj = (void *)(uintptr_t)invokeNative_Int64( + func_ptr, argv1, n_stacks); + + if (!wasm_externref_obj2ref(exec_env->module_inst, + externref_obj, &externref_idx)) + goto fail; + + argv_ret[0] = externref_idx; + } + break; + } +#endif #if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: *(v128 *)argv_ret = @@ -3699,10 +4082,24 @@ bool wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj, uint32 *p_externref_idx) { - LookupExtObj_UserData lookup_user_data; + LookupExtObj_UserData lookup_user_data = { 0 }; ExternRefMapNode *node; uint32 externref_idx; + /* + * to catch a parameter from `wasm_application_execute_func`, + * which represents a string 'null' + */ +#if UINTPTR_MAX == UINT32_MAX + if ((uint32)-1 == (uintptr_t)extern_obj) { +#else + if ((uint64)-1LL == (uintptr_t)extern_obj) { +#endif + *p_externref_idx = NULL_REF; + return true; + } + + /* in a wrapper, extern_obj could be any value */ lookup_user_data.node.extern_obj = extern_obj; lookup_user_data.node.module_inst = module_inst; lookup_user_data.found = false; @@ -3754,8 +4151,10 @@ wasm_externref_ref2obj(uint32 externref_idx, void **p_extern_obj) { ExternRefMapNode *node; + /* catch a `ref.null` vairable */ if (externref_idx == NULL_REF) { - return false; + *p_extern_obj = NULL; + return true; } os_mutex_lock(&externref_lock); @@ -4160,14 +4559,9 @@ argv_to_params(wasm_val_t *out_params, const uint32 *argv, WASMType *func_type) case VALUE_TYPE_EXTERNREF: param->kind = WASM_ANYREF; - if (NULL_REF == *argv) { - param->of.ref = NULL; - } - else { - if (!wasm_externref_ref2obj(*argv, - (void **)¶m->of.ref)) { - return false; - } + if (!wasm_externref_ref2obj(*argv, + (void **)¶m->of.foreign)) { + return false; } argv++; @@ -4203,8 +4597,8 @@ results_to_argv(WASMModuleInstanceCommon *module_inst, uint32 *out_argv, break; #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_EXTERNREF: - if (!wasm_externref_obj2ref(module_inst, result->of.ref, - argv)) { + if (!wasm_externref_obj2ref(module_inst, + (void *)result->of.foreign, argv)) { return false; } argv++; @@ -4224,17 +4618,19 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, uint32 argc, uint32 *argv, bool with_env, void *wasm_c_api_env) { - wasm_val_t params_buf[16], results_buf[4]; + wasm_val_t params_buf[16] = { 0 }, results_buf[4] = { 0 }; wasm_val_t *params = params_buf, *results = results_buf; wasm_trap_t *trap = NULL; bool ret = false; wasm_val_vec_t params_vec, results_vec; - if (func_type->param_count > 16 - && !(params = wasm_runtime_malloc(sizeof(wasm_val_t) - * func_type->param_count))) { - wasm_runtime_set_exception(module_inst, "allocate memory failed"); - return false; + if (func_type->param_count > 16) { + if (!(params = + runtime_malloc(sizeof(wasm_val_t) * func_type->param_count, + module_inst, NULL, 0))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + return false; + } } if (!argv_to_params(params, argv, func_type)) { @@ -4242,11 +4638,13 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, goto fail; } - if (func_type->result_count > 4 - && !(results = wasm_runtime_malloc(sizeof(wasm_val_t) - * func_type->result_count))) { - wasm_runtime_set_exception(module_inst, "allocate memory failed"); - goto fail; + if (func_type->result_count > 4) { + if (!(results = + runtime_malloc(sizeof(wasm_val_t) * func_type->result_count, + module_inst, NULL, 0))) { + wasm_runtime_set_exception(module_inst, "allocate memory failed"); + goto fail; + } } params_vec.data = params; diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index c84463aa20..ce188c8d18 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -525,11 +525,6 @@ bool wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices, uint32 argc, uint32 argv[]); -bool -wasm_runtime_create_exec_env_and_call_wasm( - WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *function, - uint32 argc, uint32 argv[]); - bool wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst); @@ -813,16 +808,6 @@ wasm_runtime_dump_module_inst_mem_consumption( void wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env); -#if WASM_ENABLE_REF_TYPES != 0 -void -wasm_runtime_prepare_call_function(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function); -void -wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, - WASMFunctionInstanceCommon *function, - bool ret, uint32 *argv); -#endif - bool wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, const WASMExport *export_, WASMType **out); diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 3254eaf2cd..78dc78e203 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -96,6 +96,7 @@ typedef struct AOTMemInitData { typedef struct AOTImportTable { char *module_name; char *table_name; + uint32 elem_type; uint32 table_flags; uint32 table_init_size; uint32 table_max_size; diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index f36f526af9..e19cfaa185 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -1398,6 +1398,7 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, * EMIT_STR(comp_data->import_tables[i].module_name ); * EMIT_STR(comp_data->import_tables[i].table_name); */ + EMIT_U32(comp_data->import_tables[i].elem_type); EMIT_U32(comp_data->import_tables[i].table_init_size); EMIT_U32(comp_data->import_tables[i].table_max_size); EMIT_U32(comp_data->import_tables[i].possible_grow & 0x000000FF); diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index be7dea91c7..fe43d6bce3 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -560,6 +560,10 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } else { + bool recursive_call = + (func_ctx == func_ctxes[func_idx - import_func_count]) ? true + : false; + if (comp_ctx->is_indirect_mode) { LLVMTypeRef func_ptr_type; @@ -603,7 +607,8 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Check whether there was exception thrown when executing the function */ - if (!tail_call && !check_exception_thrown(comp_ctx, func_ctx)) + if (!tail_call && !recursive_call + && !check_exception_thrown(comp_ctx, func_ctx)) goto fail; } diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 8fd6e82920..33c7179a29 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -500,7 +500,7 @@ create_cur_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) offset = I32_CONST(offsetof(AOTModuleInstance, cur_exception)); func_ctx->cur_exception = LLVMBuildInBoundsGEP( - comp_ctx->builder, func_ctx->aot_inst, &offset, 1, "cur_execption"); + comp_ctx->builder, func_ctx->aot_inst, &offset, 1, "cur_exception"); if (!func_ctx->cur_exception) { aot_set_last_error("llvm build in bounds gep failed."); return false; @@ -1610,7 +1610,76 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) abi = "ilp32d"; } - if (arch) { +#if defined(__APPLE__) || defined(__MACH__) + if (!abi) { + /* On MacOS platform, set abi to "gnu" to avoid generating + object file of Mach-O binary format which is unsupported */ + abi = "gnu"; + if (!arch && !cpu && !features) { + /* Get CPU name of the host machine to avoid checking + SIMD capability failed */ + if (!(cpu = cpu_new = LLVMGetHostCPUName())) { + aot_set_last_error("llvm get host cpu name failed."); + goto fail; + } + } + } +#endif + + if (abi) { + /* Construct target triple: --- */ + const char *vendor_sys; + char *arch1 = arch, default_arch[32] = { 0 }; + + if (!arch1) { + char *default_triple = LLVMGetDefaultTargetTriple(); + + if (!default_triple) { + aot_set_last_error( + "llvm get default target triple failed."); + goto fail; + } + + vendor_sys = strstr(default_triple, "-"); + bh_assert(vendor_sys); + bh_memcpy_s(default_arch, sizeof(default_arch), default_triple, + (uint32)(vendor_sys - default_triple)); + arch1 = default_arch; + + LLVMDisposeMessage(default_triple); + } + + /** + * Set - according to abi to generate the object file + * with the correct file format which might be different from the + * default object file format of the host, e.g., generating AOT file + * for Windows/MacOS under Linux host, or generating AOT file for + * Linux/MacOS under Windows host. + */ + if (!strcmp(abi, "msvc")) { + if (!strcmp(arch1, "i386")) + vendor_sys = "-pc-win32-"; + else + vendor_sys = "-pc-windows-"; + } + else { + vendor_sys = "-pc-linux-"; + } + + bh_assert(strlen(arch1) + strlen(vendor_sys) + strlen(abi) + < sizeof(triple_buf)); + bh_memcpy_s(triple_buf, (uint32)sizeof(triple_buf), arch1, + (uint32)strlen(arch1)); + bh_memcpy_s(triple_buf + strlen(arch1), + (uint32)(sizeof(triple_buf) - strlen(arch1)), + vendor_sys, (uint32)strlen(vendor_sys)); + bh_memcpy_s(triple_buf + strlen(arch1) + strlen(vendor_sys), + (uint32)(sizeof(triple_buf) - strlen(arch1) + - strlen(vendor_sys)), + abi, (uint32)strlen(abi)); + triple = triple_buf; + } + else if (arch) { /* Construct target triple: --- */ const char *vendor_sys; char *default_triple = LLVMGetDefaultTargetTriple(); @@ -1640,10 +1709,15 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) bh_assert(strlen(arch) + strlen(vendor_sys) + strlen(abi) < sizeof(triple_buf)); - memcpy(triple_buf, arch, strlen(arch)); - memcpy(triple_buf + strlen(arch), vendor_sys, strlen(vendor_sys)); - memcpy(triple_buf + strlen(arch) + strlen(vendor_sys), abi, - strlen(abi)); + bh_memcpy_s(triple_buf, (uint32)sizeof(triple_buf), arch, + (uint32)strlen(arch)); + bh_memcpy_s(triple_buf + strlen(arch), + (uint32)(sizeof(triple_buf) - strlen(arch)), vendor_sys, + (uint32)strlen(vendor_sys)); + bh_memcpy_s(triple_buf + strlen(arch) + strlen(vendor_sys), + (uint32)(sizeof(triple_buf) - strlen(arch) + - strlen(vendor_sys)), + abi, (uint32)strlen(abi)); triple = triple_buf; } @@ -1803,6 +1877,8 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) aot_set_last_error("create LLVM target machine failed."); goto fail; } + + LLVMSetTarget(comp_ctx->module, triple_norm); } if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0 @@ -1861,6 +1937,11 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) LLVMAddIndVarSimplifyPass(comp_ctx->pass_mgr); if (!option->is_jit_mode) { + /* Put Vectorize passes before GVN/LICM passes as the former + might gain more performance improvement and the latter might + break the optimizations for the former */ + LLVMAddLoopVectorizePass(comp_ctx->pass_mgr); + LLVMAddSLPVectorizePass(comp_ctx->pass_mgr); LLVMAddLoopRotatePass(comp_ctx->pass_mgr); LLVMAddLoopUnswitchPass(comp_ctx->pass_mgr); LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); @@ -1870,11 +1951,9 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) disable them when building as multi-thread mode */ LLVMAddGVNPass(comp_ctx->pass_mgr); LLVMAddLICMPass(comp_ctx->pass_mgr); + LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); + LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); } - LLVMAddLoopVectorizePass(comp_ctx->pass_mgr); - LLVMAddSLPVectorizePass(comp_ctx->pass_mgr); - LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); - LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); } /* Create metadata for llvm float experimental constrained intrinsics */ diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 6b66953407..5a6d4e8dff 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -155,16 +155,17 @@ enum wasm_valkind_enum { #ifndef WASM_VAL_T_DEFINED #define WASM_VAL_T_DEFINED -struct wasm_ref_t; typedef struct wasm_val_t { wasm_valkind_t kind; union { + /* also represent a function index */ int32_t i32; int64_t i64; float f32; double f64; - struct wasm_ref_t *ref; + /* represent a foreign object, aka externref in .wat */ + uintptr_t foreign; } of; } wasm_val_t; #endif @@ -790,6 +791,7 @@ wasm_runtime_get_native_addr_range(wasm_module_inst_t module_inst, * 'I': the parameter is i64 type * 'f': the parameter is f32 type * 'F': the parameter is f64 type + * 'r': the parameter is externref type, it should be a uintptr_t in host * '*': the parameter is a pointer (i32 in WASM), and runtime will * auto check its boundary before calling the native function. * If it is followed by '~', the checked length of the pointer diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 6db1a70557..9160350bef 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -544,6 +544,19 @@ wasm_get_cell_num(const uint8 *types, uint32 type_count) return cell_num; } +#if WASM_ENABLE_REF_TYPES != 0 +inline static uint16 +wasm_value_type_cell_num_outside(uint8 value_type) +{ + if (VALUE_TYPE_EXTERNREF == value_type) { + return sizeof(uintptr_t) / sizeof(uint32); + } + else { + return wasm_value_type_cell_num(value_type); + } +} +#endif + inline static bool wasm_type_equal(const WASMType *type1, const WASMType *type2) { diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 419d6d4936..0bfa02fcc7 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -3389,6 +3389,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); + expect = (uint8)expect; os_mutex_lock(&memory->mem_lock); readv = (uint32)(*(uint8 *)maddr); if (readv == expect) @@ -3399,6 +3400,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); + expect = (uint16)expect; os_mutex_lock(&memory->mem_lock); readv = (uint32)LOAD_U16(maddr); if (readv == expect) @@ -3433,6 +3435,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); + expect = (uint8)expect; os_mutex_lock(&memory->mem_lock); readv = (uint64)(*(uint8 *)maddr); if (readv == expect) @@ -3443,6 +3446,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); + expect = (uint16)expect; os_mutex_lock(&memory->mem_lock); readv = (uint64)LOAD_U16(maddr); if (readv == expect) @@ -3453,6 +3457,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); + expect = (uint32)expect; os_mutex_lock(&memory->mem_lock); readv = (uint64)LOAD_U32(maddr); if (readv == expect) diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 9bb5702194..0b567137fc 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -3308,6 +3308,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); + expect = (uint8)expect; os_mutex_lock(&memory->mem_lock); readv = (uint32)(*(uint8 *)maddr); if (readv == expect) @@ -3318,6 +3319,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); + expect = (uint16)expect; os_mutex_lock(&memory->mem_lock); readv = (uint32)LOAD_U16(maddr); if (readv == expect) @@ -3352,6 +3354,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); CHECK_ATOMIC_MEMORY_ACCESS(1); + expect = (uint8)expect; os_mutex_lock(&memory->mem_lock); readv = (uint64)(*(uint8 *)maddr); if (readv == expect) @@ -3362,6 +3365,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); + expect = (uint16)expect; os_mutex_lock(&memory->mem_lock); readv = (uint64)LOAD_U16(maddr); if (readv == expect) @@ -3372,6 +3376,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); + expect = (uint32)expect; os_mutex_lock(&memory->mem_lock); readv = (uint64)LOAD_U32(maddr); if (readv == expect) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 83f28a711c..51327d6cc1 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -47,7 +47,8 @@ static bool check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length, char *error_buf, uint32 error_buf_size) { - if (buf + length < buf || buf + length > buf_end) { + if ((uintptr_t)buf + length < (uintptr_t)buf + || (uintptr_t)buf + length > (uintptr_t)buf_end) { set_error_buf(error_buf, error_buf_size, "unexpected end of section or function"); return false; @@ -59,7 +60,8 @@ static bool check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length, char *error_buf, uint32 error_buf_size) { - if (buf + length < buf || buf + length > buf_end) { + if ((uintptr_t)buf + length < (uintptr_t)buf + || (uintptr_t)buf + length > (uintptr_t)buf_end) { set_error_buf(error_buf, error_buf_size, "unexpected end"); return false; } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 2de827c802..0a5ba3dc63 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1748,16 +1748,8 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, } #endif -#if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_prepare_call_function(exec_env, func); -#endif - ret = wasm_call_function(exec_env, func, argc, argv); -#if WASM_ENABLE_REF_TYPES != 0 - wasm_runtime_finalize_call_function(exec_env, func, ret, argv); -#endif - #if WASM_ENABLE_THREAD_MGR != 0 /* don't destroy the exec_env if it's searched from the cluster */ if (!existing_exec_env) @@ -1770,9 +1762,14 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, bool wasm_create_exec_env_singleton(WASMModuleInstance *module_inst) { - WASMExecEnv *exec_env = - wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, - module_inst->default_wasm_stack_size); + WASMExecEnv *exec_env = NULL; + + if (module_inst->exec_env_singleton) { + return true; + } + + exec_env = wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size); if (exec_env) module_inst->exec_env_singleton = exec_env; diff --git a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake index 262bc610c1..28caad10d4 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 (UVWASI_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../deps/uvwasi) -set (LIBUV_VERSION v1.39.0) +set (LIBUV_VERSION v1.42.0) add_definitions (-DWASM_ENABLE_LIBC_WASI=1 -DWASM_ENABLE_UVWASI=1) @@ -21,6 +21,7 @@ if(NOT libuv_POPULATED) include_directories("${libuv_SOURCE_DIR}/include") add_subdirectory(${libuv_SOURCE_DIR} ${libuv_BINARY_DIR} EXCLUDE_FROM_ALL) set (UV_A_LIBS uv_a) + set_target_properties(uv_a PROPERTIES POSITION_INDEPENDENT_CODE 1) endif() include_directories(${UVWASI_DIR}/include) diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index 297d0c50c0..560fdeb009 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -441,47 +441,100 @@ _Static_assert(sizeof(void *) != 4 || _Static_assert(sizeof(void *) != 8 || _Alignof(__wasi_iovec_t) == 8, "non-wasi data layout"); +/** + * The contents of a `subscription` when type is `eventtype::clock`. + */ +typedef struct __wasi_subscription_clock_t { + /** + * The clock against which to compare the timestamp. + */ + __wasi_clockid_t clock_id; + + uint8_t __paddings1[4]; + + /** + * The absolute or relative timestamp. + */ + __wasi_timestamp_t timeout; + + /** + * The amount of time that the implementation may wait additionally + * to coalesce with other events. + */ + __wasi_timestamp_t precision; + + /** + * Flags specifying whether the timeout is absolute or relative + */ + __wasi_subclockflags_t flags; + + uint8_t __paddings2[4]; + +} __wasi_subscription_clock_t __attribute__((aligned(8))); + +_Static_assert(sizeof(__wasi_subscription_clock_t) == 32, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_clock_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_clock_t, clock_id) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, timeout) == 8, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, precision) == 16, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, flags) == 24, "witx calculated offset"); + +/** + * The contents of a `subscription` when type is type is + * `eventtype::fd_read` or `eventtype::fd_write`. + */ +typedef struct __wasi_subscription_fd_readwrite_t { + /** + * The file descriptor on which to wait for it to become ready for reading or writing. + */ + __wasi_fd_t fd; + +} __wasi_subscription_fd_readwrite_t; + +_Static_assert(sizeof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_fd_readwrite_t, fd) == 0, "witx calculated offset"); + +/** + * The contents of a `subscription`. + */ +typedef union __wasi_subscription_u_u_t { + __wasi_subscription_clock_t clock; + __wasi_subscription_fd_readwrite_t fd_readwrite; +} __wasi_subscription_u_u_t ; + +typedef struct __wasi_subscription_u_t { + __wasi_eventtype_t type; + __wasi_subscription_u_u_t u; +} __wasi_subscription_u_t __attribute__((aligned(8))); + +_Static_assert(sizeof(__wasi_subscription_u_t) == 40, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_u_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_u_t, u) == 8, "witx calculated union offset"); +_Static_assert(sizeof(__wasi_subscription_u_u_t) == 32, "witx calculated union size"); +_Static_assert(_Alignof(__wasi_subscription_u_u_t) == 8, "witx calculated union align"); + +/** + * Subscription to an event. + */ typedef struct __wasi_subscription_t { + /** + * User-provided value that is attached to the subscription in the + * implementation and returned through `event::userdata`. + */ __wasi_userdata_t userdata; - __wasi_eventtype_t type; - uint8_t __paddings[7]; - union __wasi_subscription_u { - struct __wasi_subscription_u_clock_t { - __wasi_userdata_t identifier; - __wasi_clockid_t clock_id; - uint8_t __paddings1[4]; - __wasi_timestamp_t timeout; - __wasi_timestamp_t precision; - __wasi_subclockflags_t flags; - uint8_t __paddings2[6]; - } clock; - struct __wasi_subscription_u_fd_readwrite_t { - __wasi_fd_t fd; - } fd_readwrite; - } u; -} __wasi_subscription_t __attribute__((aligned(8))); -_Static_assert( - offsetof(__wasi_subscription_t, userdata) == 0, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, type) == 8, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.identifier) == 16, - "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.clock_id) == 24, - "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.timeout) == 32, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.precision) == 40, - "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.flags) == 48, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.fd_readwrite.fd) == 16, - "non-wasi data layout"); -_Static_assert(sizeof(__wasi_subscription_t) == 56, "non-wasi data layout"); -_Static_assert(_Alignof(__wasi_subscription_t) == 8, "non-wasi data layout"); + + /** + * The type of the event to which to subscribe, and its contents + */ + __wasi_subscription_u_t u; + +} __wasi_subscription_t; + +_Static_assert(sizeof(__wasi_subscription_t) == 48, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset"); #if defined(WASMTIME_SSP_WASI_API) #define WASMTIME_SSP_SYSCALL_NAME(name) \ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 94eb0024cb..7e01f85ca8 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -2418,19 +2418,19 @@ wasmtime_ssp_poll_oneoff( size_t *nevents) NO_LOCK_ANALYSIS { // Sleeping. - if (nsubscriptions == 1 && in[0].type == __WASI_EVENTTYPE_CLOCK) { + if (nsubscriptions == 1 && in[0].u.type == __WASI_EVENTTYPE_CLOCK) { out[0] = (__wasi_event_t){ .userdata = in[0].userdata, - .type = in[0].type, + .type = in[0].u.type, }; #if CONFIG_HAS_CLOCK_NANOSLEEP clockid_t clock_id; - if (convert_clockid(in[0].u.clock.clock_id, &clock_id)) { + if (convert_clockid(in[0].u.u.clock.clock_id, &clock_id)) { struct timespec ts; - convert_timestamp(in[0].u.clock.timeout, &ts); + convert_timestamp(in[0].u.u.clock.timeout, &ts); int ret = clock_nanosleep( clock_id, - (in[0].u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 + (in[0].u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 ? TIMER_ABSTIME : 0, &ts, NULL); @@ -2441,9 +2441,9 @@ wasmtime_ssp_poll_oneoff( out[0].error = __WASI_ENOTSUP; } #else - switch (in[0].u.clock.clock_id) { + switch (in[0].u.u.clock.clock_id) { case __WASI_CLOCK_MONOTONIC: - if ((in[0].u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) + if ((in[0].u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) != 0) { // TODO(ed): Implement. fputs("Unimplemented absolute sleep on monotonic clock\n", @@ -2454,12 +2454,12 @@ wasmtime_ssp_poll_oneoff( // Perform relative sleeps on the monotonic clock also using // nanosleep(). This is incorrect, but good enough for now. struct timespec ts; - convert_timestamp(in[0].u.clock.timeout, &ts); + convert_timestamp(in[0].u.u.clock.timeout, &ts); nanosleep(&ts, NULL); } break; case __WASI_CLOCK_REALTIME: - if ((in[0].u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) + if ((in[0].u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) != 0) { // Sleeping to an absolute point in time can only be done // by waiting on a condition variable. @@ -2473,7 +2473,8 @@ wasmtime_ssp_poll_oneoff( return -1; } mutex_lock(&mutex); - cond_timedwait(&cond, &mutex, in[0].u.clock.timeout, true); + cond_timedwait(&cond, &mutex, in[0].u.u.clock.timeout, + true); mutex_unlock(&mutex); mutex_destroy(&mutex); cond_destroy(&cond); @@ -2481,7 +2482,7 @@ wasmtime_ssp_poll_oneoff( else { // Relative sleeps can be done using nanosleep(). struct timespec ts; - convert_timestamp(in[0].u.clock.timeout, &ts); + convert_timestamp(in[0].u.u.clock.timeout, &ts); nanosleep(&ts, NULL); } break; @@ -2519,18 +2520,18 @@ wasmtime_ssp_poll_oneoff( const __wasi_subscription_t *clock_subscription = NULL; for (size_t i = 0; i < nsubscriptions; ++i) { const __wasi_subscription_t *s = &in[i]; - switch (s->type) { + switch (s->u.type) { case __WASI_EVENTTYPE_FD_READ: case __WASI_EVENTTYPE_FD_WRITE: { __wasi_errno_t error = - fd_object_get_locked(&fos[i], ft, s->u.fd_readwrite.fd, + fd_object_get_locked(&fos[i], ft, s->u.u.fd_readwrite.fd, __WASI_RIGHT_POLL_FD_READWRITE, 0); if (error == 0) { // Proper file descriptor on which we can poll(). pfds[i] = (struct pollfd){ .fd = fd_number(fos[i]), - .events = s->type == __WASI_EVENTTYPE_FD_READ + .events = s->u.type == __WASI_EVENTTYPE_FD_READ ? POLLRDNORM : POLLWRNORM, }; @@ -2542,14 +2543,14 @@ wasmtime_ssp_poll_oneoff( out[(*nevents)++] = (__wasi_event_t){ .userdata = s->userdata, .error = error, - .type = s->type, + .type = s->u.type, }; } break; } case __WASI_EVENTTYPE_CLOCK: if (clock_subscription == NULL - && (s->u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) + && (s->u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) == 0) { // Relative timeout. fos[i] = NULL; @@ -2565,7 +2566,7 @@ wasmtime_ssp_poll_oneoff( out[(*nevents)++] = (__wasi_event_t){ .userdata = s->userdata, .error = __WASI_ENOSYS, - .type = s->type, + .type = s->u.type, }; break; } @@ -2579,7 +2580,7 @@ wasmtime_ssp_poll_oneoff( timeout = 0; } else if (clock_subscription != NULL) { - __wasi_timestamp_t ts = clock_subscription->u.clock.timeout / 1000000; + __wasi_timestamp_t ts = clock_subscription->u.u.clock.timeout / 1000000; timeout = ts > INT_MAX ? -1 : (int)ts; } else { @@ -2603,7 +2604,7 @@ wasmtime_ssp_poll_oneoff( for (size_t i = 0; i < nsubscriptions; ++i) { if (pfds[i].fd >= 0) { __wasi_filesize_t nbytes = 0; - if (in[i].type == __WASI_EVENTTYPE_FD_READ) { + if (in[i].u.type == __WASI_EVENTTYPE_FD_READ) { int l; if (ioctl(fd_number(fos[i]), FIONREAD, &l) == 0) nbytes = (__wasi_filesize_t)l; @@ -2622,7 +2623,7 @@ wasmtime_ssp_poll_oneoff( #else .error = __WASI_EBADF, #endif - .type = in[i].type, + .type = in[i].u.type, }; } else if ((pfds[i].revents & POLLERR) != 0) { @@ -2630,14 +2631,14 @@ wasmtime_ssp_poll_oneoff( out[(*nevents)++] = (__wasi_event_t){ .userdata = in[i].userdata, .error = __WASI_EIO, - .type = in[i].type, + .type = in[i].u.type, }; } else if ((pfds[i].revents & POLLHUP) != 0) { // End-of-file. out[(*nevents)++] = (__wasi_event_t){ .userdata = in[i].userdata, - .type = in[i].type, + .type = in[i].u.type, .u.fd_readwrite.nbytes = nbytes, .u.fd_readwrite.flags = __WASI_EVENT_FD_READWRITE_HANGUP, @@ -2647,7 +2648,7 @@ wasmtime_ssp_poll_oneoff( // Read or write possible. out[(*nevents)++] = (__wasi_event_t){ .userdata = in[i].userdata, - .type = in[i].type, + .type = in[i].u.type, .u.fd_readwrite.nbytes = nbytes, }; } diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index b2524df4de..8db457c275 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -5,6 +5,13 @@ #include "thread_manager.h" +#if WASM_ENABLE_INTERP != 0 +#include "../interpreter/wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "../aot/aot_runtime.h" +#endif + #if WASM_ENABLE_DEBUG_INTERP != 0 #include "debug_engine.h" #endif @@ -337,25 +344,38 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) { WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); wasm_module_inst_t module_inst = get_module_inst(exec_env); - wasm_module_t module = wasm_exec_env_get_module(exec_env); + wasm_module_t module; wasm_module_inst_t new_module_inst; WASMExecEnv *new_exec_env; uint32 aux_stack_start, aux_stack_size; + uint32 stack_size = 8192; - if (!module) { + if (!module_inst || !(module = wasm_exec_env_get_module(exec_env))) { return NULL; } +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + stack_size = + ((WASMModuleInstance *)module_inst)->default_wasm_stack_size; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + stack_size = + ((AOTModuleInstance *)module_inst)->default_wasm_stack_size; + } +#endif + if (!(new_module_inst = wasm_runtime_instantiate_internal( - module, true, 8192, 0, NULL, 0))) { + module, true, stack_size, 0, NULL, 0))) { return NULL; } - if (module_inst) { - /* Set custom_data to new module instance */ - wasm_runtime_set_custom_data_internal( - new_module_inst, wasm_runtime_get_custom_data(module_inst)); - } + /* Set custom_data to new module instance */ + wasm_runtime_set_custom_data_internal( + new_module_inst, wasm_runtime_get_custom_data(module_inst)); new_exec_env = wasm_exec_env_create_internal(new_module_inst, exec_env->wasm_stack_size); @@ -605,16 +625,69 @@ wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst) #endif /* end of WASM_ENABLE_DEBUG_INTERP */ +/* Check whether the exec_env is in one of all clusters, the caller + should add lock to the cluster list before calling us */ +static bool +clusters_have_exec_env(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = bh_list_first_elem(cluster_list); + WASMExecEnv *node; + + while (cluster) { + node = bh_list_first_elem(&cluster->exec_env_list); + + while (node) { + if (node == exec_env) { + bh_assert(exec_env->cluster == cluster); + return true; + } + node = bh_list_elem_next(node); + } + + cluster = bh_list_elem_next(cluster); + } + + return false; +} + int32 wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) { - return os_thread_join(exec_env->handle, ret_val); + korp_tid handle; + + os_mutex_lock(&cluster_list_lock); + if (!clusters_have_exec_env(exec_env)) { + /* Invalid thread or the thread has exited */ + if (ret_val) + *ret_val = NULL; + os_mutex_unlock(&cluster_list_lock); + return 0; + } + exec_env->wait_count++; + handle = exec_env->handle; + os_mutex_unlock(&cluster_list_lock); + return os_thread_join(handle, ret_val); } int32 wasm_cluster_detach_thread(WASMExecEnv *exec_env) { - return os_thread_detach(exec_env->handle); + int32 ret = 0; + + os_mutex_lock(&cluster_list_lock); + if (!clusters_have_exec_env(exec_env)) { + /* Invalid thread or the thread has exited */ + os_mutex_unlock(&cluster_list_lock); + return 0; + } + if (exec_env->wait_count == 0) { + /* Only detach current thread when there is no other thread + joining it, otherwise let the system resources for the + thread be released after joining */ + ret = os_thread_detach(exec_env->handle); + } + os_mutex_unlock(&cluster_list_lock); + return ret; } void @@ -660,6 +733,14 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) int32 wasm_cluster_cancel_thread(WASMExecEnv *exec_env) { + os_mutex_lock(&cluster_list_lock); + if (!clusters_have_exec_env(exec_env)) { + /* Invalid thread or the thread has exited */ + os_mutex_unlock(&cluster_list_lock); + return 0; + } + os_mutex_unlock(&cluster_list_lock); + /* Set the termination flag */ #if WASM_ENABLE_DEBUG_INTERP != 0 wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index ca1cd8f804..2d4962a2c1 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -15,66 +15,11 @@ #ifdef __cplusplus extern "C" { #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 -#define WAMR_SIG_TRAP (5) -#define WAMR_SIG_STOP (19) -#define WAMR_SIG_TERM (15) -#define WAMR_SIG_SINGSTEP (0x1ff) - -#define STATUS_RUNNING (0) -#define STATUS_STOP (1) -#define STATUS_EXIT (2) -#define STATUS_STEP (3) - -#define IS_WAMR_TERM_SIG(signo) ((signo) == WAMR_SIG_TERM) - -#define IS_WAMR_STOP_SIG(signo) \ - ((signo) == WAMR_SIG_STOP || (signo) == WAMR_SIG_TRAP) - -typedef struct WASMCurrentEnvStatus { - uint64 signal_flag : 32; - uint64 step_count : 16; - uint64 running_status : 16; - korp_mutex wait_lock; - korp_cond wait_cond; -} WASMCurrentEnvStatus; +#if WASM_ENABLE_DEBUG_INTERP != 0 typedef struct WASMDebugInstance WASMDebugInstance; - -WASMCurrentEnvStatus * -wasm_cluster_create_exenv_status(); - -void -wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status); - -void -wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo); - -void -wasm_cluster_thread_stopped(WASMExecEnv *exec_env); - -void -wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env); - -void -wasm_cluster_wait_thread_status(WASMExecEnv *exec_env, uint32 *status); - -void -wasm_cluster_thread_exited(WASMExecEnv *exec_env); - -void -wasm_cluster_thread_continue(WASMExecEnv *exec_env); - -void -wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo); - -void -wasm_cluster_thread_step(WASMExecEnv *exec_env); - -void -wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst); - #endif + typedef struct WASMCluster { struct WASMCluster *next; @@ -183,6 +128,65 @@ void wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, void *custom_data); +#if WASM_ENABLE_DEBUG_INTERP != 0 +#define WAMR_SIG_TRAP (5) +#define WAMR_SIG_STOP (19) +#define WAMR_SIG_TERM (15) +#define WAMR_SIG_SINGSTEP (0x1ff) + +#define STATUS_RUNNING (0) +#define STATUS_STOP (1) +#define STATUS_EXIT (2) +#define STATUS_STEP (3) + +#define IS_WAMR_TERM_SIG(signo) ((signo) == WAMR_SIG_TERM) + +#define IS_WAMR_STOP_SIG(signo) \ + ((signo) == WAMR_SIG_STOP || (signo) == WAMR_SIG_TRAP) + +typedef struct WASMCurrentEnvStatus { + uint64 signal_flag : 32; + uint64 step_count : 16; + uint64 running_status : 16; + korp_mutex wait_lock; + korp_cond wait_cond; +} WASMCurrentEnvStatus; + +WASMCurrentEnvStatus * +wasm_cluster_create_exenv_status(); + +void +wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status); + +void +wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo); + +void +wasm_cluster_thread_stopped(WASMExecEnv *exec_env); + +void +wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env); + +void +wasm_cluster_wait_thread_status(WASMExecEnv *exec_env, uint32 *status); + +void +wasm_cluster_thread_exited(WASMExecEnv *exec_env); + +void +wasm_cluster_thread_continue(WASMExecEnv *exec_env); + +void +wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo); + +void +wasm_cluster_thread_step(WASMExecEnv *exec_env); + +void +wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst); + +#endif /* end of WASM_ENABLE_DEBUG_INTERP != 0 */ + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/android/platform_init.c b/core/shared/platform/android/platform_init.c index d7ffab33da..1e7cf4447b 100644 --- a/core/shared/platform/android/platform_init.c +++ b/core/shared/platform/android/platform_init.c @@ -89,6 +89,50 @@ readlinkat(int __dir_fd, const char *__path, char *__buf, size_t __buf_size) return -1; } +int +accept4(int __fd, struct sockaddr *__addr, socklen_t *__addr_length, + int __flags) +{ + API_NOT_SUPPORT_ERROR(accept4, 21); + return -1; +} + +int +dup3(int oldfd, int newfd, int cloexec) +{ + API_NOT_SUPPORT_ERROR(dup3, 21); + return -1; +} + +int +pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id) +{ + API_NOT_SUPPORT_ERROR(pthread_condattr_setclock, 21); + return -1; +} + +int +epoll_create1(int flags) +{ + API_NOT_SUPPORT_ERROR(epoll_create1, 21); + return -1; +} + +int +epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, + const sigset_t *sigmask) +{ + API_NOT_SUPPORT_ERROR(epoll_pwait, 21); + return -1; +} + +int +inotify_init1(int flags) +{ + API_NOT_SUPPORT_ERROR(inotify_init1, 21); + return -1; +} + #endif #if __ANDROID_API__ < 23 diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index 3ba77baaa6..3a22a5064e 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -16,6 +16,7 @@ static size_t total_size_munmapped = 0; #define HUGE_PAGE_SIZE (2 * 1024 * 1024) +#if !defined(__APPLE__) && !defined(__NuttX__) static inline uintptr_t round_up(uintptr_t v, uintptr_t b) { @@ -29,6 +30,7 @@ round_down(uintptr_t v, uintptr_t b) uintptr_t m = b - 1; return v & ~m; } +#endif void * os_mmap(void *hint, size_t size, int prot, int flags) diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 1e7e4f3750..4a20c10a08 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -326,10 +326,18 @@ os_thread_get_stack_boundary() #elif defined(__APPLE__) || defined(__NuttX__) if ((addr = (uint8 *)pthread_get_stackaddr_np(self))) { stack_size = pthread_get_stacksize_np(self); + + /** + * Check whether stack_addr is the base or end of the stack, + * change it to the base if it is the end of stack. + */ + if (addr <= (uint8 *)&stack_size) + addr = addr + stack_size; + if (stack_size > max_stack_size) - addr -= max_stack_size; - else - addr -= stack_size; + stack_size = max_stack_size; + + addr -= stack_size; /* Reserved 1 guard page at least for safety */ addr += page_size; } diff --git a/core/shared/platform/esp-idf/espidf_malloc.c b/core/shared/platform/esp-idf/espidf_malloc.c index 138df39774..8fde7c8d34 100644 --- a/core/shared/platform/esp-idf/espidf_malloc.c +++ b/core/shared/platform/esp-idf/espidf_malloc.c @@ -14,6 +14,9 @@ os_malloc(unsigned size) uintptr_t *addr_field; buf_origin = malloc(size + 8 + sizeof(uintptr_t)); + if (!buf_origin) { + return NULL; + } buf_fixed = buf_origin + sizeof(void *); if ((uintptr_t)buf_fixed & (uintptr_t)0x7) { buf_fixed = (void *)((uintptr_t)(buf_fixed + 8) & (~(uintptr_t)7)); @@ -34,12 +37,15 @@ os_realloc(void *ptr, unsigned size) uintptr_t *addr_field; if (!ptr) { - return NULL; + return os_malloc(size); } addr_field = ptr - sizeof(uintptr_t); mem_origin = (void *)(*addr_field); mem_new = realloc(mem_origin, size + 8 + sizeof(uintptr_t)); + if (!mem_new) { + return NULL; + } if (mem_origin != mem_new) { mem_new_fixed = mem_new + sizeof(uintptr_t); @@ -61,7 +67,7 @@ void os_free(void *ptr) { void *mem_origin; - uintptr *addr_field; + uintptr_t *addr_field; if (ptr) { addr_field = ptr - sizeof(uintptr_t); diff --git a/core/shared/platform/esp-idf/espidf_memmap.c b/core/shared/platform/esp-idf/espidf_memmap.c index 587fd749b5..693094a634 100644 --- a/core/shared/platform/esp-idf/espidf_memmap.c +++ b/core/shared/platform/esp-idf/espidf_memmap.c @@ -9,12 +9,34 @@ void * os_mmap(void *hint, size_t size, int prot, int flags) { - return os_malloc((int)size); + if (prot & MMAP_PROT_EXEC) { + // 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); + if (!buf_origin) { + return NULL; + } + void *buf_fixed = buf_origin + sizeof(void *); + if ((uintptr_t)buf_fixed & (uintptr_t)0x7) { + buf_fixed = (void *)((uintptr_t)(buf_fixed + 4) & (~(uintptr_t)7)); + } + + uintptr_t *addr_field = buf_fixed - sizeof(uintptr_t); + *addr_field = (uintptr_t)buf_origin; + return buf_fixed; + } + else { + return os_malloc(size); + } } void os_munmap(void *addr, size_t size) { + // We don't need special handling of the executable allocations + // here, free() of esp-idf handles it properly return os_free(addr); } diff --git a/core/shared/platform/esp-idf/espidf_platform.c b/core/shared/platform/esp-idf/espidf_platform.c index e23eedeb76..af6be88cb0 100644 --- a/core/shared/platform/esp-idf/espidf_platform.c +++ b/core/shared/platform/esp-idf/espidf_platform.c @@ -44,7 +44,13 @@ os_time_get_boot_microsecond(void) uint8 * os_thread_get_stack_boundary(void) { +#if defined(CONFIG_FREERTOS_USE_TRACE_FACILITY) + TaskStatus_t pxTaskStatus; + vTaskGetInfo(xTaskGetCurrentTaskHandle(), &pxTaskStatus, pdTRUE, eInvalid); + return pxTaskStatus.pxStackBase; +#else // !defined(CONFIG_FREERTOS_USE_TRACE_FACILITY) return NULL; +#endif } int diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index db94241630..5c50f9e30e 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -74,6 +74,9 @@ os_mem_decommit(void *ptr, size_t size); #define os_thread_local_attribute __declspec(thread) +#define strncasecmp _strnicmp +#define strcasecmp _stricmp + #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index 558a3733da..408784d544 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -47,6 +47,10 @@ static os_thread_data supervisor_thread_data; /* Thread data key */ static DWORD thread_data_key; +/* The GetCurrentThreadStackLimits API from "kernel32" */ +static void(WINAPI *GetCurrentThreadStackLimits_Kernel32)(PULONG_PTR, + PULONG_PTR) = NULL; + int os_sem_init(korp_sem *sem); int @@ -61,6 +65,8 @@ os_sem_signal(korp_sem *sem); int os_thread_sys_init() { + HMODULE module; + if (is_thread_sys_inited) return BHT_OK; @@ -84,6 +90,11 @@ os_thread_sys_init() if (!TlsSetValue(thread_data_key, &supervisor_thread_data)) goto fail4; + if ((module = GetModuleHandle((LPSTR) "kernel32"))) { + *(void **)&GetCurrentThreadStackLimits_Kernel32 = + GetProcAddress(module, "GetCurrentThreadStackLimits"); + } + is_thread_sys_inited = true; return BHT_OK; @@ -556,7 +567,6 @@ os_cond_signal(korp_cond *cond) static os_thread_local_attribute uint8 *thread_stack_boundary = NULL; -#if _WIN32_WINNT < 0x0602 static ULONG GetCurrentThreadStackLimits_Win7(PULONG_PTR p_low_limit, PULONG_PTR p_high_limit) @@ -579,7 +589,6 @@ GetCurrentThreadStackLimits_Win7(PULONG_PTR p_low_limit, os_printf("warning: VirtualQuery() failed\n"); return GetLastError(); } -#endif uint8 * os_thread_get_stack_boundary() @@ -591,13 +600,14 @@ os_thread_get_stack_boundary() return thread_stack_boundary; page_size = os_getpagesize(); -#if _WIN32_WINNT >= 0x0602 - GetCurrentThreadStackLimits(&low_limit, &high_limit); -#else - if (0 != GetCurrentThreadStackLimits_Win7(&low_limit, &high_limit)) { - return NULL; + if (GetCurrentThreadStackLimits_Kernel32) { + GetCurrentThreadStackLimits_Kernel32(&low_limit, &high_limit); } -#endif + else { + if (0 != GetCurrentThreadStackLimits_Win7(&low_limit, &high_limit)) + return NULL; + } + /* 4 pages are set unaccessible by system, we reserved one more page at least for safety */ thread_stack_boundary = (uint8 *)(uintptr_t)low_limit + page_size * 5; diff --git a/doc/build_wasm_app.md b/doc/build_wasm_app.md index eee1711f47..cff4afd2a2 100644 --- a/doc/build_wasm_app.md +++ b/doc/build_wasm_app.md @@ -2,18 +2,38 @@ # Prepare WASM building environments -For C and C++, WASI-SDK version 12.0+ is the major tool supported by WAMR to build WASM applications. Also we can use [Emscripten SDK (EMSDK)](https://github.com/emscripten-core/emsdk), but it is not recommended. And there are some other compilers such as the standard clang compiler, which might also work [here](./other_wasm_compilers.md). +For C and C++, WASI-SDK version 12.0+ is the major tool supported by WAMR to build WASM applications. Also, we can use [Emscripten SDK (EMSDK)](https://github.com/emscripten-core/emsdk), but it is not recommended. And there are some other compilers such as the standard clang compiler, which might also work [here](./other_wasm_compilers.md). To install WASI SDK, please download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`. -The offical *wasi-sdk release* doesn't fully support *latest 128-bit SIMD spec* yet. WARM provides a script in [build-wasi-sdk](../test-tools/build-wasi-sdk/) to generate -another wasi-sdk with *llvm-13* from source code and installs it at *../test-tools/wasi-sdk*. If you plan to build WASM applications with *latest 128-bit SIMD*, please use it instead of the offical release. +The official *wasi-sdk release* doesn't fully support *latest 128-bit SIMD spec* yet. WARM provides a script in [build-wasi-sdk](../test-tools/build-wasi-sdk/) to generate +another wasi-sdk with *llvm-13* from source code and installs it at *../test-tools/wasi-sdk*. If you plan to build WASM applications with *latest 128-bit SIMD*, please use it instead of the official release. And [sample workloads](../samples/workload) are using the self-compiled wasi-sdk. For [AssemblyScript](https://github.com/AssemblyScript/assemblyscript), please refer to [AssemblyScript quick start](https://www.assemblyscript.org/quick-start.html) and [AssemblyScript compiler](https://www.assemblyscript.org/compiler.html#command-line-options) for how to install `asc` compiler and build WASM applications. -For Rust, please firstly ref to [Install Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) to install cargo, rustc and rustup, by default they are installed under ~/.cargo/bin, and then run `rustup target add wasm32-wasi` to install wasm32-wasi target for Rust toolchain. To build WASM applications, we can run `cargo build --target wasm32-wasi`, the output files are under `target/wasm32-wasi`. +For Rust, please refer to [Install Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) to install *cargo*, *rustc* and *rustup*. By default they are under ~/.cargo/bin. + +And then run such a command to install `wasm32-wasi` target. + +``` bash +$ rustup target add wasm32-wasi +``` + +To build WASM applications, run + +``` bash +$ cargo build --target wasm32-wasi +``` + +The output files are under `target/wasm32-wasi`. + +To build a release version + +``` bash +$ cargo build --release --target wasm32-wasi +``` Build WASM applications with wasi-sdk @@ -55,9 +75,9 @@ To build the source file to WASM bytecode, we can input the following command: ## 1. wasi-sdk options -There are some useful options which can be specified to build the source code (for more link options, please run `/opt/wasi-sdk/bin/wasm-ld --help`): +There are some useful options that are used to compile C/C++ to Wasm (for a full introduction, please refer to [clang command line argument reference](https://clang.llvm.org/docs/ClangCommandLineReference.html) and [wasm-ld command line argument manual](https://lld.llvm.org/WebAssembly.html)): -- **-nostdlib** Do not use the standard system startup files or libraries when linking. In this mode, the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for cmake to build WAMR with libc-builtin support or libc-wasi support. +- **-nostdlib** Do not use the standard system startup files or libraries when linking. In this mode, the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for CMake to build WAMR with libc-builtin support or libc-wasi support. - **-Wl,--no-entry** Do not output any entry point @@ -69,7 +89,7 @@ There are some useful options which can be specified to build the source code (f - **-Wl,--max-memory=\** Maximum size of the linear memory, which must be a multiple of 65536 -- **-z stack-size=\** The auxiliary stack size, which is an area of linear memory, and must be smaller than initial memory size. +- **-z stack-size=\** The auxiliary stack size, which is an area of linear memory, must be smaller than the initial memory size. - **-Wl,--strip-all** Strip all symbols @@ -81,7 +101,7 @@ There are some useful options which can be specified to build the source code (f - **-pthread** Support POSIX threads in generated code -For example, we can build the wasm app with command: +For example, we can build the wasm app with the command: ``` Bash /opt/wasi-sdk/bin/clang -O3 -nostdlib \ @@ -91,9 +111,9 @@ For example, we can build the wasm app with command: -Wl,--export=__heap_base -Wl,--export=__data_end \ -Wl,--no-entry -Wl,--strip-all -Wl,--allow-undefined ``` -to generate a wasm binary with nostdlib mode, auxiliary stack size is 8192 bytes, initial memory size is 64 KB, main function, heap base global and data end global are exported, no entry function is generated (no _start function is exported), and all symbols are stripped. Note that it is nostdlib mode, so libc-builtin should be enabled by runtime embedder or iwasm (with cmake -DWAMR_BUILD_LIBC_BUILT=1, enabled by iwasm in Linux by default). +to generate a wasm binary with nostdlib mode, the auxiliary stack size is 8192 bytes, initial memory size is 64 KB, main function, heap base global and data end global are exported, no entry function is generated (no _start function is exported), and all symbols are stripped. Note that it is nostdlib mode, so libc-builtin should be enabled by runtime embedder or iwasm (with `cmake -DWAMR_BUILD_LIBC_BUILT=1`, enabled by iwasm in Linux by default). -If we want to build the wasm app with wasi mode, we may build the wasm app with command: +If we want to build the wasm app with wasi mode, we may build the wasm app with the command: ```bash /opt/wasi-sdk/bin/clang -O3 \ @@ -103,7 +123,7 @@ If we want to build the wasm app with wasi mode, we may build the wasm app with -Wl,--strip-all ``` -to generate a wasm binary with wasi mode, auxiliary stack size is 8192 bytes, initial memory size is 64 KB, heap base global and data end global are exported, wasi entry function exported (_start function), and all symbols are stripped. Note that it is wasi mode, so libc-wasi should be enabled by runtime embedder or iwasm (with cmake -DWAMR_BUILD_LIBC_WASI=1, enabled by iwasm in Linux by default), and normally no need to export main function, by default _start function is executed by iwasm. +to generate a wasm binary with wasi mode, the auxiliary stack size is 8192 bytes, initial memory size is 64 KB, heap base global and data end global are exported, wasi entry function exported (_start function), and all symbols are stripped. Note that it is wasi mode, so libc-wasi should be enabled by runtime embedder or iwasm (with `cmake -DWAMR_BUILD_LIBC_WASI=1`, enabled by iwasm in Linux by default), and normally no need to export main function, by default _start function is executed by iwasm. ## 2. How to reduce the footprint? @@ -119,7 +139,7 @@ Firstly if libc-builtin (-nostdlib) mode meets the requirements, e.g. there are - reduce auxiliary stack size - The auxiliary stack is an area of linear memory, normally the size is 64 KB by default which might be a little large for embedded devices and actually partly used, we can use `-z stack-size=n` to set its size. + The auxiliary stack is an area of linear memory, normally the size is 64 KB by default which might be a little large for embedded devices and partly used, we can use `-z stack-size=n` to set its size. - use -O3 and -Wl,--strip-all @@ -133,7 +153,7 @@ Firstly if libc-builtin (-nostdlib) mode meets the requirements, e.g. there are - decrease block_addr_cache size for classic interpreter - The block_addr_cache is an hash cache to store the else/end addresses for WebAssembly blocks (BLOCK/IF/LOOP) to speed up address lookup. This is only available in classic interpreter. We can set it by define macro `-DBLOCK_ADDR_CACHE_SIZE=n`, e.g. add `add_defintion (-DBLOCK_ADDR_CACHE_SIZE=n)` in CMakeLists.txt, by default it is 64, and total block_addr_cache size is 3072 bytes in 64-bit platform and 1536 bytes in 32-bit platform. + The block_addr_cache is a hash cache to store the else/end addresses for WebAssembly blocks (BLOCK/IF/LOOP) to speed up address lookup. This is only available in the classic interpreter. We can set it by defineing macro `-DBLOCK_ADDR_CACHE_SIZE=n`, e.g. add `add_defintion (-DBLOCK_ADDR_CACHE_SIZE=n)` in CMakeLists.txt, by default it is 64, and the total block_addr_cache size is 3072 bytes in 64-bit platform and 1536 bytes in 32-bit platform. ### (2) Methods to reduce the libc-wasi (without -nostdlib) mode footprint @@ -178,7 +198,7 @@ EMCC_ONLY_FORCED_STDLIBS=1 emcc -O3 -s STANDALONE_WASM=1 \ There are some useful options: -- **EMCC_ONLY_FORCED_STDLIBS=1** whether to link libc library into the output binary or not, similar to `-nostdlib` option of wasi-sdk clang. If specified, then no libc library is linked and the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for cmake to build WAMR with libc-builtin support or libc-wasi support. +- **EMCC_ONLY_FORCED_STDLIBS=1** whether to link libc library into the output binary or not, similar to `-nostdlib` option of wasi-sdk clang. If specified, then no libc library is linked and the **libc-builtin** library of WAMR must be built to run the wasm app, otherwise, the **libc-wasi** library must be built. You can specify **-DWAMR_BUILD_LIBC_BUILTIN=1** or **-DWAMR_BUILD_LIBC_WASI=1** for CMake to build WAMR with libc-builtin support or libc-wasi support. The emsdk's wasi implementation is incomplete, e.g. open a file might just return fail, so it is strongly not recommended to use this mode, especially when there are file io operations in wasm app, please use wasi-sdk instead. @@ -200,31 +220,48 @@ For more options, please ref to /upstream/emscripten/src/settings.js, # Build a project with cmake -If you have complex WASM application project which contains dozens of source files, you can consider using cmake for project building. +If you have a complex WASM application project which contains dozens of source files, you can consider using cmake for project building. You can cross compile your project by using the toolchain provided by WAMR. -We can generate a `CMakeLists.txt` file for `test.c`: +Assume the original `CMakeLists.txt` for `test.c` likes below: ``` cmake cmake_minimum_required (VERSION 3.5) project(hello_world) - -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS},--export=main") add_executable(hello_world test.c) ``` -It is simple to build this project by cmake: +It is easy to use *wasi-sdk* in CMake by setting *CMAKE_TOOLCHAIN_FILE* without any modification on the original *CMakeLists.txt*. -``` Bash -mkdir build && cd build -cmake .. -DCMAKE_TOOLCHAIN_FILE=$WAMR_ROOT/wamr-sdk/app/wamr_toolchain.cmake -make +``` +$ cmake -DWASI_SDK_PREFIX=${WASI_SDK_INSTALLTION_DIR} + -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_INSTALLTION_DIR}/share/cmake/wasi-sdk.cmake + -DCMAKE_SYSROOT= + .. ``` -You will get ```hello_world``` which is the WASM app binary. +`WASI_SDK_INSTALLTION_DIR` is the directory in where you install the *wasi-sdk*. like */opt/wasi-sdk* + +If you prefer WASI, set *CMAKE_SYSROOT* to *wasi-sysroot* + +``` +$ cmake + -DCMAKE_SYSROOT=${WASI_SDK_INSTALLTION_DIR}/share/wasi-sysroot + .. +``` -> Note: If you have already built a SDK profile, then the **DCMAKE_TOOLCHAIN_FILE** should be changed into `$WAMR_ROOT/wamr-sdk/out/${PROFILE}/app-sdk/wamr_toolchain.cmake` +If you prefer *WAMR builtin libc*, set *CMAKE_SYSROOT* to *libc-builtin-sysroot* + +> Note: If you have already built a SDK profile + +``` +$ cmake + -DCMAKE_SYSROOT=${WAMR_SOURCE_ROOT}/wamr-sdk/app/libc-builtin-sysroot + .. +``` + +You will get ```hello_world``` which is the WASM app binary. # Compile WASM to AoT module diff --git a/doc/export_native_api.md b/doc/export_native_api.md index e507c5c41e..fba83d3ea8 100644 --- a/doc/export_native_api.md +++ b/doc/export_native_api.md @@ -85,10 +85,11 @@ The function signature field in **NativeSymbol** structure is a string for descr Each letter in the "()" represents a parameter type, and the one following after ")" represents the return value type. The meaning of each letter: -- '**i**': i32 or externref (for externref, developer should use `wasm_externref_obj2ref()` to map host object to externref index firstly) +- '**i**': i32 - '**I**': i64 - '**f**': f32 - '**F**': f64 +- '**r**': externref (has to be the value of a `uintptr_t` variable) - '**\***': the parameter is a buffer address in WASM application - '**~**': the parameter is the byte length of WASM buffer as referred by preceding argument "\*". It must follow after '*', otherwise, registration will fail - '**$**': the parameter is a string in WASM application diff --git a/doc/multi_module.md b/doc/multi_module.md index 030ad221fc..1c22863f95 100644 --- a/doc/multi_module.md +++ b/doc/multi_module.md @@ -1,17 +1,24 @@ -Multiple Modules as Dependencies -========================= +# Multiple Modules as Dependencies -It is allowed that one WASM module can *import* *functions*, *globals*, *memories* and *tables* from other modules as its dependencies, and also one module can *export* those entities for other modules to *access* and may *write*. +A WASM module can _import_ _functions_, _globals_, _memories_ and _tables_ from other modules as dependencies. A module can also _export_ those entities for other modules like a library. -WAMR loads all dependencies recursively according to the *import section* of a module. +WAMR loads all dependencies recursively according to the _import section_ of a module. -> Currently WAMR only implements the load-time dynamic linking. Please refer to [dynamic linking](https://webassembly.org/docs/dynamic-linking/) for more details. +> WAMR only implements the load-time dynamic linking. Please refer to [dynamic linking](https://webassembly.org/docs/dynamic-linking/) for more details. + +WAMR follows [WASI Command/Reactor Model](https://github.com/WebAssembly/WASI/blob/main/design/application-abi.md#current-unstable-abi). The WASI model separates modules into commands and reactors. A Command is the main module that requires exports of reactors(submodules). + +if `WASM_ENABLE_LIBC_WASI` is enabled, any module imports a WASI APIs, like `(import "wasi_snapshot_preview1" "XXX")`, should follow restrictions of the _WASI application ABI_: + +- a main module(a command) should include `_start()` +- a submodule(a reactor) should include `_initialize()` +- both a command and a reactor should include an exported `memory` ## Multi-Module Related APIs ### Register a module -``` c +```c bool wasm_runtime_register_module(const char *module_name, wasm_module_t module, @@ -19,23 +26,23 @@ wasm_runtime_register_module(const char *module_name, uint32_t error_buf_size); ``` -It is used to register a *module* with a *module_name* to WASM runtime, especially for the root module, which is loaded by `wasm_runtime_load()` and doesn't have a chance to tell runtime its *module name*. +It is used to register a _module_ with a _module_name_ to WASM runtime, especially for the main module, which is loaded by `wasm_runtime_load()` and doesn't have a chance to tell runtime its _module name_. -Fot all the sub modules, WAMR will get their names and load the .wasm files from the filesystem or stream, so no need to register the sub modules again. +WAMR will get submodules' names(according to the _import section_ of the main module) and load .wasm files from the filesystem or stream and then register them internally. ### Find a registered module -``` c +```c wasm_module_t wasm_runtime_find_module_registered( const char *module_name); ``` -It is used to check if a module with a given *module_name* has been registered, if yes return the module. +It is used to check whether a module with a given _module_name_ has been registered before or not. Return the module if yes. ### Module reader and destroyer -``` c +```c typedef bool (*module_reader)(const char *module_name, uint8_t **p_buffer, uint32_t *p_size); @@ -48,9 +55,9 @@ wasm_runtime_set_module_reader(const module_reader reader, const module_destroyer destroyer); ``` -WAMR hopes that the native host or embedding environment loads/unloads the module WASM files by themselves and only passes runtime the binary content without worrying filesystem or storage issues. `module_reader` and `module_destroyer` are two callbacks called when dynamic-loading/unloading the sub modules. Developers must implement the two callbacks by themselves. +WAMR hopes that the native host or embedding environment loads/unloads the module WASM files by themselves and only passes runtime the binary content without worrying about filesystem or storage issues. `module_reader` and `module_destroyer` are two callbacks called when dynamic-loading/unloading submodules. Developers must implement the two callbacks by themselves. -### Call function of sub module +### Call function of a submodule ```c wasm_function_inst_t @@ -59,87 +66,75 @@ wasm_runtime_lookup_function(wasm_module_inst_t const module_inst, const char *signature); ``` -Multi-module allows to lookup the function of sub module and call it. There are two ways to indicate the function *name*: +Multi-module allows one to look up an exported function of a submodule. There are two ways to indicate the function _name_: -- parent function name only by default, used to lookup the function of parent module -- sub module name, function name of sub module and two $ symbols, e.g. `$sub_module_name$function_name`, used to lookup function of sub module +- parent function name only by default, used to look up the function of the parent module +- submodule name, function name and two $ symbols, e.g. `$submodule_name$function_name`, used to lookup function of submodule +- `signature` can be NULL ## Example -### WASM modules -Suppose we have three C files, *mA.c*, *mB.c* and *mC.c*. Each of them has some exported functions and import some from others except mA. +### Attributes in C/C++ -Undefined symbols can be marked in the source code with the *import_name* clang attribute which means that they are expected to be undefined at static link time. Without the *import_module* clang attribute, undefined symbols will be marked from the *env* module. +Suppose there are three C files, _mA.c_, _mB.c_ and _mC.c_. Each of them exports functions and imports from others except mA. -``` C +import/export with two kinds of `__attribute__`: + +- `__attribute__((import_module("MODULE_NAME"))) __attribute__((import_name("FUNCTION_NAME")))`. to indicate dependencies of the current module. + +- `__attribute__((export_name("FUNCTION_NAME")))`. to expose functions. + +```C // mA.c -int A() { return 10; } +__attribute__((export_name("A1"))) int +A1() +{ + return 11; +} ``` -``` C +```C // mB.c -__attribute__((import_module("mA"))) __attribute__((import_name("A"))) extern int A(); -int B() { return 11; } -int call_A() { return A(); } -``` +__attribute__((import_module("mA"))) +__attribute__((import_name("A1"))) extern int +A1(); -``` C -// mC.c -__attribute__((import_module("mA"))) __attribute__((import_name("A"))) extern int A(); -__attribute__((import_module("mB"))) __attribute__((import_name("B"))) extern int B(); -int C() { return 12; } -int call_A() { return A(); } -int call_B() { return B(); } +__attribute__((export_name("B1"))) int +B1() +{ + return 21; +} ``` -By default no undefined symbols are allowed in the final binary. The flag *--allow-undefined* results in a WebAssembly import being defined for each undefined symbol. It is then up to the runtime to provide such symbols. - -When building an executable, only the entry point (_start) and symbols with the *export_name* attribute exported by default. in addition, symbols can be exported via the linker command line using *--export*. - -In the example, another linked command option *--export-all* is used. - -> with more detail, please refer to [WebAssembly lld port](https://lld.llvm.org/WebAssembly.html) +### Compile Options -Here is an example how to compile a *.c* to a *.wasm* with clang. Since there is no *start* function, we use *--no-entry* option. +to generate a wasm module as a command -``` shell -$ clang --target=wasm32 -nostdlib \ - -Wl,--no-entry,--allow-undefined,--export-all \ - -o mA.wasm mA.c -$ clang --target=wasm32 -nostdlib \ - -Wl,--no-entry,--allow-undefined,--export-all \ - -o mB.wasm mB.c -$ clang --target=wasm32 -nostdlib \ - -Wl,--no-entry,--allow-undefined,--export-all \ - -o mC.wasm mC.c +``` +$ /path/to/wasi-sdk/bin/clang -o command.wasm main_module.c ``` -put *mA.wasm*, *mB.wasm* and *mC.wasm* in the directory *wasm-apps* +to generate a wasm module as a reactor -``` shell -$ # copy mA.wasm, mB.wasm and mC.wasm into wasm-apps -$ tree wasm-apps/ -wasm-apps/ -├── mA.wasm -├── mB.wasm -└── mC.wasm +``` +$ /path/to/wasi-sdk/bin/clang -mexec-model=reactor -o reactor.wasm submodule.c ``` -eventually, their *import relationships* will be like: +In the above case, _mA_ and _mB_ are reactors(submodules), _mC_ is the command(main module). Their _import relationships_ will be like: ![import relationships](./pics/multi_module_pic1.png) ### libvmlib -We need to enable *WAMR_BUILD_MULTI_MODULE* option when building WAMR vmlib. Please ref to [Build WAMR core](./build_wamr.md) for a thoughtful guide. +We need to enable _WAMR_BUILD_MULTI_MODULE_ option when building WAMR vmlib. Please ref to [Build WAMR core](./build_wamr.md) for a thoughtful guide. ### code -After all above preparation, we can call some functions from native code with APIs +After all the preparation, we can call some functions from native code with APIs -first, create two callbacks to load WASM module files into memory and unload them later +First, create two callbacks to load WASM module files into memory and unload them later -``` c +```c static bool module_reader_cb(const char *module_name, uint8 **p_buffer, uint32 *p_size) { @@ -155,74 +150,12 @@ module_destroyer_cb(uint8 *buffer, uint32 size) } ``` -second, create a large buffer and tell WAMR malloc any resource only from this buffer later +Second, create a large buffer and tell WAMR malloc any resource only from this buffer later. -``` c -static char sandbox_memory_space[10 * 1024 * 1024] = { 0 }; -``` +More details -third, put all together - -``` c -int main() -{ - /* all malloc() only from the given buffer */ - init_args.mem_alloc_type = Alloc_With_Pool; - init_args.mem_alloc_option.pool.heap_buf = sandbox_memory_space; - init_args.mem_alloc_option.pool.heap_size = sizeof(sandbox_memory_space); - - /* initialize runtime environment */ - wasm_runtime_full_init(&init_args); - - /* set module reader and destroyer */ - wasm_runtime_set_module_reader(module_reader_cb, module_destroyer_cb); - - /* load WASM byte buffer from WASM bin file */ - module_reader_cb("mC", &file_buf, &file_buf_size)); - - /* load mC and let WAMR load mA and mB */ - module = wasm_runtime_load(file_buf, file_buf_size, - error_buf, sizeof(error_buf)); - - /* instantiate the module */ - module_inst = - wasm_runtime_instantiate(module, stack_size, - heap_size, error_buf, sizeof(error_buf))); - - - printf("call \"C\", it will return 0xc:i32, ===> "); - wasm_application_execute_func(module_inst, "C", 0, &args[0]); - printf("call \"call_B\", it will return 0xb:i32, ===> "); - wasm_application_execute_func(module_inst, "call_B", 0, &args[0]); - printf("call \"call_A\", it will return 0xa:i32, ===>"); - wasm_application_execute_func(module_inst, "call_A", 0, &args[0]); - - /* call some functions of mB */ - printf("call \"mB.B\", it will return 0xb:i32, ===>"); - wasm_application_execute_func(module_inst, "$mB$B", 0, &args[0]); - printf("call \"mB.call_A\", it will return 0xa:i32, ===>"); - wasm_application_execute_func(module_inst, "$mB$call_A", 0, &args[0]); - - /* call some functions of mA */ - printf("call \"mA.A\", it will return 0xa:i32, ===>"); - wasm_application_execute_func(module_inst, "$mA$A", 0, &args[0]); - - // ... -} +```c +static char sandbox_memory_space[10 * 1024 * 1024] = { 0 }; ``` -> please refer to [main.c](../samples/multi_modules/src/main.c) - -The output of the main.c will like: - -``` shell -$ ./a.out - -call "C", it will return 0xc:i32, ===> 0xc:i32 -call "call_B", it will return 0xb:i32, ===> 0xb:i32 -call "call_A", it will return 0xa:i32, ===>0xa:i32 -call "mB.B", it will return 0xb:i32, ===>0xb:i32 -call "mB.call_A", it will return 0xa:i32, ===>0xa:i32 -call "mA.A", it will return 0xa:i32, ===>0xa:i32 - -``` +Third, put all together. Please refer to [main.c](../samples/multi-module/src/main.c) diff --git a/doc/ref_types.md b/doc/ref_types.md index ed37411f3c..7fefa999d5 100644 --- a/doc/ref_types.md +++ b/doc/ref_types.md @@ -1,22 +1,9 @@ # WAMR reference-types introduction -WebAssembly [reference-types](https://github.com/WebAssembly/reference-types) proposal introduces the new type `externref` and makes it easier and more efficient to interoperate with host environment, allowing host references to be represented directly by type externref. And WASM modules can talk about host references directly, rather than requiring external glue code running in the host. +WebAssembly [reference-types](https://github.com/WebAssembly/reference-types) proposal introduces two new types `funcref` and `externref`. With `externref`, It is easier and more efficient to interoperate with host environment. Host references are able to be represented directly by type `externref`. -WAMR implements the reference-types proposal, allowing developer to pass the host object to WASM application and then restore and access the host object in native lib. In WAMR internal, the external host object is represented as externref index with `uint32` type, developer must firstly map the host object of `void *` type to the externref index, and then pass the index to the function to called as the function's externref argument. +WAMR has implemented the reference-types proposal. WAMR allows a native method to pass a host object to a WASM application as an `externref` parameter or receives a host object from a WASM application as an `externref` result. Internally, WAMR won't try to parse or dereference `externref`. It is an opaque type. -Currently WAMR provides APIs as below: -```C -bool -wasm_externref_obj2ref(wasm_module_inst_t module_inst, - void *extern_obj, uint32_t *p_externref_idx); - -WASM_RUNTIME_API_EXTERN bool -wasm_externref_ref2obj(uint32_t externref_idx, void **p_extern_obj); - -WASM_RUNTIME_API_EXTERN bool -wasm_externref_retain(uint32 externref_idx); -``` - -The `wasm_externref_obj2ref()` API is used to map the host object to the externref index, and the `wasm_externref_ref2obj()` API is used to retrieve the original host object mapped. The `wasm_externref_retain()` API is to retain the host object if we don't want the object to be cleaned when it isn't used during externref object reclaim. +The restriction of using `externref` in a native method is the host object has to be the value of a `unintptr_t` variable. In other words, it takes **8 bytes** on 64-bit machine and **4 bytes** on 32-bit machines. Please keep that in mind especially when calling `wasm_runtime_call_wasm`. Please ref to the [sample](../samples/ref-types) for more details. diff --git a/product-mini/platforms/darwin/CMakeLists.txt b/product-mini/platforms/darwin/CMakeLists.txt index 5ef30eb4cb..6485b59038 100644 --- a/product-mini/platforms/darwin/CMakeLists.txt +++ b/product-mini/platforms/darwin/CMakeLists.txt @@ -15,7 +15,7 @@ set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") @@ -55,8 +55,8 @@ if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) endif () if (NOT DEFINED WAMR_BUILD_LIBC_WASI) - # Disable libc wasi support by default - set (WAMR_BUILD_LIBC_WASI 0) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 1) endif () if (NOT DEFINED WAMR_BUILD_FAST_INTERP) @@ -65,7 +65,7 @@ if (NOT DEFINED WAMR_BUILD_FAST_INTERP) endif () if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) - # Enable multiple modules + # Disable multiple module by default set (WAMR_BUILD_MULTI_MODULE 0) endif () diff --git a/product-mini/platforms/esp-idf/.gitignore b/product-mini/platforms/esp-idf/.gitignore new file mode 100644 index 0000000000..c260f41fd2 --- /dev/null +++ b/product-mini/platforms/esp-idf/.gitignore @@ -0,0 +1,2 @@ +sdkconfig +sdkconfig.old \ No newline at end of file diff --git a/product-mini/platforms/esp-idf/CMakeLists.txt b/product-mini/platforms/esp-idf/CMakeLists.txt index 0c06469c39..d8a3d2f96c 100644 --- a/product-mini/platforms/esp-idf/CMakeLists.txt +++ b/product-mini/platforms/esp-idf/CMakeLists.txt @@ -1,77 +1,12 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. +# Copyright (C) 2019-21 Intel Corporation and others. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # from ESP-IDF 4.0 examples/build_system/cmake/idf_as_lib cmake_minimum_required(VERSION 3.5) -project(wamr_on_esp32c3) -enable_language(ASM) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) -endif () +set (COMPONENTS ${IDF_TARGET} main freertos esptool_py wamr) +list(APPEND EXTRA_COMPONENT_DIRS "$ENV{WAMR_PATH}/build-scripts/esp-idf") -if("${IDF_TARGET}" STREQUAL "") - message(FATAL_ERROR "You need to set IDF_TARGET to your target string") -endif() - -# Include for ESP-IDF build system functions -include($ENV{IDF_PATH}/tools/cmake/idf.cmake) -# Create idf::esp32c3 and idf::freertos static libraries -idf_build_process(${IDF_TARGET} - # try and trim the build; additional components - # will be included as needed based on dependency tree - # - # although esptool_py does not generate static library, - # processing the component is needed for flashing related - # targets and file generation - COMPONENTS ${IDF_TARGET} freertos esptool_py - SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig - BUILD_DIR ${CMAKE_BINARY_DIR}) - -# Set WAMR's build options -if("${IDF_TARGET}" STREQUAL "esp32c3") - set(WAMR_BUILD_TARGET "RISCV32") -else() - set(WAMR_BUILD_TARGET "XTENSA") - add_compile_options(-DWAMR_BUILD_TARGET_XTENSA=1) -endif() - -set(WAMR_BUILD_PLATFORM "esp-idf") - -if (NOT DEFINED WAMR_BUILD_INTERP) - set (WAMR_BUILD_INTERP 0) -endif () - -if (NOT DEFINED WAMR_BUILD_FAST_INTERP) - set (WAMR_BUILD_FAST_INTERP 0) -endif () - -if (NOT DEFINED WAMR_BUILD_AOT) - set (WAMR_BUILD_AOT 1) -endif () - -if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) - set (WAMR_BUILD_LIBC_BUILTIN 1) -endif () - -if (NOT DEFINED WAMR_BUILD_APP_FRAMEWORK) - set (WAMR_BUILD_APP_FRAMEWORK 0) -endif () - - -# Set the compile time variable so that the right binary is selected -add_compile_options(-DWAMR_BUILD_INTERP=${WAMR_BUILD_INTERP}) - -set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) -include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) - -# define WAMR as library and provide it the esp-idf srcs -add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) -target_link_libraries(vmlib PUBLIC idf::pthread idf::${IDF_TARGET} idf::freertos) - -# Define the final executable -set(elf_file ${CMAKE_PROJECT_NAME}.elf) -add_executable(${elf_file} main.c test_wasm.h) -target_link_libraries(${elf_file} idf::${IDF_TARGET} idf::freertos idf::spi_flash vmlib) -idf_build_executable(${elf_file}) +project(wamr-simple) \ No newline at end of file diff --git a/product-mini/platforms/esp-idf/build.sh b/product-mini/platforms/esp-idf/build.sh deleted file mode 100755 index d96fe404eb..0000000000 --- a/product-mini/platforms/esp-idf/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -rm -rf build && mkdir build && cd build -cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32c3.cmake -DIDF_TARGET=esp32c3 -DCMAKE_BUILD_TYPE=Release -GNinja -cmake --build . -ninja flash diff --git a/product-mini/platforms/esp-idf/build_and_run.sh b/product-mini/platforms/esp-idf/build_and_run.sh new file mode 100755 index 0000000000..dd8dd5ca9b --- /dev/null +++ b/product-mini/platforms/esp-idf/build_and_run.sh @@ -0,0 +1,33 @@ +#!/bin/bash -e + +# Copyright (C) 2019-21 Intel Corporation and others. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +ESP32_TARGET="esp32" +ESP32C3_TARGET="esp32c3" + +usage () +{ + echo "USAGE:" + echo "$0 $ESP32_TARGET|$ESP32C3_TARGET" + echo "Example:" + echo " $0 $ESP32_TARGET" + echo " $0 $ESP32C3_TARGET" + exit 1 +} + +if [ $# != 1 ] ; then + usage +fi + +TARGET=$1 + +if [[ -z "${WAMR_PATH}" ]]; then + export WAMR_PATH=$PWD/../../.. +fi + +rm -rf build +idf.py set-target $TARGET +idf.py build +idf.py flash + diff --git a/product-mini/platforms/esp-idf/main.c b/product-mini/platforms/esp-idf/main.c deleted file mode 100644 index 4589ab80f5..0000000000 --- a/product-mini/platforms/esp-idf/main.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "wasm_export.h" -#include "bh_platform.h" -#include "test_wasm.h" - -static void * -app_instance_main(wasm_module_inst_t module_inst) -{ - const char *exception; - - wasm_application_execute_main(module_inst, 0, NULL); - if ((exception = wasm_runtime_get_exception(module_inst))) - printf("%s\n", exception); - return NULL; -} - -void * -iwasm_main(void *arg) -{ - (void)arg; /* unused */ - /* setup variables for instantiating and running the wasm module */ - uint8_t *wasm_file_buf = NULL; - unsigned wasm_file_buf_size = 0; - wasm_module_t wasm_module = NULL; - wasm_module_inst_t wasm_module_inst = NULL; - char error_buf[128]; - void *ret; - RuntimeInitArgs init_args; - - /* configure memory allocation */ - memset(&init_args, 0, sizeof(RuntimeInitArgs)); - init_args.mem_alloc_type = Alloc_With_Allocator; - init_args.mem_alloc_option.allocator.malloc_func = (void *)os_malloc; - init_args.mem_alloc_option.allocator.realloc_func = (void *)os_realloc; - init_args.mem_alloc_option.allocator.free_func = (void *)os_free; - - printf("wasm_runtime_full_init\n"); - /* initialize runtime environment */ - if (!wasm_runtime_full_init(&init_args)) { - printf("Init runtime failed.\n"); - return NULL; - } - - /* load WASM byte buffer from byte buffer of include file */ - printf("use an internal test file, that's going to output Hello World\n"); - wasm_file_buf = (uint8_t *)wasm_test_file; - wasm_file_buf_size = sizeof(wasm_test_file); - - /* load WASM module */ - if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_buf_size, - error_buf, sizeof(error_buf)))) { - printf("Error in wasm_runtime_load: %s\n", error_buf); - goto fail1; - } - - printf("about to call wasm_runtime_instantiate\n"); - if (!(wasm_module_inst = - wasm_runtime_instantiate(wasm_module, 32 * 1024, // stack size - 32 * 1024, // heap size - error_buf, sizeof(error_buf)))) { - printf("Error while instantiating: %s\n", error_buf); - goto fail2; - } - - printf("run main() of the application\n"); - ret = app_instance_main(wasm_module_inst); - assert(!ret); - - /* destroy the module instance */ - printf("wasm_runtime_deinstantiate\n"); - wasm_runtime_deinstantiate(wasm_module_inst); - -fail2: - /* unload the module */ - printf("wasm_runtime_unload\n"); - wasm_runtime_unload(wasm_module); - -fail1: - /* destroy runtime environment */ - printf("wasm_runtime_destroy\n"); - wasm_runtime_destroy(); - - return NULL; -} - -void -app_main(void) -{ - pthread_t t; - int res; - - res = pthread_create(&t, NULL, iwasm_main, (void *)NULL); - assert(res == 0); - - res = pthread_join(t, NULL); - assert(res == 0); - - printf("Exiting... \n"); -} diff --git a/product-mini/platforms/esp-idf/main/CMakeLists.txt b/product-mini/platforms/esp-idf/main/CMakeLists.txt new file mode 100644 index 0000000000..55e7256704 --- /dev/null +++ b/product-mini/platforms/esp-idf/main/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (C) 2021 Intel Corporation and others. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +idf_component_register(SRCS "main.c" + INCLUDE_DIRS "." + REQUIRES wamr) diff --git a/product-mini/platforms/esp-idf/main/main.c b/product-mini/platforms/esp-idf/main/main.c new file mode 100644 index 0000000000..d13295d834 --- /dev/null +++ b/product-mini/platforms/esp-idf/main/main.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2019-21 Intel Corporation and others. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "wasm_export.h" +#include "bh_platform.h" +#include "test_wasm.h" + +#include "esp_log.h" + +#define LOG_TAG "wamr" + +static void * +app_instance_main(wasm_module_inst_t module_inst) +{ + const char *exception; + + wasm_application_execute_main(module_inst, 0, NULL); + if ((exception = wasm_runtime_get_exception(module_inst))) + printf("%s\n", exception); + return NULL; +} + +void * +iwasm_main(void *arg) +{ + (void)arg; /* unused */ + /* setup variables for instantiating and running the wasm module */ + uint8_t *wasm_file_buf = NULL; + unsigned wasm_file_buf_size = 0; + wasm_module_t wasm_module = NULL; + wasm_module_inst_t wasm_module_inst = NULL; + char error_buf[128]; + void *ret; + RuntimeInitArgs init_args; + + /* configure memory allocation */ + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = (void *)os_malloc; + init_args.mem_alloc_option.allocator.realloc_func = (void *)os_realloc; + init_args.mem_alloc_option.allocator.free_func = (void *)os_free; + + ESP_LOGI(LOG_TAG, "Initialize WASM runtime"); + /* initialize runtime environment */ + if (!wasm_runtime_full_init(&init_args)) { + ESP_LOGE(LOG_TAG, "Init runtime failed."); + return NULL; + } + +#if WASM_ENABLE_INTERP != 0 + ESP_LOGI(LOG_TAG, "Run wamr with interpreter"); + + wasm_file_buf = (uint8_t *)wasm_test_file_interp; + wasm_file_buf_size = sizeof(wasm_test_file_interp); + + /* load WASM module */ + if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_buf_size, + error_buf, sizeof(error_buf)))) { + ESP_LOGE(LOG_TAG, "Error in wasm_runtime_load: %s", error_buf); + goto fail1interp; + } + + ESP_LOGI(LOG_TAG, "Instantiate WASM runtime"); + if (!(wasm_module_inst = + wasm_runtime_instantiate(wasm_module, 32 * 1024, // stack size + 32 * 1024, // heap size + error_buf, sizeof(error_buf)))) { + ESP_LOGE(LOG_TAG, "Error while instantiating: %s", error_buf); + goto fail2interp; + } + + ESP_LOGI(LOG_TAG, "run main() of the application"); + ret = app_instance_main(wasm_module_inst); + assert(!ret); + + /* destroy the module instance */ + ESP_LOGI(LOG_TAG, "Deinstantiate WASM runtime"); + wasm_runtime_deinstantiate(wasm_module_inst); + +fail2interp: + /* unload the module */ + ESP_LOGI(LOG_TAG, "Unload WASM module"); + wasm_runtime_unload(wasm_module); + +fail1interp: +#endif +#if WASM_ENABLE_AOT != 0 + ESP_LOGI(LOG_TAG, "Run wamr with AoT"); + + wasm_file_buf = (uint8_t *)wasm_test_file_aot; + wasm_file_buf_size = sizeof(wasm_test_file_aot); + + /* load WASM module */ + if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_buf_size, + error_buf, sizeof(error_buf)))) { + ESP_LOGE(LOG_TAG, "Error in wasm_runtime_load: %s", error_buf); + goto fail1aot; + } + + ESP_LOGI(LOG_TAG, "Instantiate WASM runtime"); + if (!(wasm_module_inst = + wasm_runtime_instantiate(wasm_module, 32 * 1024, // stack size + 32 * 1024, // heap size + error_buf, sizeof(error_buf)))) { + ESP_LOGE(LOG_TAG, "Error while instantiating: %s", error_buf); + goto fail2aot; + } + + ESP_LOGI(LOG_TAG, "run main() of the application"); + ret = app_instance_main(wasm_module_inst); + assert(!ret); + + /* destroy the module instance */ + ESP_LOGI(LOG_TAG, "Deinstantiate WASM runtime"); + wasm_runtime_deinstantiate(wasm_module_inst); + +fail2aot: + /* unload the module */ + ESP_LOGI(LOG_TAG, "Unload WASM module"); + wasm_runtime_unload(wasm_module); +fail1aot: +#endif + + /* destroy runtime environment */ + ESP_LOGI(LOG_TAG, "Destroy WASM runtime"); + wasm_runtime_destroy(); + + return NULL; +} + +void +app_main(void) +{ + pthread_t t; + int res; + + pthread_attr_t tattr; + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); + pthread_attr_setstacksize(&tattr, 4096); + + res = pthread_create(&t, &tattr, iwasm_main, (void *)NULL); + assert(res == 0); + + res = pthread_join(t, NULL); + assert(res == 0); + + ESP_LOGI(LOG_TAG, "Exiting..."); +} diff --git a/product-mini/platforms/esp-idf/test_wasm.h b/product-mini/platforms/esp-idf/main/test_wasm.h similarity index 97% rename from product-mini/platforms/esp-idf/test_wasm.h rename to product-mini/platforms/esp-idf/main/test_wasm.h index e4e648ecb9..fc2d76fdb7 100644 --- a/product-mini/platforms/esp-idf/test_wasm.h +++ b/product-mini/platforms/esp-idf/main/test_wasm.h @@ -1,16 +1,10 @@ /* - * Copyright (C) 2019 Intel Corporation. All rights reserved. + * Copyright (C) 2019-21 Intel Corporation and others. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -/** - * The byte array buffer is the file content of a test wasm binary file, - * which is compiled by wasi-sdk toolchain from C source file of: - * product-mini/app-samples/hello-world/main.c. - */ -unsigned char __aligned(4) wasm_test_file[] = { -// binary for the interpreter -#if WAMR_BUILD_INTERP != 0 +#if WASM_ENABLE_INTERP != 0 +unsigned char __aligned(4) wasm_test_file_interp[] = { 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01, 0x7F, 0x00, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x70, 0x75, @@ -45,8 +39,13 @@ unsigned char __aligned(4) wasm_test_file[] = { 0x3A, 0x20, 0x25, 0x73, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x20, 0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00 -// binary for the xtensa aot compiler -#elif WAMR_BUILD_TARGET_XTENSA != 0 +}; +#endif + +#if WASM_ENABLE_AOT != 0 +#if BUILD_TARGET_XTENSA != 0 +// XTENSA +unsigned char __aligned(4) wasm_test_file_aot[] = { 0x00, 0x61, 0x6F, 0x74, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -156,8 +155,10 @@ unsigned char __aligned(4) wasm_test_file[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00 -// binary for the riscv aot compiler +}; #else +// RISC-V +unsigned char __aligned(4) wasm_test_file_aot[] = { 0x00, 0x61, 0x6F, 0x74, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xF3, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -282,5 +283,6 @@ unsigned char __aligned(4) wasm_test_file[] = { 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xE8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 -#endif }; +#endif +#endif \ No newline at end of file diff --git a/product-mini/platforms/esp-idf/sdkconfig.defaults b/product-mini/platforms/esp-idf/sdkconfig.defaults new file mode 100644 index 0000000000..bb158eea93 --- /dev/null +++ b/product-mini/platforms/esp-idf/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +# CONFIG_ESP_SYSTEM_MEMPROT_FEATURE is not set diff --git a/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32 b/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32 new file mode 100644 index 0000000000..538ea3da1f --- /dev/null +++ b/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32 @@ -0,0 +1 @@ +# CONFIG_ESP32_MEMPROT_FEATURE is not set diff --git a/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32c3 b/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32c3 new file mode 100644 index 0000000000..29b82c4b8f --- /dev/null +++ b/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32c3 @@ -0,0 +1 @@ +# CONFIG_ESP32C3_MEMPROT_FEATURE is not set 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 25bc75258b..c20abdc14f 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -131,10 +131,11 @@ align_ptr(const uint8 *p, uint32 b) #define AOT_SECTION_TYPE_SIGANATURE 6 #define E_TYPE_XIP 4 -#define CHECK_BUF(buf, buf_end, length) \ - do { \ - if (buf + length < buf || buf + length > buf_end) \ - return false; \ +#define CHECK_BUF(buf, buf_end, length) \ + do { \ + if ((uintptr_t)buf + length < (uintptr_t)buf \ + || (uintptr_t)buf + length > (uintptr_t)buf_end) \ + return false; \ } while (0) #define read_uint16(p, p_end, res) \ @@ -162,6 +163,7 @@ is_xip_file(const uint8 *buf, uint32 size) if (get_package_type(buf, size) != Wasm_Module_AoT) return false; + CHECK_BUF(p, p_end, 8); p += 8; while (p < p_end) { @@ -172,15 +174,14 @@ is_xip_file(const uint8 *buf, uint32 size) if (section_type == AOT_SECTION_TYPE_TARGET_INFO) { p += 4; read_uint16(p, p_end, e_type); - if (e_type == E_TYPE_XIP) { - return true; - } + return (e_type == E_TYPE_XIP) ? true : false; } else if (section_type >= AOT_SECTION_TYPE_SIGANATURE) { return false; } p += section_size; } + return false; } diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index 6b739753b3..c0b6f6a8c9 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -18,7 +18,7 @@ set (CMAKE_C_STANDARD 99) # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index 0ac3fa302a..c85e2c548b 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -103,7 +103,7 @@ set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN -D_WINSOCK_DEPRECATED_NO_WARNINGS") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO") diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index dbe9acd590..6e25c4359b 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -234,6 +234,7 @@ main(int argc, char *argv[]) int log_verbose_level = 2; #endif bool is_repl_mode = false; + bool is_xip_file = false; #if WASM_ENABLE_LIBC_WASI != 0 const char *dir_list[8] = { NULL }; uint32 dir_list_size = 0; @@ -382,6 +383,27 @@ main(int argc, char *argv[]) (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size))) goto fail1; +#if WASM_ENABLE_AOT != 0 + if (wasm_runtime_is_xip_file(wasm_file_buf, wasm_file_size)) { + uint8 *wasm_file_mapped; + int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; + int map_flags = MMAP_MAP_32BIT; + + if (!(wasm_file_mapped = + os_mmap(NULL, (uint32)wasm_file_size, map_prot, map_flags))) { + printf("mmap memory failed\n"); + wasm_runtime_free(wasm_file_buf); + goto fail1; + } + + bh_memcpy_s(wasm_file_mapped, wasm_file_size, wasm_file_buf, + wasm_file_size); + wasm_runtime_free(wasm_file_buf); + wasm_file_buf = wasm_file_mapped; + is_xip_file = true; + } +#endif + #if WASM_ENABLE_MULTI_MODULE != 0 wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer); #endif @@ -422,7 +444,10 @@ main(int argc, char *argv[]) fail2: /* free the file buffer */ - wasm_runtime_free(wasm_file_buf); + if (!is_xip_file) + wasm_runtime_free(wasm_file_buf); + else + os_munmap(wasm_file_buf, wasm_file_size); fail1: /* destroy runtime environment */ diff --git a/samples/basic/CMakeLists.txt b/samples/basic/CMakeLists.txt index d8a37652d9..7e10d46094 100644 --- a/samples/basic/CMakeLists.txt +++ b/samples/basic/CMakeLists.txt @@ -26,7 +26,7 @@ set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") diff --git a/samples/multi-module/CMakeLists.txt b/samples/multi-module/CMakeLists.txt index 48f67e1bbe..e3edd0476e 100644 --- a/samples/multi-module/CMakeLists.txt +++ b/samples/multi-module/CMakeLists.txt @@ -20,7 +20,7 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") @@ -113,8 +113,8 @@ else() message(CHECK_FAIL "not found") endif() -if(NOT EXISTS ${WASI_SDK_DIR} OR NOT EXISTS ${WASI_TOOLCHAIN_FILE} OR NOT EXISTS ${WASI_SYS_ROOT}) - message(FATAL_ERROR "Please set the absolute path of wasi-sdk with \'cmake -DWASI_SDK_HOME=XXX\'") +if((NOT EXISTS ${WASI_SDK_DIR}) OR (NOT EXISTS ${WASI_TOOLCHAIN_FILE}) OR (NOT EXISTS ${WASI_SYS_ROOT})) + message(FATAL_ERROR "Please set the absolute path of wasi-sdk with \'cmake -DWASI_SDK_DIR=XXX\'") else() message(STATUS "WASI_SDK_DIR is ${WASI_SDK_DIR}") message(STATUS "WASI_TOOLCHAIN_FILE is ${WASI_TOOLCHAIN_FILE}") diff --git a/samples/multi-thread/CMakeLists.txt b/samples/multi-thread/CMakeLists.txt index 0cf2bed13e..89b59833aa 100644 --- a/samples/multi-thread/CMakeLists.txt +++ b/samples/multi-thread/CMakeLists.txt @@ -20,7 +20,7 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") diff --git a/samples/ref-types/CMakeLists.txt b/samples/ref-types/CMakeLists.txt index 1da1517ef6..229afd3c43 100644 --- a/samples/ref-types/CMakeLists.txt +++ b/samples/ref-types/CMakeLists.txt @@ -26,7 +26,7 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") @@ -116,7 +116,7 @@ endif() # wat to wasm file(GLOB WAT_FILE src/hello.wat) add_custom_target(hello_wasm ALL - COMMAND ${WAT2WASM} ${WAT_FILE} -o ${PROJECT_BINARY_DIR}/hello.wasm + COMMAND ${WAT2WASM} ${WAT_FILE} --enable-reference-types -o ${PROJECT_BINARY_DIR}/hello.wasm DEPENDS ${WAT_FILE} BYPRODUCTS ${PROJECT_BINARY_DIR}/hello.wasm VERBATIM diff --git a/samples/ref-types/src/hello.c b/samples/ref-types/src/hello.c index b353c9901b..024d026b86 100644 --- a/samples/ref-types/src/hello.c +++ b/samples/ref-types/src/hello.c @@ -13,52 +13,170 @@ static char global_heap_buf[10 * 1024 * 1024] = { 0 }; #endif -static int -test_write_wrapper(wasm_exec_env_t exec_env, uint32 externref_idx_of_file, - const char *str, int len) -{ - FILE *file; - char buf[16]; - - printf("## retrieve file handle from externref index\n"); - if (!wasm_externref_ref2obj(externref_idx_of_file, (void **)&file)) { - printf("failed to get host object from externref index!\n"); - return -1; - } +static uintptr_t global_objects[10] = { 0 }; - snprintf(buf, sizeof(buf), "%%%ds", len); - - printf("## write string to file: "); - printf(buf, str); +int32 +local_cmp_externref(wasm_exec_env_t exec_env, uintptr_t externref_a, + uintptr_t externref_b) +{ + return externref_a == externref_b; +} - return fprintf(file, buf, str); +int32 +local_chk_externref(wasm_exec_env_t exec_env, int32 index, uintptr_t externref) +{ + return externref == global_objects[index]; } /* clang-format off */ static NativeSymbol native_symbols[] = { - { "test_write", test_write_wrapper, "(i*~)i", NULL } + { "native-cmp-externref", local_cmp_externref, "(II)i", NULL }, + { "native-chk-externref", local_chk_externref, "(iI)i", NULL }, }; /* clang-format on */ +static inline void +local_set_externref(int32 index, uintptr_t externref) +{ + global_objects[index] = externref; +} + +static WASMFunctionInstanceCommon *wasm_set_externref_ptr; +static WASMFunctionInstanceCommon *wasm_get_externref_ptr; +static WASMFunctionInstanceCommon *wasm_cmp_externref_ptr; + +static bool +wasm_set_externref(wasm_exec_env_t exec_env, wasm_module_inst_t inst, + int32 index, uintptr_t externref) +{ + union { + uintptr_t val; + uint32 parts[2]; + } u; + uint32 argv[3] = { 0 }; + + if (!exec_env || !wasm_set_externref_ptr) { + return false; + } + + u.val = externref; + argv[0] = index; + argv[1] = u.parts[0]; + argv[2] = u.parts[1]; + if (!wasm_runtime_call_wasm(exec_env, wasm_set_externref_ptr, 2, argv)) { + const char *exception; + if ((exception = wasm_runtime_get_exception(inst))) { + printf("Exception: %s\n", exception); + } + return false; + } + + return true; +} + +static bool +wasm_get_externref(wasm_exec_env_t exec_env, wasm_module_inst_t inst, + int32 index, uintptr_t *ret_externref) +{ + wasm_val_t results[1] = { 0 }; + + if (!exec_env || !wasm_get_externref_ptr || !ret_externref) { + return false; + } + + if (!wasm_runtime_call_wasm_v(exec_env, wasm_get_externref_ptr, 1, results, + 1, index)) { + const char *exception; + if ((exception = wasm_runtime_get_exception(inst))) { + printf("Exception: %s\n", exception); + } + return false; + } + + if (WASM_ANYREF != results[0].kind) { + return false; + } + + *ret_externref = results[0].of.foreign; + return true; +} + +static bool +wasm_cmp_externref(wasm_exec_env_t exec_env, wasm_module_inst_t inst, + int32 index, uintptr_t externref, int32 *ret_result) +{ + wasm_val_t results[1] = { 0 }; + wasm_val_t arguments[2] = { + { .kind = WASM_I32, .of.i32 = index }, + { .kind = WASM_ANYREF, .of.foreign = externref }, + }; + + if (!exec_env || !wasm_cmp_externref_ptr || !ret_result) { + return false; + } + + if (!wasm_runtime_call_wasm_a(exec_env, wasm_cmp_externref_ptr, 1, results, + 2, arguments)) { + const char *exception; + if ((exception = wasm_runtime_get_exception(inst))) { + printf("Exception: %s\n", exception); + } + return false; + } + + if (results[0].kind != WASM_I32) { + return false; + } + + *ret_result = results[0].of.i32; + return true; +} + +static bool +set_and_cmp(wasm_exec_env_t exec_env, wasm_module_inst_t inst, int32 i, + uintptr_t externref) +{ + int32 cmp_result = 0; + uintptr_t wasm_externref = 0; + + wasm_set_externref(exec_env, inst, i, externref); + local_set_externref(i, externref); + + wasm_get_externref(exec_env, inst, 0, &wasm_externref); + if (!local_chk_externref(exec_env, 0, wasm_externref)) { + printf("#%d, In host language world Wasm Externref 0x%lx Vs. Native " + "Externref 0x%lx FAILED\n", + i, wasm_externref, externref); + return false; + } + + if (!wasm_cmp_externref(exec_env, inst, i, global_objects[i], &cmp_result) + || !cmp_result) { + printf("#%d, In Wasm world Native Externref 0x%lx Vs, Wasm Externref " + "FAILED\n", + i, global_objects[i]); + return false; + } + + return true; +} + int main(int argc, char *argv[]) { char *wasm_file = "hello.wasm"; uint8 *wasm_file_buf = NULL; - uint32 wasm_file_size, externref_idx; + uint32 wasm_file_size; uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; wasm_module_t wasm_module = NULL; wasm_module_inst_t wasm_module_inst = NULL; - wasm_function_inst_t func_inst = NULL; wasm_exec_env_t exec_env = NULL; RuntimeInitArgs init_args; char error_buf[128] = { 0 }; - const char *exce; - unsigned argv1[8]; #if WASM_ENABLE_LOG != 0 int log_verbose_level = 2; #endif - FILE *file; + const uint64 big_number = 0x123456789abc; memset(&init_args, 0, sizeof(RuntimeInitArgs)); @@ -90,13 +208,13 @@ main(int argc, char *argv[]) /* load WASM byte buffer from WASM bin file */ if (!(wasm_file_buf = (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size))) - goto fail1; + goto fail; /* load WASM module */ if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, sizeof(error_buf)))) { printf("%s\n", error_buf); - goto fail2; + goto fail; } /* instantiate the module */ @@ -104,62 +222,66 @@ main(int argc, char *argv[]) wasm_runtime_instantiate(wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf)))) { printf("%s\n", error_buf); - goto fail3; - } - - /* lookup function instance */ - if (!(func_inst = - wasm_runtime_lookup_function(wasm_module_inst, "test", NULL))) { - printf("%s\n", "lookup function test failed"); - goto fail4; + goto fail; } + /* create an execution env */ if (!(exec_env = wasm_runtime_create_exec_env(wasm_module_inst, stack_size))) { printf("%s\n", "create exec env failed"); - goto fail4; + goto fail; } - printf("## open file test.txt\n"); - if (!(file = fopen("test.txt", "wb+"))) { - printf("%s\n", "open file text.txt failed"); - goto fail5; + /* lookup function instance */ + if (!(wasm_cmp_externref_ptr = wasm_runtime_lookup_function( + wasm_module_inst, "cmp-externref", NULL))) { + printf("%s\n", "lookup function cmp-externref failed"); + goto fail; } - printf("## map file handle to externref index\n"); - if (!wasm_externref_obj2ref(wasm_module_inst, file, &externref_idx)) { - printf("%s\n", "map host object to externref index failed"); - goto fail6; + if (!(wasm_get_externref_ptr = wasm_runtime_lookup_function( + wasm_module_inst, "get-externref", NULL))) { + printf("%s\n", "lookup function get-externref failed"); + goto fail; } - printf("## call wasm function with externref index\n"); - argv1[0] = externref_idx; - wasm_runtime_call_wasm(exec_env, func_inst, 1, argv1); + if (!(wasm_set_externref_ptr = wasm_runtime_lookup_function( + wasm_module_inst, "set-externref", NULL))) { + printf("%s\n", "lookup function set-externref failed"); + goto fail; + } - if ((exce = wasm_runtime_get_exception(wasm_module_inst))) { - printf("Exception: %s\n", exce); + /* test with NULL */ + if (!set_and_cmp(exec_env, wasm_module_inst, 0, 0) + || !set_and_cmp(exec_env, wasm_module_inst, 1, big_number + 1) + || !set_and_cmp(exec_env, wasm_module_inst, 2, big_number + 2) + || !set_and_cmp(exec_env, wasm_module_inst, 3, big_number + 3)) { + goto fail; } -fail6: - fclose(file); + printf("GREAT! PASS ALL CHKs\n"); -fail5: +fail: /* destroy exec env */ - wasm_runtime_destroy_exec_env(exec_env); + if (exec_env) { + wasm_runtime_destroy_exec_env(exec_env); + } -fail4: /* destroy the module instance */ - wasm_runtime_deinstantiate(wasm_module_inst); + if (wasm_module_inst) { + wasm_runtime_deinstantiate(wasm_module_inst); + } -fail3: /* unload the module */ - wasm_runtime_unload(wasm_module); + if (wasm_module) { + wasm_runtime_unload(wasm_module); + } -fail2: /* free the file buffer */ - wasm_runtime_free(wasm_file_buf); + if (wasm_file_buf) { + wasm_runtime_free(wasm_file_buf); + } -fail1: /* destroy runtime environment */ wasm_runtime_destroy(); return 0; diff --git a/samples/ref-types/src/hello.wat b/samples/ref-types/src/hello.wat index 1a0f21db3c..3c2d2f96de 100644 --- a/samples/ref-types/src/hello.wat +++ b/samples/ref-types/src/hello.wat @@ -2,21 +2,43 @@ ;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception (module - ;; import test_write function which is implemented by host - (import "env" "test_write" - (func $test_write (param externref i32 i32) (result i32))) - - ;; memory with one page (64KiB). - (memory (export "memory") 1) - - (data (i32.const 0x8) "Hello, world!\n") - - ;; function that writes string to a given open file handle - (func (export "test") (param externref) - (local.get 0) - (i32.const 0x8) - (i32.const 14) - (call $test_write) - drop + (type $t0 (func (param i32 externref) (result i32))) + + (import "env" "native-cmp-externref" + (func $native-cmp-externref (param externref externref) (result i32)) + ) + + (import "env" "native-chk-externref" + (func $native-chk-externref (param i32 externref) (result i32)) + ) + + (table $t1 8 8 externref) + (table $t2 funcref + (elem + $native-cmp-externref + $native-chk-externref + ) + ) + + (func (export "set-externref") (param $i i32) (param $r externref) + (table.set $t1 (local.get $i) (local.get $r)) + ) + + (func (export "get-externref") (param $i i32) (result externref) + (table.get $t1 (local.get $i)) + ) + + (func (export "cmp-externref") (param $i i32) (param $r externref) (result i32) + (table.get $t1 (local.get $i)) + (local.get $r) + (call $native-cmp-externref) + ) + + (func (export "chk-externref") (param $i i32) (param $r externref) (result i32) + (call_indirect $t2 (type $t0) + (local.get $i) + (local.get $r) + (i32.const 1) + ) ) ) diff --git a/samples/spawn-thread/CMakeLists.txt b/samples/spawn-thread/CMakeLists.txt index 9fa129b219..794ec2aa21 100644 --- a/samples/spawn-thread/CMakeLists.txt +++ b/samples/spawn-thread/CMakeLists.txt @@ -20,7 +20,7 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index b855822a04..c395b627a1 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -32,7 +32,7 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" if (NOT DEFINED WAMR_BUILD_TARGET) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") set (WAMR_BUILD_TARGET "AARCH64") elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") set (WAMR_BUILD_TARGET "RISCV64") diff --git a/samples/wasm-c-api/src/callback.c b/samples/wasm-c-api/src/callback.c index b62d72894d..fc6c109db5 100644 --- a/samples/wasm-c-api/src/callback.c +++ b/samples/wasm-c-api/src/callback.c @@ -35,7 +35,7 @@ void wasm_val_print(wasm_val_t val) { // A function to be called from Wasm code. own wasm_trap_t* print_callback( - const wasm_val_vec_t *args, wasm_val_vec_t *results + const wasm_val_vec_t* args, wasm_val_vec_t* results ) { printf("Calling back...\n> "); wasm_val_print(args->data[0]); @@ -48,7 +48,7 @@ own wasm_trap_t* print_callback( // A function closure. own wasm_trap_t* closure_callback( - void* env, const wasm_val_vec_t *args, wasm_val_vec_t *results + void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results ) { int i = *(int*)env; printf("Calling back closure...\n"); @@ -113,11 +113,10 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 2, (wasm_extern_t *[]) { + wasm_extern_t* externs[] = { wasm_func_as_extern(print_func), wasm_func_as_extern(closure_func) - }); + }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -147,9 +146,10 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 2, (wasm_val_t[]){ WASM_I32_VAL(3), WASM_I32_VAL(4) }); - wasm_val_vec_new(&results, 1, (wasm_val_t[]) { WASM_INIT_VAL }); + wasm_val_t as[2] = { WASM_I32_VAL(3), WASM_I32_VAL(4) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(as); + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); return 1; @@ -159,7 +159,7 @@ int main(int argc, const char* argv[]) { // Print result. printf("Printing result...\n"); - printf("> %u\n", results.data[0].of.i32); + printf("> %u\n", rs[0].of.i32); // Shut down. printf("Shutting down...\n"); diff --git a/samples/wasm-c-api/src/callback_chain.c b/samples/wasm-c-api/src/callback_chain.c index 1b5f1b5941..64f42d960d 100644 --- a/samples/wasm-c-api/src/callback_chain.c +++ b/samples/wasm-c-api/src/callback_chain.c @@ -61,10 +61,7 @@ enum EXPORT_ITEM_NAME { DEFINE_FUNCTION(get_pairs) { - wasm_val_vec_t arg, ret; - wasm_val_vec_new(&ret, 1, (wasm_val_t []){ WASM_INIT_VAL }); - wasm_val_vec_new(&arg, 1, (wasm_val_t []){ WASM_I32_VAL(24) }); - call_wasm_function(e_malloc, &arg, &ret, "malloc"); + call_wasm_function(e_malloc, args, results, "malloc"); return NULL; } @@ -204,9 +201,6 @@ main(int argc, const char *argv[]) IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME) #undef IMPORT_FUNCTION_VARIABLE_NAME - wasm_extern_vec_t imports; - wasm_extern_vec_new_uninitialized(&imports, 10); - #define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \ { \ own wasm_functype_t *type = CREATE_FUNC_TYPE; \ @@ -219,13 +213,13 @@ main(int argc, const char *argv[]) IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION) #undef CREATE_WASM_FUNCTION + wasm_extern_t *fs[10] = {0}; #define ADD_TO_FUNCTION_LIST(name, index, ...) \ - imports.data[index] = wasm_func_as_extern(function_##name); \ - imports.num_elems += 1; + fs[index] = wasm_func_as_extern(function_##name); IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST) -#undef CREATE_IMPORT_FUNCTION - +#undef ADD_TO_FUNCTION_LIST + wasm_extern_vec_t imports = WASM_ARRAY_VEC(fs); own wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { diff --git a/samples/wasm-c-api/src/global.c b/samples/wasm-c-api/src/global.c index dab1bb49af..f16af9cc90 100644 --- a/samples/wasm-c-api/src/global.c +++ b/samples/wasm-c-api/src/global.c @@ -39,10 +39,11 @@ wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { #define check_call(func, type, expected) \ { \ - wasm_val_vec_t results; \ - wasm_val_vec_new_uninitialized(&results, 1); \ - wasm_func_call(func, NULL, &results); \ - check(results.data[0], type, expected); \ + wasm_val_t vs[1]; \ + wasm_val_vec_t args = WASM_EMPTY_VEC; \ + wasm_val_vec_t results = WASM_ARRAY_VEC(vs); \ + wasm_func_call(func, &args, &results); \ + check(vs[0], type, expected); \ } @@ -116,19 +117,13 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - /*const wasm_extern_t* imports1[] = { + wasm_extern_t* externs[] = { wasm_global_as_extern(const_f32_import), wasm_global_as_extern(const_i64_import), wasm_global_as_extern(var_f32_import), wasm_global_as_extern(var_i64_import) - };*/ - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 4, (wasm_extern_t* []) { - wasm_global_as_extern(const_f32_import), - wasm_global_as_extern(const_i64_import), - wasm_global_as_extern(var_f32_import), - wasm_global_as_extern(var_i64_import) - }); + }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -208,18 +203,19 @@ int main(int argc, const char* argv[]) { check_call(get_var_i64_export, i64, 38); // Modify variables through calls and check again. - wasm_val_vec_t args73; - wasm_val_vec_new(&args73, 1, (wasm_val_t []){ WASM_F32_VAL(73) }); - wasm_func_call(set_var_f32_import, &args73, NULL); - wasm_val_vec_t args74; - wasm_val_vec_new(&args74, 1, (wasm_val_t []){ WASM_I64_VAL(74) }); - wasm_func_call(set_var_i64_import, &args74, NULL); - wasm_val_vec_t args77; - wasm_val_vec_new(&args77, 1, (wasm_val_t []){ WASM_F32_VAL(77) }); - wasm_func_call(set_var_f32_export, &args77, NULL); - wasm_val_vec_t args78; - wasm_val_vec_new(&args78, 1, (wasm_val_t []){ WASM_I64_VAL(78) }); - wasm_func_call(set_var_i64_export, &args78, NULL); + wasm_val_vec_t res = WASM_EMPTY_VEC; + wasm_val_t vs73[] = { WASM_F32_VAL(73) }; + wasm_val_vec_t args73 = WASM_ARRAY_VEC(vs73); + wasm_func_call(set_var_f32_import, &args73, &res); + wasm_val_t vs74[] = { WASM_I64_VAL(74) }; + wasm_val_vec_t args74 = WASM_ARRAY_VEC(vs74); + wasm_func_call(set_var_i64_import, &args74, &res); + wasm_val_t vs77[] = { WASM_F32_VAL(77) }; + wasm_val_vec_t args77 = WASM_ARRAY_VEC(vs77); + wasm_func_call(set_var_f32_export, &args77, &res); + wasm_val_t vs78[] = { WASM_I64_VAL(78) }; + wasm_val_vec_t args78 = WASM_ARRAY_VEC(vs78); + wasm_func_call(set_var_i64_export, &args78, &res); check_global(var_f32_import, f32, 73); check_global(var_i64_import, i64, 74); diff --git a/samples/wasm-c-api/src/hello.c b/samples/wasm-c-api/src/hello.c index 9a6834b56f..6b566447b3 100644 --- a/samples/wasm-c-api/src/hello.c +++ b/samples/wasm-c-api/src/hello.c @@ -66,9 +66,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t* []) { wasm_func_as_extern(hello_func) }); - + wasm_extern_t* externs[] = { wasm_func_as_extern(hello_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -98,7 +97,9 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - if (wasm_func_call(run_func, NULL, NULL)) { + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); return 1; } @@ -114,4 +115,3 @@ int main(int argc, const char* argv[]) { printf("Done.\n"); return 0; } - diff --git a/samples/wasm-c-api/src/hostref.c b/samples/wasm-c-api/src/hostref.c index d802c2b661..211f0cffd0 100644 --- a/samples/wasm-c-api/src/hostref.c +++ b/samples/wasm-c-api/src/hostref.c @@ -47,21 +47,23 @@ wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) { own wasm_ref_t* call_v_r(const wasm_func_t* func) { printf("call_v_r... "); fflush(stdout); - wasm_val_vec_t rs; - wasm_val_vec_new_uninitialized(&rs, 1); - if (wasm_func_call(func, NULL, &rs)) { + wasm_val_t rs[] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } printf("okay\n"); - return rs.data[0].of.ref; + return rs[0].of.ref; } void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) { printf("call_r_v... "); fflush(stdout); - wasm_val_vec_t vs; - wasm_val_vec_new(&vs, 1, (wasm_val_t []){ WASM_REF_VAL(ref) }); - if (wasm_func_call(func, &vs, NULL)) { + wasm_val_t vs[1] = { WASM_REF_VAL(ref) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } @@ -70,22 +72,24 @@ void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) { own wasm_ref_t* call_r_r(const wasm_func_t* func, wasm_ref_t* ref) { printf("call_r_r... "); fflush(stdout); - wasm_val_vec_t vs, rs; - wasm_val_vec_new(&vs, 1, (wasm_val_t []){ WASM_REF_VAL(ref) }); - wasm_val_vec_new_uninitialized(&rs, 1); - if (wasm_func_call(func, &vs, &rs)) { + wasm_val_t vs[1] = { WASM_REF_VAL(ref) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } printf("okay\n"); - return rs.data[0].of.ref; + return rs[0].of.ref; } void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) { printf("call_ir_v... "); fflush(stdout); - wasm_val_vec_t vs; - wasm_val_vec_new(&vs, 2, (wasm_val_t []){ WASM_I32_VAL(i), WASM_REF_VAL(ref) }); - if (wasm_func_call(func, &vs, NULL)) { + wasm_val_t vs[2] = { WASM_I32_VAL(i), WASM_REF_VAL(ref) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } @@ -94,31 +98,30 @@ void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) { own wasm_ref_t* call_i_r(const wasm_func_t* func, int32_t i) { printf("call_i_r... "); fflush(stdout); - wasm_val_vec_t vs, rs; - wasm_val_vec_new(&vs, 1, (wasm_val_t []){ WASM_I32_VAL(i) }); - wasm_val_vec_new_uninitialized(&rs, 1); - if (wasm_func_call(func, &vs, &rs)) { + wasm_val_t vs[1] = { WASM_I32_VAL(i) }; + wasm_val_t rs[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + if (wasm_func_call(func, &args, &results)) { printf("> Error calling function!\n"); exit(1); } printf("okay\n"); - return rs.data[0].of.ref; + return rs[0].of.ref; } -void -check(own wasm_ref_t *actual, const wasm_ref_t *expected, bool release_ref) -{ - if (actual != expected - && !(actual && expected && wasm_ref_same(actual, expected))) { - printf("> Error reading reference, expected %p, got %p\n", - expected ? wasm_ref_get_host_info(expected) : NULL, - actual ? wasm_ref_get_host_info(actual) : NULL); - exit(1); - } - if (release_ref && actual) - wasm_ref_delete(actual); +void check(own wasm_ref_t* actual, const wasm_ref_t* expected) { + if (actual != expected && + !(actual && expected && wasm_ref_same(actual, expected))) { + printf("> Error reading reference, expected %p, got %p\n", + expected ? wasm_ref_get_host_info(expected) : NULL, + actual ? wasm_ref_get_host_info(actual) : NULL); + exit(1); + } + // if (actual) wasm_ref_delete(actual); } + int main(int argc, const char* argv[]) { // Initialize. printf("Initializing...\n"); @@ -169,8 +172,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t* []) { wasm_func_as_extern(callback_func) }); + wasm_extern_t* externs[] = { wasm_func_as_extern(callback_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -204,54 +207,61 @@ int main(int argc, const char* argv[]) { wasm_ref_set_host_info(host2, (void*)2); // Some sanity checks. - check(NULL, NULL, true); - check(wasm_ref_copy(host1), host1, true); - check(wasm_ref_copy(host2), host2, true); + check(NULL, NULL); + wasm_ref_t *host1_cp = wasm_ref_copy(host1); + wasm_ref_t *host2_cp = wasm_ref_copy(host2); + check(host1_cp, host1); + check(host2_cp, host2); + wasm_ref_delete(host1_cp); + wasm_ref_delete(host2_cp); own wasm_val_t val; val.kind = WASM_ANYREF; val.of.ref = wasm_ref_copy(host1); - check(wasm_ref_copy(val.of.ref), host1, true); - own wasm_ref_t* ref = val.of.ref; - check(wasm_ref_copy(ref), host1, true); + wasm_ref_t *ref_cp = wasm_ref_copy(val.of.ref); + check(ref_cp, host1); + check(val.of.ref, host1); wasm_ref_delete(val.of.ref); + wasm_ref_delete(ref_cp); // Interact. printf("Accessing global...\n"); - check(call_v_r(global_get), NULL, false); + check(call_v_r(global_get), NULL); call_r_v(global_set, host1); - check(call_v_r(global_get), host1, false); + check(call_v_r(global_get), host1); call_r_v(global_set, host2); - check(call_v_r(global_get), host2, false); + check(call_v_r(global_get), host2); call_r_v(global_set, NULL); - check(call_v_r(global_get), NULL, false); + check(call_v_r(global_get), NULL); wasm_global_get(global, &val); assert(val.kind == WASM_ANYREF); - check(val.of.ref, NULL, false); + assert(val.of.ref == NULL); val.of.ref = host2; wasm_global_set(global, &val); - check(call_v_r(global_get), host2, false); wasm_global_get(global, &val); assert(val.kind == WASM_ANYREF); - check(val.of.ref, host2, false); + assert(val.of.ref == host2); printf("Accessing table...\n"); - check(call_i_r(table_get, 0), NULL, false); - check(call_i_r(table_get, 1), NULL, false); + check(call_i_r(table_get, 0), NULL); + check(call_i_r(table_get, 1), NULL); call_ir_v(table_set, 0, host1); call_ir_v(table_set, 1, host2); - check(call_i_r(table_get, 0), host1, false); - check(call_i_r(table_get, 1), host2, false); + check(call_i_r(table_get, 0), host1); + check(call_i_r(table_get, 1), host2); call_ir_v(table_set, 0, NULL); - check(call_i_r(table_get, 0), NULL, false); + check(call_i_r(table_get, 0), NULL); - check(wasm_table_get(table, 2), NULL, false); + check(wasm_table_get(table, 2), NULL); + wasm_table_set(table, 2, host1); + check(call_i_r(table_get, 2), host1); + check(wasm_table_get(table, 2), host1); printf("Accessing function...\n"); - check(call_r_r(func_call, NULL), NULL, false); - check(call_r_r(func_call, host1), host1, false); - check(call_r_r(func_call, host2), host2, false); + check(call_r_r(func_call, NULL), NULL); + check(call_r_r(func_call, host1), host1); + check(call_r_r(func_call, host2), host2); wasm_ref_delete(host1); wasm_ref_delete(host2); diff --git a/samples/wasm-c-api/src/memory.c b/samples/wasm-c-api/src/memory.c index a6c17654ff..62ebe3cf1e 100644 --- a/samples/wasm-c-api/src/memory.c +++ b/samples/wasm-c-api/src/memory.c @@ -33,13 +33,10 @@ void check(bool success) { } void check_call(wasm_func_t* func, int i, wasm_val_t args[], int32_t expected) { - wasm_val_vec_t args_vec; - wasm_val_vec_t results_vec; - if (args) - wasm_val_vec_new(&args_vec, i, args); - wasm_val_vec_new(&results_vec, 1, (wasm_val_t []){ WASM_INIT_VAL }); - if (wasm_func_call(func, args ? &args_vec : NULL, &results_vec) - || results_vec.data[0].of.i32 != expected) { + wasm_val_t r[] = {WASM_INIT_VAL}; + wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; + wasm_val_vec_t results = WASM_ARRAY_VEC(r); + if (wasm_func_call(func, &args_, &results) || r[0].of.i32 != expected) { printf("> Error on result\n"); exit(1); } @@ -60,9 +57,9 @@ void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected } void check_ok(wasm_func_t* func, int i, wasm_val_t args[]) { - wasm_val_vec_t args_vec; - wasm_val_vec_new(&args_vec, i, args); - if (wasm_func_call(func, &args_vec, NULL)) { + wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; + wasm_val_vec_t results = WASM_EMPTY_VEC; + if (wasm_func_call(func, &args_, &results)) { printf("> Error on result, expected empty\n"); exit(1); } @@ -74,10 +71,10 @@ void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { } void check_trap(wasm_func_t* func, int i, wasm_val_t args[]) { - wasm_val_vec_t args_vec, results_vec; - wasm_val_vec_new(&args_vec, i, args); - wasm_val_vec_new(&results_vec, 1, (wasm_val_t []){ WASM_INIT_VAL }); - own wasm_trap_t* trap = wasm_func_call(func, &args_vec, &results_vec); + wasm_val_t r[] = {WASM_INIT_VAL}; + wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; + wasm_val_vec_t results = WASM_ARRAY_VEC(r); + own wasm_trap_t* trap = wasm_func_call(func, &args_, &results); if (! trap) { printf("> Error on result, expected trap\n"); exit(1); @@ -137,8 +134,9 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - own wasm_instance_t* instance = - wasm_instance_new_with_args(store, module, NULL, NULL, KILOBYTE(8), 0); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + own wasm_instance_t *instance = wasm_instance_new_with_args( + store, module, &imports, NULL, KILOBYTE(32), 0); if (!instance) { printf("> Error instantiating module!\n"); return 1; @@ -156,15 +154,6 @@ int main(int argc, const char* argv[]) { wasm_module_delete(module); - if (!memory || !wasm_memory_data(memory)) { - printf("> Error getting memory!\n"); - wasm_extern_vec_delete(&exports); - wasm_instance_delete(instance); - wasm_store_delete(store); - wasm_engine_delete(engine); - return 1; - } - // Try cloning. own wasm_memory_t* copy = wasm_memory_copy(memory); assert(wasm_memory_same(memory, copy)); @@ -172,13 +161,13 @@ int main(int argc, const char* argv[]) { // Check initial memory. printf("Checking memory...\n"); - check(wasm_memory_size(memory) >= 2); - check(wasm_memory_data_size(memory) >= 0x20000); + check(wasm_memory_size(memory) == 2); + check(wasm_memory_data_size(memory) == 0x20000); check(wasm_memory_data(memory)[0] == 0); check(wasm_memory_data(memory)[0x1000] == 1); check(wasm_memory_data(memory)[0x1003] == 4); - (void)size_func; + check_call0(size_func, 2); check_call1(load_func, 0, 0); check_call1(load_func, 0x1000, 1); check_call1(load_func, 0x1003, 4); diff --git a/samples/wasm-c-api/src/multi.c b/samples/wasm-c-api/src/multi.c index c4599640a5..92ef0eea77 100644 --- a/samples/wasm-c-api/src/multi.c +++ b/samples/wasm-c-api/src/multi.c @@ -9,7 +9,7 @@ // A function to be called from Wasm code. own wasm_trap_t* callback( - const wasm_val_vec_t *args, wasm_val_vec_t *results + const wasm_val_vec_t* args, wasm_val_vec_t* results ) { printf("Calling back...\n> "); printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n", @@ -27,14 +27,14 @@ own wasm_trap_t* callback( // A function closure. own wasm_trap_t* closure_callback( - void* env, const wasm_val_t args[], wasm_val_t results[] + void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results ) { int i = *(int*)env; printf("Calling back closure...\n"); printf("> %d\n", i); - results[0].kind = WASM_I32; - results[0].of.i32 = (int32_t)i; + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = (int32_t)i; return NULL; } @@ -47,7 +47,11 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE* file = fopen("multi.aot", "rb"); +#else FILE* file = fopen("multi.wasm", "rb"); +#endif if (!file) { printf("> Error loading module!\n"); return 1; @@ -91,8 +95,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t *[]) { wasm_func_as_extern(callback_func) }); + wasm_extern_t* externs[] = { wasm_func_as_extern(callback_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -121,13 +125,14 @@ int main(int argc, const char* argv[]) { // Call. printf("Calling export...\n"); - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 4, (wasm_val_t []){ - WASM_I32_VAL(1), WASM_I64_VAL(2), WASM_I64_VAL(3), WASM_I32_VAL(4) - }); - wasm_val_vec_new(&results, 4, (wasm_val_t []) { - WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL - }); + wasm_val_t vals[4] = { + WASM_I32_VAL(1), WASM_I64_VAL(2), WASM_I64_VAL(3), WASM_I32_VAL(4) + }; + wasm_val_t res[4] = { + WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL + }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vals); + wasm_val_vec_t results = WASM_ARRAY_VEC(res); if (wasm_func_call(run_func, &args, &results)) { printf("> Error calling function!\n"); return 1; @@ -138,12 +143,12 @@ int main(int argc, const char* argv[]) { // Print result. printf("Printing result...\n"); printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n", - results.data[0].of.i32, results.data[1].of.i64, results.data[2].of.i64, results.data[3].of.i32); + res[0].of.i32, res[1].of.i64, res[2].of.i64, res[3].of.i32); - assert(results.data[0].of.i32 == 1); - assert(results.data[1].of.i64 == 2); - assert(results.data[2].of.i64 == 3); - assert(results.data[3].of.i32 == 4); + assert(res[0].of.i32 == 4); + assert(res[1].of.i64 == 3); + assert(res[2].of.i64 == 2); + assert(res[3].of.i32 == 1); // Shut down. printf("Shutting down...\n"); diff --git a/samples/wasm-c-api/src/reflect.c b/samples/wasm-c-api/src/reflect.c index a90fa2aabf..915163b983 100644 --- a/samples/wasm-c-api/src/reflect.c +++ b/samples/wasm-c-api/src/reflect.c @@ -32,12 +32,6 @@ void print_valtype(const wasm_valtype_t* type) { void print_valtypes(const wasm_valtype_vec_t* types) { bool first = true; - - if (!types) { - printf("> Error print a NULL valtype\n"); - return; - } - for (size_t i = 0; i < types->size; ++i) { if (first) { first = false; @@ -49,11 +43,6 @@ void print_valtypes(const wasm_valtype_vec_t* types) { } void print_externtype(const wasm_externtype_t* type) { - if (!type) { - printf("> Error print a NULL externtype\n"); - return; - } - switch (wasm_externtype_kind(type)) { case WASM_EXTERN_FUNC: { const wasm_functype_t* functype = @@ -89,11 +78,6 @@ void print_externtype(const wasm_externtype_t* type) { } void print_name(const wasm_name_t* name) { - if (!name) { - printf("> Error print a NULL name\n"); - return; - } - printf("\"%.*s\"", (int)name->size, name->data); } @@ -139,8 +123,9 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; own wasm_instance_t* instance = - wasm_instance_new(store, module, NULL, NULL); + wasm_instance_new(store, module, &imports, NULL); if (!instance) { printf("> Error instantiating module!\n"); return 1; diff --git a/samples/wasm-c-api/src/table.c b/samples/wasm-c-api/src/table.c index 942f281cfc..739385e938 100644 --- a/samples/wasm-c-api/src/table.c +++ b/samples/wasm-c-api/src/table.c @@ -49,19 +49,21 @@ void check_table(wasm_table_t* table, int32_t i, bool expect_set) { } void check_call(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) { - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 2, (wasm_val_t []){ WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }); - wasm_val_vec_new(&results, 1, (wasm_val_t []){ WASM_INIT_VAL }); - if (wasm_func_call(func, &args, &results) || results.data[0].of.i32 != expected) { + wasm_val_t vs[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + wasm_val_t r[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(r); + if (wasm_func_call(func, &args, &results) || r[0].of.i32 != expected) { printf("> Error on result\n"); exit(1); } } void check_trap(wasm_func_t* func, int32_t arg1, int32_t arg2) { - wasm_val_vec_t args, results; - wasm_val_vec_new(&args, 2, (wasm_val_t []){ WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }); - wasm_val_vec_new(&results, 1, (wasm_val_t []){ WASM_INIT_VAL }); + wasm_val_t vs[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) }; + wasm_val_t r[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(vs); + wasm_val_vec_t results = WASM_ARRAY_VEC(r); own wasm_trap_t* trap = wasm_func_call(func, &args, &results); if (! trap) { printf("> Error on result, expected trap\n"); @@ -112,8 +114,9 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - own wasm_instance_t *instance = - wasm_instance_new(store, module, NULL, NULL); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + own wasm_instance_t* instance = + wasm_instance_new(store, module, &imports, NULL); if (!instance) { printf("> Error instantiating module!\n"); return 1; @@ -134,6 +137,7 @@ int main(int argc, const char* argv[]) { // Create external function. printf("Creating callback...\n"); own wasm_functype_t* neg_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32()); + own wasm_func_t* h = wasm_func_new(store, neg_type, neg_callback); wasm_functype_delete(neg_type); @@ -155,7 +159,9 @@ int main(int argc, const char* argv[]) { printf("Mutating table...\n"); check(wasm_table_set(table, 0, wasm_func_as_ref(g))); check(wasm_table_set(table, 1, NULL)); - check(! wasm_table_set(table, 2, wasm_func_as_ref(f))); + wasm_ref_t *ref_f = wasm_func_as_ref(f); + check(! wasm_table_set(table, 2, ref_f)); + wasm_ref_delete(ref_f); check_table(table, 0, true); check_table(table, 1, false); check_call(call_indirect, 7, 0, 666); @@ -165,6 +171,8 @@ int main(int argc, const char* argv[]) { // Grow table. // DO NOT SUPPORT printf("Bypass Growing table...\n"); + + wasm_func_delete(h); wasm_extern_vec_delete(&exports); wasm_instance_delete(instance); diff --git a/samples/wasm-c-api/src/trap.c b/samples/wasm-c-api/src/trap.c index 16dc2e0c34..5feb9511da 100644 --- a/samples/wasm-c-api/src/trap.c +++ b/samples/wasm-c-api/src/trap.c @@ -80,8 +80,8 @@ int main(int argc, const char* argv[]) { // Instantiate. printf("Instantiating module...\n"); - wasm_extern_vec_t imports; - wasm_extern_vec_new(&imports, 1, (wasm_extern_t* []) { wasm_func_as_extern(fail_func) }); + wasm_extern_t* externs[] = { wasm_func_as_extern(fail_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); own wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); if (!instance) { @@ -112,10 +112,9 @@ int main(int argc, const char* argv[]) { } printf("Calling export %d...\n", i); - - wasm_val_vec_t results; - wasm_val_vec_new_uninitialized(&results, 1); - own wasm_trap_t* trap = wasm_func_call(func, NULL, &results); + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_EMPTY_VEC; + own wasm_trap_t* trap = wasm_func_call(func, &args, &results); if (!trap) { printf("> Error calling function, expected trap!\n"); return 1; diff --git a/samples/workload/XNNPACK/CMakeLists.txt b/samples/workload/XNNPACK/CMakeLists.txt index 054d326997..1be0332682 100644 --- a/samples/workload/XNNPACK/CMakeLists.txt +++ b/samples/workload/XNNPACK/CMakeLists.txt @@ -15,6 +15,7 @@ ExternalProject_Add(xnnpack GIT_PROGRESS ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack UPDATE_COMMAND git checkout . + && git reset --hard 4d738aef36872669e4bba05a4b259149ba8e62e1 && cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/benchmark.patch ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/third_party && git apply ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack.patch CONFIGURE_COMMAND "" diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 65a102a315..e19ad6fde9 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -21,7 +21,8 @@ The script itself has to be put under the same directory with the "spec". """ -IWASM_CMD = "../../../product-mini/platforms/linux/build/iwasm" +PLATFORM_NAME = os.uname().sysname.lower() +IWASM_CMD = "../../../product-mini/platforms/" + PLATFORM_NAME + "/build/iwasm" IWASM_SGX_CMD = "../../../product-mini/platforms/linux-sgx/enclave-sample/iwasm" SPEC_TEST_DIR = "spec/test/core" WAST2WASM_CMD = "./wabt/out/gcc/Release/wat2wasm" diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index 7db0c042aa..920b0d0f36 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -141,6 +141,8 @@ def cleanup(self): os.killpg(self.p.pid, signal.SIGTERM) except OSError: pass + except IOError: + pass self.p = None self.stdin.close() if self.stdin != self.stdout: diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index f6fdf97422..8d943d97e6 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -222,6 +222,10 @@ if (NOT MSVC) endif() endif() +if (MSVC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WINSOCK_DEPRECATED_NO_WARNINGS") +endif() + # message ("-- CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") add_library (vmlib diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index c25d1ef1b7..1587d2ae14 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -79,7 +79,7 @@ main(int argc, char *argv[]) AOTCompOption option = { 0 }; char error_buf[128]; int log_verbose_level = 2; - bool sgx_mode = false; + bool sgx_mode = false, size_level_set = false; int exit_status = EXIT_FAILURE; option.opt_level = 3; @@ -133,6 +133,7 @@ main(int argc, char *argv[]) option.size_level = (uint32)atoi(argv[0] + 13); if (option.size_level > 3) option.size_level = 3; + size_level_set = true; } else if (!strcmp(argv[0], "-sgx")) { sgx_mode = true; @@ -207,6 +208,26 @@ main(int argc, char *argv[]) if (argc == 0 || !out_file_name) return print_help(); + if (!size_level_set) { + /** + * Set opt level to 1 by default for Windows and MacOS as + * they can not memory map out 0-2GB memory and might not + * be able to meet the requirements of some AOT relocation + * operations. + */ + if (option.target_abi && !strcmp(option.target_abi, "msvc")) { + LOG_VERBOSE("Set size level to 1 for Windows AOT file"); + option.size_level = 1; + } +#if defined(_WIN32) || defined(_WIN32_) || defined(__APPLE__) \ + || defined(__MACH__) + if (!option.target_abi) { + LOG_VERBOSE("Set size level to 1 for Windows or MacOS AOT file"); + option.size_level = 1; + } +#endif + } + if (sgx_mode) { option.size_level = 1; option.is_sgx_platform = true; @@ -214,6 +235,11 @@ main(int argc, char *argv[]) wasm_file_name = argv[0]; + if (!strcmp(wasm_file_name, out_file_name)) { + printf("Error: input file and output file are the same"); + return -1; + } + memset(&init_args, 0, sizeof(RuntimeInitArgs)); init_args.mem_alloc_type = Alloc_With_Allocator; @@ -236,6 +262,11 @@ main(int argc, char *argv[]) (uint8 *)bh_read_file_to_buffer(wasm_file_name, &wasm_file_size))) goto fail1; + if (get_package_type(wasm_file, wasm_file_size) != Wasm_Module_Bytecode) { + printf("Invalid file type: expected wasm file but got other\n"); + goto fail2; + } + /* load WASM module */ if (!(wasm_module = wasm_runtime_load(wasm_file, wasm_file_size, error_buf, sizeof(error_buf)))) { diff --git a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h index 3084144578..71b7fce8c4 100644 --- a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h +++ b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h @@ -6,6 +6,10 @@ #ifndef _WAMR_LIB_PTHREAD_H #define _WAMR_LIB_PTHREAD_H +#ifdef __cplusplus +extern "C" { +#endif + #include /* Data type define of pthread, mutex, cond and key */ @@ -58,4 +62,8 @@ void *pthread_getspecific(pthread_key_t key); int pthread_key_delete(pthread_key_t key); +#ifdef __cplusplus +} +#endif + #endif /* end of _WAMR_LIB_PTHREAD_H */