diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index c1c31f5f52..934e839c9b 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -19,6 +19,7 @@ on: - "samples/**" - "!samples/workload/**" - "tests/wamr-test-suites/**" + - "tests/unit/**" - "wamr-compiler/**" - "test-tools/wamr-ide/**" # will be triggered on push events @@ -36,6 +37,7 @@ on: - "samples/**" - "!samples/workload/**" - "tests/wamr-test-suites/**" + - "tests/unit/**" - "wamr-compiler/**" - "test-tools/wamr-ide/**" # allow to be triggered manually @@ -272,10 +274,73 @@ jobs: cmake --build . --config Release --parallel 4 working-directory: product-mini/platforms/${{ matrix.platform }} + build_unit_tests: + needs: + [ + build_llvm_libraries_on_ubuntu_2204, + build_wamrc + ] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04] + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-linux.tar.gz", + ] + wabt_release: + [ + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz", + ] + include: + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Get LLVM libraries + id: retrieve_llvm_libs + uses: actions/cache@v4 + with: + path: | + ./core/deps/llvm/build/bin + ./core/deps/llvm/build/include + ./core/deps/llvm/build/lib + ./core/deps/llvm/build/libexec + ./core/deps/llvm/build/share + key: ${{ matrix.llvm_cache_key }} + + - name: Quit if cache miss + if: (steps.retrieve_llvm_libs.outputs.cache-hit != 'true') + run: echo "::error::can not get prebuilt llvm libraries" && exit 1 + + - name: download and install wasi-sdk + run: | + cd /opt + sudo wget ${{ matrix.wasi_sdk_release }} + sudo tar -xzf wasi-sdk-*.tar.gz + sudo ln -sf wasi-sdk-20.0 wasi-sdk + + - name: download and install wabt + run: | + cd /opt + sudo wget ${{ matrix.wabt_release }} + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt + + - name: Build wamrc + run: | + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + working-directory: wamr-compiler + - name: Build and run unit tests run: | - mkdir build-unittests && cd build-unittests - cmake .. ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} + mkdir build && cd build + cmake .. cmake --build . --config Release --parallel 4 ctest working-directory: tests/unit diff --git a/.github/workflows/compilation_on_nuttx.yml b/.github/workflows/compilation_on_nuttx.yml index 5ff2d181cc..09bdfd324b 100644 --- a/.github/workflows/compilation_on_nuttx.yml +++ b/.github/workflows/compilation_on_nuttx.yml @@ -85,14 +85,14 @@ jobs: - name: Checkout NuttX uses: actions/checkout@v4 with: - repository: apache/incubator-nuttx + repository: apache/nuttx ref: releases/12.4 path: nuttx - name: Checkout NuttX Apps uses: actions/checkout@v4 with: - repository: apache/incubator-nuttx-apps + repository: apache/nuttx-apps ref: releases/12.4 path: apps diff --git a/.github/workflows/spec_test_on_nuttx.yml b/.github/workflows/spec_test_on_nuttx.yml index 1dbeb83483..4976cab86a 100644 --- a/.github/workflows/spec_test_on_nuttx.yml +++ b/.github/workflows/spec_test_on_nuttx.yml @@ -112,14 +112,14 @@ jobs: - name: Checkout NuttX uses: actions/checkout@v4 with: - repository: apache/incubator-nuttx + repository: apache/nuttx ref: releases/12.4 path: nuttx - name: Checkout NuttX Apps uses: actions/checkout@v4 with: - repository: apache/incubator-nuttx-apps + repository: apache/nuttx-apps ref: releases/12.4 path: apps diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index 2c83d66748..3a4afa0d2f 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -35,7 +35,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the | uvwasi | unspecified | v0.0.12 | https://github.com/nodejs/uvwasi | | | asmjit | unspecified | unspecified | https://github.com/asmjit/asmjit | | | zydis | unspecified | e14a07895136182a5b53e181eec3b1c6e0b434de | https://github.com/zyantific/zydis | | -| NuttX ELF headers | 72313301e23f9c2de969fb64b9a0f67bb4c284df | 10.3.0 | https://github.com/apache/incubator-nuttx | | +| NuttX ELF headers | 72313301e23f9c2de969fb64b9a0f67bb4c284df | 10.3.0 | https://github.com/apache/nuttx | | | Dhrystone | 2.1 | 2.1 | https://fossies.org/linux/privat/old/ | | ## Licenses diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 0721fc6383..59ce379fc8 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,101 @@ +## WAMR-2.1.0 + +### Breaking Changes + +### New Features + - Add wasm_export.h APIs to expose memory type (#3496) + - Add api to get export global instance (#3452) + - Add wasm-mutator-fuzz test (#3420) + - Implement Memory64 support for AOT (#3362) + - Add wasm module global type information APIs (#3406) + - Add aot binary analysis tool aot-analyzer (#3379) + - Expose API to get import/export function's param/result valkind (#3363) + - Add WASI support for esp-idf platform (#3348) + +### Bug Fixes + - Fix posix build when libc wasi is disabled and debug interp is enabled (#3503) + - Fix wasm_mini_loader.c build when jit or multi-module is enabled (#3502) + - Fix wasm loader check data segment count (#3492) + - Fix loader parse block type and calculate dynamic offset for loop args (#3482) + - Fix memory64 handling find_block_addr and execute_main (#3480) + - Fix two issues to make fuzzing test quit earlier (#3471) + - Fix test-wamr-ide CI failure (#3485) + - NuttX: Fix a dbus-related crash on esp32s3 (#3470) + - Clone data segments when specified with load args (#3463) + - Fix codeql compilation error (#3461) + - Fix several typos and fix bh_log calculate mills (#3441) + - ssp_config.h: Fix ifdef for android random api (#3444) + - libc-wasi: Fix a locking botch (#3437) + - Fix fast interp RECOVER_BR_INFO and local set/tee (#3434) + - aot compiler: Fix a type mismatch in compile_op_float_min_max (#3423) + - Correct Exception Handling tag type when GC is enabled (#3413) + - wasm loader: Fix handling if block without op else (#3404) + - ref-types: Correct default value for function local variables (#3397) + - aot compiler: Fix the length type passed to aot_memmove/aot_memset (#3378) + - Fix loader and mini-loader select potiential error (#3374) + - Fix aot debugger compilation error on windows (#3370) + - A few native stack detection fixes for macOS/arm64 (#3368) + - Fix ESP32-S3 compiling error (#3359) + - Fix a few native stack address calculations (#3351) + +### Enhancements + - Modify logging for windows exception handler and remove unused function (#3489) + - posix iwasm: Make the timeout logic a bit more robust (#3478) + - libc-builtin: Enhance buffered print for printf_wrapper (#3460) + - Enhance GC const initializer expression to support nested struct/array new (#3447) + - wasi: Tweak the configuration for nuttx and explain why (#3451) + - NuttX: Replace esp32s3 bits with the OS-provided APIs (#3439) + - Allow not copying the wasm binary in wasm-c-api and not referring to the binary in wasm/aot loader (#3389) + - aot: Make precheck functions use short-call for xtensa (#3418) + - Add wasm_runtime_detect_native_stack_overflow_size (#3355) + - Enhance wasm loader checks for opcode br_table (#3352) + +### Others + - Bump requests from 2.32.2 to 2.32.3 in /build-scripts (#3494) + - Enable building static library on Android platform (#3488) + - wasm-mutator-fuzz: Generate more kinds of corpus (#3487) + - Correct nuttx repo names (#3484) + - Bump requests from 2.31.0 to 2.32.2 in /build-scripts (#3474) + - wasm-mutator-fuzz: Adapt to oss-fuzz compilation (#3464) + - Add regression tests of BA issue cases (#3462) + - Add malformed test cases (#3459) + - NuttX: Rename a few recently-added nuttx options (#3449) + - wamr-test-suites: Enable AOT multi-module spec tests (#3450) + - Remove install_wasi_sdk from workload preparation script (#3445) + - Add cmake static/shared library build settings (#3443) + - Update spec test to latest commit (#3293) + - Fix typo of WAMR_CONFIGUABLE_BOUNDS_CHECKS (#3424) + - ci/coding_guidelines_check.py: Allow some well-known file names to contain '-' (#3428) + - product-mini/platforms/posix/main.c: Adapt to WASM_MEM_DUAL_BUS_MIRROR (#3427) + - Add comments to global type function declarations (#3431) + - nuttx/esp32s3: Apply ibus/dbus adjustment to internal ram 1 as well (#3421) + - Change WASM_ANYREF to WASM_EXTERNREF (#3426) + - Remove unused macros which were moved to wamr-app-framework (#3425) + - Add WASM_V128 in wasm_valkind_enum (#3412) + - Fix basic example, parameter missmatch between host and wasm (#3415) + - Fix workspaces path in build_wamr.sh (#3414) + - core/iwasm/compilation: Remove stale function prototypes (#3408) + - Add test cases for the requirements of "gc-aot" feature (#3399) + - append_aot_to_wasm.py: Add --ver-str option to emit more info in custom section name (#3398) + - Fix clang compile warnings (#3396) + - Fix some more spelling issues (#3393) + - Fix some spelling issues (#3385) + - samples/native-stack-overflow: Examine native functions with signature (#3382) + - Add some more comments on WASM_STACK_GUARD_SIZE (#3380) + - Fix typo for 'native' in wasm_export.h (#3376) + - CI: Use macos-13 instead of macos-latest (#3366) + - Test more samples in nightly-run CI (#3358) + - Random improvements to samples/native-stack-overflow (#3353) + - Reduce WASM_STACK_GUARD_SIZE a bit for posix-like platforms (#3350) + - doc: Add ADOPTERS.md (#3324) + - Update binary size info in README.md (#3030) + - core/config.h: Bump the default WASM_STACK_GUARD_SIZE (#3344) + - Add unit test suites (#3490) + - Fix internal global getter types (#3495) + - Fix CI build and run unit tests (#3499) + +--- + ## WAMR-2.0.0 ### Breaking Changes diff --git a/build-scripts/requirements.txt b/build-scripts/requirements.txt index 077c95d8a4..ef487e06e0 100644 --- a/build-scripts/requirements.txt +++ b/build-scripts/requirements.txt @@ -1 +1 @@ -requests==2.31.0 \ No newline at end of file +requests==2.32.3 \ No newline at end of file diff --git a/core/config.h b/core/config.h index b2a34b590f..2f3e401dde 100644 --- a/core/config.h +++ b/core/config.h @@ -663,4 +663,17 @@ #define WASM_MEM_ALLOC_WITH_USAGE 0 #endif +#ifndef WASM_ENABLE_FUZZ_TEST +#define WASM_ENABLE_FUZZ_TEST 0 +#endif + +#ifndef WASM_MEM_ALLOC_MAX_SIZE +#if WASM_ENABLE_FUZZ_TEST != 0 +/* In oss-fuzz, the maximum RAM is ~2.5G */ +#define WASM_MEM_ALLOC_MAX_SIZE (2U * 1024 * 1024 * 1024) +#else +#define WASM_MEM_ALLOC_MAX_SIZE UINT32_MAX +#endif +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 33e74acc8d..8d705248c5 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1043,16 +1043,16 @@ load_memory_info(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, } for (i = 0; i < module->memory_count; i++) { - read_uint32(buf, buf_end, module->memories[i].memory_flags); + read_uint32(buf, buf_end, module->memories[i].flags); - if (!wasm_memory_check_flags(module->memories[i].memory_flags, - error_buf, error_buf_size, true)) { + if (!wasm_memory_check_flags(module->memories[i].flags, error_buf, + error_buf_size, true)) { return false; } read_uint32(buf, buf_end, module->memories[i].num_bytes_per_page); - read_uint32(buf, buf_end, module->memories[i].mem_init_page_count); - read_uint32(buf, buf_end, module->memories[i].mem_max_page_count); + read_uint32(buf, buf_end, module->memories[i].init_page_count); + read_uint32(buf, buf_end, module->memories[i].max_page_count); } read_uint32(buf, buf_end, module->mem_init_data_count); @@ -3637,9 +3637,9 @@ has_module_memory64(AOTModule *module) /* TODO: multi-memories for now assuming the memory idx type is consistent * across multi-memories */ if (module->import_memory_count > 0) - return !!(module->import_memories[0].memory_flags & MEMORY64_FLAG); + return !!(module->import_memories[0].mem_type.flags & MEMORY64_FLAG); else if (module->memory_count > 0) - return !!(module->memories[0].memory_flags & MEMORY64_FLAG); + return !!(module->memories[0].flags & MEMORY64_FLAG); return false; } diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index e01b8d207d..e136613033 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -789,10 +789,9 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, { void *heap_handle; uint32 num_bytes_per_page = memory->num_bytes_per_page; - uint32 init_page_count = memory->mem_init_page_count; - uint32 max_page_count = - wasm_runtime_get_max_mem(max_memory_pages, memory->mem_init_page_count, - memory->mem_max_page_count); + uint32 init_page_count = memory->init_page_count; + uint32 max_page_count = wasm_runtime_get_max_mem( + max_memory_pages, memory->init_page_count, memory->max_page_count); uint32 default_max_pages; uint32 inc_page_count, global_idx; uint32 bytes_of_last_page, bytes_to_page_end; @@ -800,11 +799,11 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, heap_offset = (uint64)num_bytes_per_page * init_page_count; uint64 memory_data_size, max_memory_data_size; uint8 *p = NULL, *global_addr; - bool is_memory64 = memory->memory_flags & MEMORY64_FLAG; + bool is_memory64 = memory->flags & MEMORY64_FLAG; bool is_shared_memory = false; #if WASM_ENABLE_SHARED_MEMORY != 0 - is_shared_memory = memory->memory_flags & SHARED_MEMORY_FLAG ? true : false; + is_shared_memory = memory->flags & SHARED_MEMORY_FLAG ? true : false; /* Shared memory */ if (is_shared_memory && parent != NULL) { AOTMemoryInstance *shared_memory_instance; @@ -1946,7 +1945,7 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) if (!is_sub_inst) { #if WASM_ENABLE_WASI_NN != 0 - wasi_nn_destroy(module_inst); + wasi_nn_destroy((WASMModuleInstanceCommon *)module_inst); #endif wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst); } diff --git a/core/iwasm/common/gc/gc_type.c b/core/iwasm/common/gc/gc_type.c index 5ade1cb27b..c9e6d206e1 100644 --- a/core/iwasm/common/gc/gc_type.c +++ b/core/iwasm/common/gc/gc_type.c @@ -846,12 +846,6 @@ wasm_is_reftype_supers_of_func(uint8 type) return (type == REF_TYPE_FUNCREF) ? true : false; } -inline static bool -wasm_is_reftype_supers_of_extern(uint8 type) -{ - return (type == REF_TYPE_EXTERNREF) ? true : false; -} - #if WASM_ENABLE_STRINGREF != 0 inline static bool wasm_is_reftype_supers_of_string(uint8 type) diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index b7e64460ad..da3b31c952 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -201,9 +201,23 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) if (func_type->param_count) { for (i = 0; i < argc; i++) total_argv_size += (uint32)(strlen(argv[i]) + 1); - total_argv_size = align_uint(total_argv_size, 4); +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) + /* `char **argv` is an array of 64-bit elements in memory64 */ + total_argv_size = align_uint(total_argv_size, 8); + else +#endif + total_argv_size = align_uint(total_argv_size, 4); - total_size = (uint64)total_argv_size + sizeof(int32) * (uint64)argc; +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) + /* `char **argv` is an array of 64-bit elements in memory64 */ + total_size = + (uint64)total_argv_size + sizeof(uint64) * (uint64)argc; + else +#endif + total_size = + (uint64)total_argv_size + sizeof(uint32) * (uint64)argc; if (total_size >= UINT32_MAX || !(argv_buf_offset = wasm_runtime_module_malloc( @@ -219,7 +233,15 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) for (i = 0; i < argc; i++) { bh_memcpy_s(p, (uint32)(p_end - p), argv[i], (uint32)(strlen(argv[i]) + 1)); - argv_offsets[i] = (uint32)argv_buf_offset + (uint32)(p - argv_buf); +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) + /* `char **argv` is an array of 64-bit elements in memory64 */ + ((uint64 *)argv_offsets)[i] = + (uint32)argv_buf_offset + (uint32)(p - argv_buf); + else +#endif + argv_offsets[i] = + (uint32)argv_buf_offset + (uint32)(p - argv_buf); p += strlen(argv[i]) + 1; } diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 190a4beff1..2a8f266811 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -2580,8 +2580,8 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) + (i - import_func_count - import_global_count); module_name_rt = import->u.names.module_name; field_name_rt = import->u.names.field_name; - min_page = import->u.memory.init_page_count; - max_page = import->u.memory.max_page_count; + min_page = import->u.memory.mem_type.init_page_count; + max_page = import->u.memory.mem_type.max_page_count; } #endif @@ -2592,8 +2592,8 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) + (i - import_func_count - import_global_count); module_name_rt = import->module_name; field_name_rt = import->memory_name; - min_page = import->mem_init_page_count; - max_page = import->mem_max_page_count; + min_page = import->mem_type.init_page_count; + max_page = import->mem_type.max_page_count; } #endif @@ -4308,12 +4308,12 @@ wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt, AOTModule *module_aot = (AOTModule *)inst_aot->module; if (memory_idx_rt < module_aot->import_memory_count) { - min_pages = module_aot->import_memories->mem_init_page_count; - max_pages = module_aot->import_memories->mem_max_page_count; + min_pages = module_aot->import_memories->mem_type.init_page_count; + max_pages = module_aot->import_memories->mem_type.max_page_count; } else { - min_pages = module_aot->memories->mem_init_page_count; - max_pages = module_aot->memories->mem_max_page_count; + min_pages = module_aot->memories->init_page_count; + max_pages = module_aot->memories->max_page_count; } init_flag = true; } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 6f2508618c..f18cd784ae 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -384,12 +384,14 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info) return ret; } #endif + else { + LOG_WARNING("Unhandled exception thrown: exception code: 0x%lx, " + "exception address: %p, exception information: %p\n", + ExceptionRecord->ExceptionCode, + ExceptionRecord->ExceptionAddress, sig_addr); + } } - LOG_ERROR("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 */ @@ -3871,7 +3873,8 @@ wasm_runtime_get_import_type(WASMModuleCommon *const module, int32 import_index, import_type->kind = WASM_IMPORT_EXPORT_KIND_FUNC; import_type->linked = aot_import_func->func_ptr_linked ? true : false; - import_type->u.func_type = aot_import_func->func_type; + import_type->u.func_type = + (WASMFuncType *)aot_import_func->func_type; return; } @@ -3907,6 +3910,8 @@ wasm_runtime_get_import_type(WASMModuleCommon *const module, int32 import_index, import_type->name = aot_import_memory->memory_name; import_type->kind = WASM_IMPORT_EXPORT_KIND_MEMORY; import_type->linked = false; + import_type->u.memory_type = + (WASMMemoryType *)&aot_import_memory->mem_type; return; } @@ -3931,7 +3936,8 @@ wasm_runtime_get_import_type(WASMModuleCommon *const module, int32 import_index, switch (import_type->kind) { case WASM_IMPORT_EXPORT_KIND_FUNC: import_type->linked = wasm_import->u.function.func_ptr_linked; - import_type->u.func_type = wasm_import->u.function.func_type; + import_type->u.func_type = + (WASMFuncType *)wasm_import->u.function.func_type; break; case WASM_IMPORT_EXPORT_KIND_GLOBAL: import_type->linked = wasm_import->u.global.is_linked; @@ -3939,12 +3945,12 @@ wasm_runtime_get_import_type(WASMModuleCommon *const module, int32 import_index, (WASMGlobalType *)&wasm_import->u.global.type; break; case WASM_IMPORT_EXPORT_KIND_TABLE: - /* not supported */ - import_type->linked = false; + import_type->linked = false; /* not supported */ break; case WASM_IMPORT_EXPORT_KIND_MEMORY: - /* not supported */ - import_type->linked = false; + import_type->linked = false; /* not supported */ + import_type->u.memory_type = + (WASMMemoryType *)&wasm_import->u.memory.mem_type; break; default: bh_assert(0); @@ -4024,12 +4030,11 @@ wasm_runtime_get_export_type(WASMModuleCommon *const module, int32 export_index, .type; break; case WASM_IMPORT_EXPORT_KIND_TABLE: - /* not supported */ - // export_type->linked = false; break; case WASM_IMPORT_EXPORT_KIND_MEMORY: - /* not supported */ - // export_type->linked = false; + export_type->u.memory_type = + &aot_module->memories[aot_export->index + - aot_module->import_memory_count]; break; default: bh_assert(0); @@ -4066,13 +4071,13 @@ wasm_runtime_get_export_type(WASMModuleCommon *const module, int32 export_index, .type; break; case WASM_IMPORT_EXPORT_KIND_TABLE: - /* not supported */ - // export_type->linked = false; break; case WASM_IMPORT_EXPORT_KIND_MEMORY: - /* not supported */ - // export_type->linked = false; + export_type->u.memory_type = + &wasm_module->memories[wasm_export->index + - wasm_module->import_memory_count]; break; + default: bh_assert(0); break; } @@ -4168,7 +4173,7 @@ wasm_func_type_get_result_valkind(WASMFuncType *const func_type, } wasm_valkind_t -wasm_global_type_get_valkind(const wasm_global_type_t global_type) +wasm_global_type_get_valkind(WASMGlobalType *const global_type) { bh_assert(global_type); @@ -4176,13 +4181,37 @@ wasm_global_type_get_valkind(const wasm_global_type_t global_type) } bool -wasm_global_type_get_mutable(const wasm_global_type_t global_type) +wasm_global_type_get_mutable(WASMGlobalType *const global_type) { bh_assert(global_type); return global_type->is_mutable; } +bool +wasm_memory_type_get_shared(WASMMemoryType *const memory_type) +{ + bh_assert(memory_type); + + return (memory_type->flags & SHARED_MEMORY_FLAG) ? true : false; +} + +uint32 +wasm_memory_type_get_init_page_count(WASMMemoryType *const memory_type) +{ + bh_assert(memory_type); + + return memory_type->init_page_count; +} + +uint32 +wasm_memory_type_get_max_page_count(WASMMemoryType *const memory_type) +{ + bh_assert(memory_type); + + return memory_type->max_page_count; +} + bool wasm_runtime_register_natives(const char *module_name, NativeSymbol *native_symbols, @@ -6517,8 +6546,8 @@ wasm_runtime_get_export_memory_type(const WASMModuleCommon *module_comm, if (export->index < module->import_memory_count) { WASMMemoryImport *import_memory = &((module->import_memories + export->index)->u.memory); - *out_min_page = import_memory->init_page_count; - *out_max_page = import_memory->max_page_count; + *out_min_page = import_memory->mem_type.init_page_count; + *out_max_page = import_memory->mem_type.max_page_count; } else { WASMMemory *memory = @@ -6538,14 +6567,14 @@ wasm_runtime_get_export_memory_type(const WASMModuleCommon *module_comm, if (export->index < module->import_memory_count) { AOTImportMemory *import_memory = module->import_memories + export->index; - *out_min_page = import_memory->mem_init_page_count; - *out_max_page = import_memory->mem_max_page_count; + *out_min_page = import_memory->mem_type.init_page_count; + *out_max_page = import_memory->mem_type.max_page_count; } else { AOTMemory *memory = module->memories + (export->index - module->import_memory_count); - *out_min_page = memory->mem_init_page_count; - *out_max_page = memory->mem_max_page_count; + *out_min_page = memory->init_page_count; + *out_max_page = memory->max_page_count; } return true; } diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index 0d1b9028cd..33b8c0f34c 100644 --- a/core/iwasm/compilation/aot.c +++ b/core/iwasm/compilation/aot.c @@ -558,28 +558,24 @@ aot_create_comp_data(WASMModule *module, const char *target_arch, /* Set memory page count */ for (i = 0; i < module->import_memory_count + module->memory_count; i++) { if (i < module->import_memory_count) { - comp_data->memories[i].memory_flags = - module->import_memories[i].u.memory.flags; + comp_data->memories[i].flags = + module->import_memories[i].u.memory.mem_type.flags; comp_data->memories[i].num_bytes_per_page = - module->import_memories[i].u.memory.num_bytes_per_page; - comp_data->memories[i].mem_init_page_count = - module->import_memories[i].u.memory.init_page_count; - comp_data->memories[i].mem_max_page_count = - module->import_memories[i].u.memory.max_page_count; - comp_data->memories[i].num_bytes_per_page = - module->import_memories[i].u.memory.num_bytes_per_page; + module->import_memories[i].u.memory.mem_type.num_bytes_per_page; + comp_data->memories[i].init_page_count = + module->import_memories[i].u.memory.mem_type.init_page_count; + comp_data->memories[i].max_page_count = + module->import_memories[i].u.memory.mem_type.max_page_count; } else { j = i - module->import_memory_count; - comp_data->memories[i].memory_flags = module->memories[j].flags; + comp_data->memories[i].flags = module->memories[j].flags; comp_data->memories[i].num_bytes_per_page = module->memories[j].num_bytes_per_page; - comp_data->memories[i].mem_init_page_count = + comp_data->memories[i].init_page_count = module->memories[j].init_page_count; - comp_data->memories[i].mem_max_page_count = + comp_data->memories[i].max_page_count = module->memories[j].max_page_count; - comp_data->memories[i].num_bytes_per_page = - module->memories[j].num_bytes_per_page; } } diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index ae04dfbc78..94e34113b4 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -46,6 +46,8 @@ typedef WASMStructType AOTStructType; typedef WASMArrayType AOTArrayType; #endif typedef WASMExport AOTExport; +typedef WASMMemory AOTMemory; +typedef WASMMemoryType AOTMemoryType; #if WASM_ENABLE_DEBUG_AOT != 0 typedef void *dwarf_extractor_handle_t; @@ -81,23 +83,9 @@ typedef enum AOTFloatCond { typedef struct AOTImportMemory { char *module_name; char *memory_name; - uint32 memory_flags; - uint32 num_bytes_per_page; - uint32 mem_init_page_count; - uint32 mem_max_page_count; + AOTMemoryType mem_type; } AOTImportMemory; -/** - * Memory information - */ -typedef struct AOTMemory { - /* memory info */ - uint32 memory_flags; - uint32 num_bytes_per_page; - uint32 mem_init_page_count; - uint32 mem_max_page_count; -} AOTMemory; - /** * A segment of memory init data */ diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 5c66e0fe82..96ed8facfe 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -1028,7 +1028,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) } else { frame_ip--; - read_leb_uint32(frame_ip, frame_ip_end, type_index); + read_leb_int32(frame_ip, frame_ip_end, type_index); + /* type index was checked in wasm loader */ + bh_assert(type_index < comp_ctx->comp_data->type_count); func_type = (AOTFuncType *)comp_ctx->comp_data->types[type_index]; param_count = func_type->param_count; @@ -1048,7 +1050,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case EXT_OP_LOOP: case EXT_OP_IF: { - read_leb_uint32(frame_ip, frame_ip_end, type_index); + read_leb_int32(frame_ip, frame_ip_end, type_index); + /* type index was checked in wasm loader */ + bh_assert(type_index < comp_ctx->comp_data->type_count); func_type = (AOTFuncType *)comp_ctx->comp_data->types[type_index]; param_count = func_type->param_count; diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index f9016ac6b1..06dc77212d 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -520,8 +520,7 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type) } while (0) #if WASM_ENABLE_MEMORY64 != 0 -#define IS_MEMORY64 \ - (comp_ctx->comp_data->memories[0].memory_flags & MEMORY64_FLAG) +#define IS_MEMORY64 (comp_ctx->comp_data->memories[0].flags & MEMORY64_FLAG) #define MEMORY64_COND_VALUE(VAL_IF_ENABLED, VAL_IF_DISABLED) \ (IS_MEMORY64 ? VAL_IF_ENABLED : VAL_IF_DISABLED) #else diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 70fd2efac8..1c5906a8eb 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -189,7 +189,7 @@ get_import_memory_size(AOTCompData *comp_data) static uint32 get_memory_size(AOTCompData *comp_data) { - /* memory_count + count * (memory_flags + num_bytes_per_page + + /* memory_count + count * (flags + num_bytes_per_page + init_page_count + max_page_count) */ return (uint32)(sizeof(uint32) + comp_data->memory_count * sizeof(uint32) * 4); @@ -1762,10 +1762,10 @@ aot_emit_mem_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, EMIT_U32(comp_data->memory_count); /* Emit memory items */ for (i = 0; i < comp_data->memory_count; i++) { - EMIT_U32(comp_data->memories[i].memory_flags); + EMIT_U32(comp_data->memories[i].flags); EMIT_U32(comp_data->memories[i].num_bytes_per_page); - EMIT_U32(comp_data->memories[i].mem_init_page_count); - EMIT_U32(comp_data->memories[i].mem_max_page_count); + EMIT_U32(comp_data->memories[i].init_page_count); + EMIT_U32(comp_data->memories[i].max_page_count); } /* Emit mem init data count */ diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 24511ffd04..7d73d8d906 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -853,7 +853,7 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMBasicBlockRef terminate_block, non_terminate_block; AOTFuncType *aot_func_type = func_ctx->aot_func->func_type; bool is_shared_memory = - comp_ctx->comp_data->memories[0].memory_flags & 0x02 ? true : false; + comp_ctx->comp_data->memories[0].flags & 0x02 ? true : false; /* Only need to check the suspend flags when memory is shared since shared memory must be enabled for multi-threading */ diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index a506f2a780..506467449b 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -109,7 +109,7 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool is_target_64bit, is_local_of_aot_value = false; #if WASM_ENABLE_SHARED_MEMORY != 0 bool is_shared_memory = - comp_ctx->comp_data->memories[0].memory_flags & SHARED_MEMORY_FLAG; + comp_ctx->comp_data->memories[0].flags & SHARED_MEMORY_FLAG; #endif is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false; @@ -177,7 +177,7 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 num_bytes_per_page = comp_ctx->comp_data->memories[0].num_bytes_per_page; uint32 init_page_count = - comp_ctx->comp_data->memories[0].mem_init_page_count; + comp_ctx->comp_data->memories[0].init_page_count; uint64 mem_data_size = (uint64)num_bytes_per_page * init_page_count; if (mem_offset + bytes <= mem_data_size) { @@ -224,7 +224,7 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, && aot_checked_addr_list_find(func_ctx, local_idx_of_aot_value, offset, bytes))) { uint32 init_page_count = - comp_ctx->comp_data->memories[0].mem_init_page_count; + comp_ctx->comp_data->memories[0].init_page_count; if (init_page_count == 0) { LLVMValueRef mem_size; @@ -932,8 +932,7 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Get memory base address and memory data size */ #if WASM_ENABLE_SHARED_MEMORY != 0 - bool is_shared_memory = - comp_ctx->comp_data->memories[0].memory_flags & 0x02; + bool is_shared_memory = comp_ctx->comp_data->memories[0].flags & 0x02; if (func_ctx->mem_space_unchanged || is_shared_memory) { #else @@ -961,7 +960,7 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 num_bytes_per_page = comp_ctx->comp_data->memories[0].num_bytes_per_page; uint32 init_page_count = - comp_ctx->comp_data->memories[0].mem_init_page_count; + comp_ctx->comp_data->memories[0].init_page_count; uint64 mem_data_size = (uint64)num_bytes_per_page * init_page_count; if (mem_data_size > 0 && mem_offset + mem_len <= mem_data_size) { /* inside memory space */ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index bda8ee3b72..df07c3ca6c 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1219,7 +1219,7 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Load memory base address */ #if WASM_ENABLE_SHARED_MEMORY != 0 is_shared_memory = - comp_ctx->comp_data->memories[0].memory_flags & 0x02 ? true : false; + comp_ctx->comp_data->memories[0].flags & 0x02 ? true : false; if (is_shared_memory) { LLVMValueRef shared_mem_addr; offset = I32_CONST(offsetof(AOTModuleInstance, memories)); diff --git a/core/iwasm/fast-jit/jit_frontend.c b/core/iwasm/fast-jit/jit_frontend.c index 092f9c0c74..a8e87c92bc 100644 --- a/core/iwasm/fast-jit/jit_frontend.c +++ b/core/iwasm/fast-jit/jit_frontend.c @@ -234,7 +234,7 @@ is_shared_memory(WASMModule *module, uint32 mem_idx) if (mem_idx < module->import_memory_count) { memory_import = &(module->import_memories[mem_idx].u.memory); - is_shared = memory_import->flags & 0x02 ? true : false; + is_shared = memory_import->mem_type.flags & 0x02 ? true : false; } else { memory = &module->memories[mem_idx - module->import_memory_count]; @@ -1510,7 +1510,9 @@ jit_compile_func(JitCompContext *cc) case EXT_OP_LOOP: case EXT_OP_IF: { - read_leb_uint32(frame_ip, frame_ip_end, type_idx); + read_leb_int32(frame_ip, frame_ip_end, type_idx); + /* type index was checked in wasm loader */ + bh_assert(type_idx < cc->cur_wasm_module->type_count); func_type = cc->cur_wasm_module->types[type_idx]; param_count = func_type->param_count; param_types = func_type->types; diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 2dd1eb9055..85fd522d7d 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -78,6 +78,10 @@ typedef struct WASMFuncType *wasm_func_type_t; struct WASMGlobalType; typedef struct WASMGlobalType *wasm_global_type_t; +struct WASMMemory; +typedef struct WASMMemory WASMMemoryType; +typedef WASMMemoryType *wasm_memory_type_t; + typedef struct wasm_import_t { const char *module_name; const char *name; @@ -86,6 +90,7 @@ typedef struct wasm_import_t { union { wasm_func_type_t func_type; wasm_global_type_t global_type; + wasm_memory_type_t memory_type; } u; } wasm_import_t; @@ -95,6 +100,7 @@ typedef struct wasm_export_t { union { wasm_func_type_t func_type; wasm_global_type_t global_type; + wasm_memory_type_t memory_type; } u; } wasm_export_t; @@ -1350,6 +1356,36 @@ wasm_global_type_get_valkind(const wasm_global_type_t global_type); WASM_RUNTIME_API_EXTERN bool wasm_global_type_get_mutable(const wasm_global_type_t global_type); +/** + * Get the shared setting for a memory type + * + * @param memory_type the memory type + * + * @return true if shared, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_memory_type_get_shared(const wasm_memory_type_t memory_type); + +/** + * Get the initial page count for a memory type + * + * @param memory_type the memory type + * + * @return the initial memory page count + */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_memory_type_get_init_page_count(const wasm_memory_type_t memory_type); + +/** + * Get the maximum page count for a memory type + * + * @param memory_type the memory type + * + * @return the maximum memory page count + */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_memory_type_get_max_page_count(const wasm_memory_type_t memory_type); + /** * Register native functions with same module name * diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 1f6ca6deb9..4bd6505293 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -512,7 +512,7 @@ typedef struct WASMMemory { uint32 num_bytes_per_page; uint32 init_page_count; uint32 max_page_count; -} WASMMemory; +} WASMMemory, WASMMemoryType; typedef struct WASMTableImport { char *module_name; @@ -536,10 +536,7 @@ typedef struct WASMTableImport { typedef struct WASMMemoryImport { char *module_name; char *field_name; - uint32 flags; - uint32 num_bytes_per_page; - uint32 init_page_count; - uint32 max_page_count; + WASMMemoryType mem_type; #if WASM_ENABLE_MULTI_MODULE != 0 WASMModule *import_module; WASMMemory *import_memory_linked; diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index df6aa73a2e..8250792494 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -3446,10 +3446,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { /* clang-format off */ #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 - local_offset = *frame_ip++; + local_offset = *frame_ip++; #else - local_offset = *frame_ip; - frame_ip += 2; + local_offset = *frame_ip; + frame_ip += 2; #endif /* clang-format on */ *(uint32 *)(frame_lp + local_offset) = @@ -3463,10 +3463,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { /* clang-format off */ #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 - local_offset = *frame_ip++; + local_offset = *frame_ip++; #else - local_offset = *frame_ip; - frame_ip += 2; + local_offset = *frame_ip; + frame_ip += 2; #endif /* clang-format on */ PUT_I64_TO_ADDR((uint32 *)(frame_lp + local_offset), diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 40bf135b6b..bf117dd828 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -44,7 +44,8 @@ has_module_memory64(WASMModule *module) /* TODO: multi-memories for now assuming the memory idx type is consistent * across multi-memories */ if (module->import_memory_count > 0) - return !!(module->import_memories[0].u.memory.flags & MEMORY64_FLAG); + return !!(module->import_memories[0].u.memory.mem_type.flags + & MEMORY64_FLAG); else if (module->memory_count > 0) return !!(module->memories[0].flags & MEMORY64_FLAG); @@ -379,7 +380,8 @@ loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) { void *mem; - if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) { + if (size >= WASM_MEM_ALLOC_MAX_SIZE + || !(mem = wasm_runtime_malloc((uint32)size))) { set_error_buf(error_buf, error_buf_size, "allocate memory failed"); return NULL; } @@ -2934,10 +2936,10 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, } /* now we believe all declaration are ok */ - memory->flags = mem_flag; - memory->init_page_count = declare_init_page_count; - memory->max_page_count = declare_max_page_count; - memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; + memory->mem_type.flags = mem_flag; + memory->mem_type.init_page_count = declare_init_page_count; + memory->mem_type.max_page_count = declare_max_page_count; + memory->mem_type.num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; *p_buf = p; @@ -3052,7 +3054,12 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, #if WASM_ENABLE_GC == 0 CHECK_BUF(p, p_end, 2); + /* global type */ declare_type = read_uint8(p); + if (!is_value_type(declare_type)) { + set_error_buf(error_buf, error_buf_size, "type mismatch"); + return false; + } declare_mutable = read_uint8(p); #else if (!resolve_value_type(&p, p_end, parent_module, parent_module->type_count, @@ -4034,7 +4041,12 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, for (i = 0; i < global_count; i++, global++) { #if WASM_ENABLE_GC == 0 CHECK_BUF(p, p_end, 2); + /* global type */ global->type.val_type = read_uint8(p); + if (!is_value_type(global->type.val_type)) { + set_error_buf(error_buf, error_buf_size, "type mismatch"); + return false; + } mutable = read_uint8(p); #else if (!resolve_value_type(&p, p_end, module, module->type_count, @@ -4705,8 +4717,12 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, static bool load_data_segment_section(const uint8 *buf, const uint8 *buf_end, - WASMModule *module, bool clone_data_seg, - char *error_buf, uint32 error_buf_size) + WASMModule *module, +#if WASM_ENABLE_BULK_MEMORY != 0 + bool has_datacount_section, +#endif + bool clone_data_seg, char *error_buf, + uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; uint32 data_seg_count, i, mem_index, data_seg_len; @@ -4722,8 +4738,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, read_leb_uint32(p, p_end, data_seg_count); #if WASM_ENABLE_BULK_MEMORY != 0 - if ((module->data_seg_count1 != 0) - && (data_seg_count != module->data_seg_count1)) { + if (has_datacount_section && data_seg_count != module->data_seg_count1) { set_error_buf(error_buf, error_buf_size, "data count and data section have inconsistent lengths"); return false; @@ -4791,8 +4806,8 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, /* This memory_flag is from memory instead of data segment */ uint8 memory_flag; if (module->import_memory_count > 0) { - memory_flag = - module->import_memories[mem_index].u.memory.flags; + memory_flag = module->import_memories[mem_index] + .u.memory.mem_type.flags; } else { memory_flag = @@ -5231,10 +5246,11 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, module->name_section_buf = buf; module->name_section_buf_end = buf_end; p += name_len; - handle_name_section(p, p_end, module, is_load_from_file_buf, error_buf, - error_buf_size); + if (!handle_name_section(p, p_end, module, is_load_from_file_buf, + error_buf, error_buf_size)) { + return false; + } LOG_VERBOSE("Load custom name section success."); - return true; } #endif @@ -5778,6 +5794,9 @@ load_from_sections(WASMModule *module, WASMSection *sections, uint8 malloc_free_io_type = VALUE_TYPE_I32; bool reuse_const_strings = is_load_from_file_buf && !wasm_binary_freeable; bool clone_data_seg = is_load_from_file_buf && wasm_binary_freeable; +#if WASM_ENABLE_BULK_MEMORY != 0 + bool has_datacount_section = false; +#endif /* Find code and function sections if have */ while (section) { @@ -5870,6 +5889,9 @@ load_from_sections(WASMModule *module, WASMSection *sections, break; case SECTION_TYPE_DATA: if (!load_data_segment_section(buf, buf_end, module, +#if WASM_ENABLE_BULK_MEMORY != 0 + has_datacount_section, +#endif clone_data_seg, error_buf, error_buf_size)) return false; @@ -5879,6 +5901,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, if (!load_datacount_section(buf, buf_end, module, error_buf, error_buf_size)) return false; + has_datacount_section = true; break; #endif #if WASM_ENABLE_STRINGREF != 0 @@ -6131,13 +6154,14 @@ load_from_sections(WASMModule *module, WASMSection *sections, if (shrunk_memory_size <= UINT32_MAX) { if (module->import_memory_count) { memory_import = &module->import_memories[0].u.memory; - init_memory_size = (uint64)memory_import->num_bytes_per_page - * memory_import->init_page_count; + init_memory_size = + (uint64)memory_import->mem_type.num_bytes_per_page + * memory_import->mem_type.init_page_count; if (shrunk_memory_size <= init_memory_size) { /* Reset memory info to decrease memory usage */ - memory_import->num_bytes_per_page = + memory_import->mem_type.num_bytes_per_page = (uint32)shrunk_memory_size; - memory_import->init_page_count = 1; + memory_import->mem_type.init_page_count = 1; LOG_VERBOSE("Shrink import memory size to %" PRIu64, shrunk_memory_size); } @@ -6163,16 +6187,16 @@ load_from_sections(WASMModule *module, WASMSection *sections, memory_import = &module->import_memories[0].u.memory; /* Only resize the memory to one big page if num_bytes_per_page is * in valid range of uint32 */ - if (memory_import->init_page_count < DEFAULT_MAX_PAGES) { - memory_import->num_bytes_per_page *= - memory_import->init_page_count; + if (memory_import->mem_type.init_page_count < DEFAULT_MAX_PAGES) { + memory_import->mem_type.num_bytes_per_page *= + memory_import->mem_type.init_page_count; - if (memory_import->init_page_count > 0) - memory_import->init_page_count = - memory_import->max_page_count = 1; + if (memory_import->mem_type.init_page_count > 0) + memory_import->mem_type.init_page_count = + memory_import->mem_type.max_page_count = 1; else - memory_import->init_page_count = - memory_import->max_page_count = 0; + memory_import->mem_type.init_page_count = + memory_import->mem_type.max_page_count = 0; } } if (module->memory_count) { @@ -6403,7 +6427,7 @@ create_sections(const uint8 *buf, uint32 size, WASMSection **p_section_list, char *error_buf, uint32 error_buf_size) { WASMSection *section_list_end = NULL, *section; - const uint8 *p = buf, *p_end = buf + size /*, *section_body*/; + const uint8 *p = buf, *p_end = buf + size; uint8 section_type, section_index, last_section_index = (uint8)-1; uint32 section_size; @@ -7075,7 +7099,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, } else { p--; - skip_leb_uint32(p, p_end); + /* block type */ + skip_leb_int32(p, p_end); } if (block_nested_depth < sizeof(block_stack) / sizeof(BlockAddr)) { @@ -7090,7 +7115,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case EXT_OP_LOOP: case EXT_OP_IF: /* block type */ - skip_leb_uint32(p, p_end); + skip_leb_int32(p, p_end); if (block_nested_depth < sizeof(block_stack) / sizeof(BlockAddr)) { block_stack[block_nested_depth].start_addr = p; @@ -7647,7 +7672,6 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) case WASM_OP_SIMD_PREFIX: { - /* TODO: memory64 offset type changes */ uint32 opcode1; read_leb_uint32(p, p_end, opcode1); @@ -7672,8 +7696,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case SIMD_v128_store: /* memarg align */ skip_leb_uint32(p, p_end); - /* memarg offset*/ - skip_leb_uint32(p, p_end); + /* memarg offset */ + skip_leb_mem_offset(p, p_end); break; case SIMD_v128_const: @@ -7712,8 +7736,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case SIMD_v128_store64_lane: /* memarg align */ skip_leb_uint32(p, p_end); - /* memarg offset*/ - skip_leb_uint32(p, p_end); + /* memarg offset */ + skip_leb_mem_offset(p, p_end); /* ImmLaneId */ CHECK_BUF(p, p_end, 1); p++; @@ -7723,8 +7747,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case SIMD_v128_load64_zero: /* memarg align */ skip_leb_uint32(p, p_end); - /* memarg offset*/ - skip_leb_uint32(p, p_end); + /* memarg offset */ + skip_leb_mem_offset(p, p_end); break; default: @@ -7840,7 +7864,11 @@ typedef struct BranchBlock { BranchBlockPatch *patch_list; /* This is used to save params frame_offset of of if block */ int16 *param_frame_offsets; - /* This is used to recover dynamic offset for else branch */ + /* This is used to recover the dynamic offset for else branch, + * and also to remember the start offset of dynamic space which + * stores the block arguments for loop block, so we can use it + * to copy the stack operands to the loop block's arguments in + * wasm_loader_emit_br_info for opcode br. */ uint16 start_dynamic_offset; #endif @@ -7991,13 +8019,26 @@ static void free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num) { BranchBlock *tmp_csp = frame_csp; + uint32 i; - for (uint32 i = 0; i < csp_num; i++) { + for (i = 0; i < csp_num; i++) { free_label_patch_list(tmp_csp); tmp_csp++; } } +static void +free_all_label_param_frame_offsets(BranchBlock *frame_csp, uint32 csp_num) +{ + BranchBlock *tmp_csp = frame_csp; + uint32 i; + + for (i = 0; i < csp_num; i++) { + if (tmp_csp->param_frame_offsets) + wasm_runtime_free(tmp_csp->param_frame_offsets); + tmp_csp++; + } +} #endif /* end of WASM_ENABLE_FAST_INTERP */ #if WASM_ENABLE_GC != 0 @@ -8116,6 +8157,8 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx) if (ctx->frame_csp_bottom) { #if WASM_ENABLE_FAST_INTERP != 0 free_all_label_patch_lists(ctx->frame_csp_bottom, ctx->csp_num); + free_all_label_param_frame_offsets(ctx->frame_csp_bottom, + ctx->csp_num); #endif #if WASM_ENABLE_GC != 0 wasm_loader_clean_all_local_use_masks(ctx); @@ -9228,8 +9271,14 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, emit_operand(ctx, *(int16 *)(frame_offset)); } /* Part e */ - dynamic_offset = - frame_csp->dynamic_offset + wasm_get_cell_num(types, arity); + if (frame_csp->label_type == LABEL_TYPE_LOOP) + /* Use start_dynamic_offset which was set in + copy_params_to_dynamic_space */ + dynamic_offset = frame_csp->start_dynamic_offset + + wasm_get_cell_num(types, arity); + else + dynamic_offset = + frame_csp->dynamic_offset + wasm_get_cell_num(types, arity); if (is_br) ctx->dynamic_offset = dynamic_offset; for (i = (int32)arity - 1; i >= 0; i--) { @@ -10613,8 +10662,8 @@ check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block, * Part e: each param's dst offset */ static bool -copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, - char *error_buf, uint32 error_buf_size) +copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, char *error_buf, + uint32 error_buf_size) { bool ret = false; int16 *frame_offset = NULL; @@ -10628,6 +10677,7 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, uint32 param_count = block_type->u.type->param_count; int16 condition_offset = 0; bool disable_emit = false; + bool is_if_block = (block->label_type == LABEL_TYPE_IF ? true : false); int16 operand_offset = 0; uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets)); @@ -10680,6 +10730,14 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, if (is_if_block) emit_operand(loader_ctx, condition_offset); + /* Since the start offset to save the block's params and + * the start offset to save the block's results may be + * different, we remember the dynamic offset for loop block + * so that we can use it to copy the stack operands to the + * loop block's params in wasm_loader_emit_br_info. */ + if (block->label_type == LABEL_TYPE_LOOP) + block->start_dynamic_offset = loader_ctx->dynamic_offset; + /* Part e) */ /* Push to dynamic space. The push will emit the dst offset. */ for (i = 0; i < param_count; i++) @@ -11052,12 +11110,12 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, #endif /* end of WASM_ENABLE_GC != 0 */ } else { - uint32 type_index; + int32 type_index; /* Resolve the leb128 encoded type index as block type */ p--; p_org = p - 1; - read_leb_uint32(p, p_end, type_index); - if (type_index >= module->type_count) { + read_leb_int32(p, p_end, type_index); + if ((uint32)type_index >= module->type_count) { set_error_buf(error_buf, error_buf_size, "unknown type"); goto fail; @@ -11161,8 +11219,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, if (BLOCK_HAS_PARAM(block_type)) { /* Make sure params are in dynamic space */ - if (!copy_params_to_dynamic_space( - loader_ctx, false, error_buf, error_buf_size)) + if (!copy_params_to_dynamic_space(loader_ctx, error_buf, + error_buf_size)) goto fail; } @@ -11208,8 +11266,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, /* skip the if label */ skip_label(); /* Emit a copy instruction */ - if (!copy_params_to_dynamic_space( - loader_ctx, true, error_buf, error_buf_size)) + if (!copy_params_to_dynamic_space(loader_ctx, error_buf, + error_buf_size)) goto fail; /* Emit the if instruction */ diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index c0966aad27..41d137c253 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -33,7 +33,7 @@ has_module_memory64(WASMModule *module) /* TODO: multi-memories for now assuming the memory idx type is consistent * across multi-memories */ if (module->import_memory_count > 0) - return !!(module->import_memories[0].u.memory.flags & MEMORY64_FLAG); + return !!(module->import_memories[0].u.mem_type.flags & MEMORY64_FLAG); else if (module->memory_count > 0) return !!(module->memories[0].flags & MEMORY64_FLAG); @@ -761,10 +761,10 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, } /* now we believe all declaration are ok */ - memory->flags = mem_flag; - memory->init_page_count = declare_init_page_count; - memory->max_page_count = declare_max_page_count; - memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; + memory->mem_type.flags = mem_flag; + memory->mem_type.init_page_count = declare_init_page_count; + memory->mem_type.max_page_count = declare_max_page_count; + memory->mem_type.num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; *p_buf = p; return true; @@ -1740,8 +1740,12 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, static bool load_data_segment_section(const uint8 *buf, const uint8 *buf_end, - WASMModule *module, bool clone_data_seg, - char *error_buf, uint32 error_buf_size) + WASMModule *module, +#if WASM_ENABLE_BULK_MEMORY != 0 + bool has_datacount_section, +#endif + bool clone_data_seg, char *error_buf, + uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; uint32 data_seg_count, i, mem_index, data_seg_len; @@ -1757,7 +1761,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, read_leb_uint32(p, p_end, data_seg_count); #if WASM_ENABLE_BULK_MEMORY != 0 - bh_assert(module->data_seg_count1 == 0 + bh_assert(!has_datacount_section || data_seg_count == module->data_seg_count1); #endif @@ -1808,7 +1812,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, uint8 memory_flag; if (module->import_memory_count > 0) { memory_flag = - module->import_memories[mem_index].u.memory.flags; + module->import_memories[mem_index].u.mem_type.flags; } else { memory_flag = @@ -2029,8 +2033,10 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 if (name_len == 4 && memcmp(p, "name", 4) == 0) { p += name_len; - handle_name_section(p, p_end, module, is_load_from_file_buf, error_buf, - error_buf_size); + if (!handle_name_section(p, p_end, module, is_load_from_file_buf, + error_buf, error_buf_size)) { + return false; + } } #endif LOG_VERBOSE("Load custom section success.\n"); @@ -2108,7 +2114,7 @@ static bool init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, uint32 error_buf_size) { - LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options(); + LLVMJITOptions *llvm_jit_options = wasm_runtime_get_llvm_jit_options(); AOTCompOption option = { 0 }; char *aot_last_error; uint64 size; @@ -2579,6 +2585,9 @@ load_from_sections(WASMModule *module, WASMSection *sections, uint8 malloc_free_io_type = VALUE_TYPE_I32; bool reuse_const_strings = is_load_from_file_buf && !wasm_binary_freeable; bool clone_data_seg = is_load_from_file_buf && wasm_binary_freeable; +#if WASM_ENABLE_BULK_MEMORY != 0 + bool has_datacount_section = false; +#endif /* Find code and function sections if have */ while (section) { @@ -2660,6 +2669,9 @@ load_from_sections(WASMModule *module, WASMSection *sections, break; case SECTION_TYPE_DATA: if (!load_data_segment_section(buf, buf_end, module, +#if WASM_ENABLE_BULK_MEMORY != 0 + has_datacount_section, +#endif clone_data_seg, error_buf, error_buf_size)) return false; @@ -2669,6 +2681,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, if (!load_datacount_section(buf, buf_end, module, error_buf, error_buf_size)) return false; + has_datacount_section = true; break; #endif default: @@ -2909,12 +2922,14 @@ load_from_sections(WASMModule *module, WASMSection *sections, if (shrunk_memory_size <= UINT32_MAX) { if (module->import_memory_count) { memory_import = &module->import_memories[0].u.memory; - init_memory_size = (uint64)memory_import->num_bytes_per_page - * memory_import->init_page_count; + init_memory_size = + (uint64)memory_import->mem_type.num_bytes_per_page + * memory_import->mem_type.init_page_count; if (shrunk_memory_size <= init_memory_size) { /* Reset memory info to decrease memory usage */ - memory_import->num_bytes_per_page = shrunk_memory_size; - memory_import->init_page_count = 1; + memory_import->mem_type.num_bytes_per_page = + shrunk_memory_size; + memory_import->mem_type.init_page_count = 1; LOG_VERBOSE("Shrink import memory size to %" PRIu64, shrunk_memory_size); } @@ -2937,15 +2952,15 @@ load_from_sections(WASMModule *module, WASMSection *sections, if (module->import_memory_count) { memory_import = &module->import_memories[0].u.memory; - if (memory_import->init_page_count < DEFAULT_MAX_PAGES) { - memory_import->num_bytes_per_page *= - memory_import->init_page_count; - if (memory_import->init_page_count > 0) - memory_import->init_page_count = - memory_import->max_page_count = 1; + if (memory_import->mem_type.init_page_count < DEFAULT_MAX_PAGES) { + memory_import->mem_type.num_bytes_per_page *= + memory_import->mem_type.init_page_count; + if (memory_import->mem_type.init_page_count > 0) + memory_import->mem_type.init_page_count = + memory_import->mem_type.max_page_count = 1; else - memory_import->init_page_count = - memory_import->max_page_count = 0; + memory_import->mem_type.init_page_count = + memory_import->mem_type.max_page_count = 0; } } @@ -3220,8 +3235,11 @@ load(const uint8 *buf, uint32 size, WASMModule *module, } WASMModule * -wasm_loader_load(uint8 *buf, uint32 size, const LoadArgs *args, char *error_buf, - uint32 error_buf_size) +wasm_loader_load(uint8 *buf, uint32 size, +#if WASM_ENABLE_MULTI_MODULE != 0 + bool main_module, +#endif + const LoadArgs *args, char *error_buf, uint32 error_buf_size) { WASMModule *module = create_module(args->name, error_buf, error_buf_size); if (!module) { @@ -3239,6 +3257,10 @@ wasm_loader_load(uint8 *buf, uint32 size, const LoadArgs *args, char *error_buf, goto fail; } +#if WASM_ENABLE_MULTI_MODULE != 0 + (void)main_module; +#endif + LOG_VERBOSE("Load module success.\n"); return module; @@ -3451,7 +3473,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case EXT_OP_LOOP: case EXT_OP_IF: /* block type */ - skip_leb_uint32(p, p_end); + skip_leb_int32(p, p_end); if (block_nested_depth < sizeof(block_stack) / sizeof(BlockAddr)) { block_stack[block_nested_depth].start_addr = p; @@ -3921,7 +3943,11 @@ typedef struct BranchBlock { /* This is used to store available param num for if/else branch, so the else * opcode can know how many parameters should be copied to the stack */ uint32 available_param_num; - /* This is used to recover dynamic offset for else branch */ + /* This is used to recover the dynamic offset for else branch, + * and also to remember the start offset of dynamic space which + * stores the block arguments for loop block, so we can use it + * to copy the stack operands to the loop block's arguments in + * wasm_loader_emit_br_info for opcode br. */ uint16 start_dynamic_offset; #endif @@ -4050,13 +4076,26 @@ static void free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num) { BranchBlock *tmp_csp = frame_csp; + uint32 i; - for (uint32 i = 0; i < csp_num; i++) { + for (i = 0; i < csp_num; i++) { free_label_patch_list(tmp_csp); tmp_csp++; } } +static void +free_all_label_param_frame_offsets(BranchBlock *frame_csp, uint32 csp_num) +{ + BranchBlock *tmp_csp = frame_csp; + uint32 i; + + for (i = 0; i < csp_num; i++) { + if (tmp_csp->param_frame_offsets) + wasm_runtime_free(tmp_csp->param_frame_offsets); + tmp_csp++; + } +} #endif static bool @@ -4120,6 +4159,8 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx) if (ctx->frame_csp_bottom) { #if WASM_ENABLE_FAST_INTERP != 0 free_all_label_patch_lists(ctx->frame_csp_bottom, ctx->csp_num); + free_all_label_param_frame_offsets(ctx->frame_csp_bottom, + ctx->csp_num); #endif wasm_runtime_free(ctx->frame_csp_bottom); } @@ -4798,8 +4839,14 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp, emit_operand(ctx, *(int16 *)(frame_offset)); } /* Part e */ - dynamic_offset = - frame_csp->dynamic_offset + wasm_get_cell_num(types, arity); + if (frame_csp->label_type == LABEL_TYPE_LOOP) + /* Use start_dynamic_offset which was set in + copy_params_to_dynamic_space */ + dynamic_offset = frame_csp->start_dynamic_offset + + wasm_get_cell_num(types, arity); + else + dynamic_offset = + frame_csp->dynamic_offset + wasm_get_cell_num(types, arity); if (is_br) ctx->dynamic_offset = dynamic_offset; for (i = (int32)arity - 1; i >= 0; i--) { @@ -5778,8 +5825,8 @@ check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block, * Part e: each param's dst offset */ static bool -copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, - char *error_buf, uint32 error_buf_size) +copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, char *error_buf, + uint32 error_buf_size) { bool ret = false; int16 *frame_offset = NULL; @@ -5793,6 +5840,7 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, uint32 param_count = block_type->u.type->param_count; int16 condition_offset = 0; bool disable_emit = false; + bool is_if_block = (block->label_type == LABEL_TYPE_IF ? true : false); int16 operand_offset = 0; uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets)); @@ -5845,6 +5893,14 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, if (is_if_block) emit_operand(loader_ctx, condition_offset); + /* Since the start offset to save the block's params and + * the start offset to save the block's results may be + * different, we remember the dynamic offset for loop block + * so that we can use it to copy the stack operands to the + * loop block's params in wasm_loader_emit_br_info. */ + if (block->label_type == LABEL_TYPE_LOOP) + block->start_dynamic_offset = loader_ctx->dynamic_offset; + /* Part e) */ /* Push to dynamic space. The push will emit the dst offset. */ for (i = 0; i < param_count; i++) @@ -6043,11 +6099,11 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, block_type.u.value_type.type = value_type; } else { - uint32 type_index; + int32 type_index; /* Resolve the leb128 encoded type index as block type */ p--; - read_leb_uint32(p, p_end, type_index); - bh_assert(type_index < module->type_count); + read_leb_int32(p, p_end, type_index); + bh_assert((uint32)type_index < module->type_count); block_type.is_value_type = false; block_type.u.type = module->types[type_index]; #if WASM_ENABLE_FAST_INTERP == 0 @@ -6134,8 +6190,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, skip_label(); if (BLOCK_HAS_PARAM(block_type)) { /* Make sure params are in dynamic space */ - if (!copy_params_to_dynamic_space( - loader_ctx, false, error_buf, error_buf_size)) + if (!copy_params_to_dynamic_space(loader_ctx, error_buf, + error_buf_size)) goto fail; } if (opcode == WASM_OP_LOOP) { @@ -6175,8 +6231,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, /* skip the if label */ skip_label(); /* Emit a copy instruction */ - if (!copy_params_to_dynamic_space( - loader_ctx, true, error_buf, error_buf_size)) + if (!copy_params_to_dynamic_space(loader_ctx, error_buf, + error_buf_size)) goto fail; /* Emit the if instruction */ @@ -6942,7 +6998,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, uint32 j; for (i = 0; i < module->global_count; i++) { - if (module->globals[i].type == VALUE_TYPE_FUNCREF + if (module->globals[i].type.val_type + == VALUE_TYPE_FUNCREF && module->globals[i].init_expr.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST && module->globals[i].init_expr.u.u32 == func_idx) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 635fdea6d9..122325bc28 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -396,12 +396,13 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, /* instantiate memories from import section */ import = module->import_memories; for (i = 0; i < module->import_memory_count; i++, import++, memory++) { - uint32 num_bytes_per_page = import->u.memory.num_bytes_per_page; - uint32 init_page_count = import->u.memory.init_page_count; + uint32 num_bytes_per_page = + import->u.memory.mem_type.num_bytes_per_page; + uint32 init_page_count = import->u.memory.mem_type.init_page_count; uint32 max_page_count = wasm_runtime_get_max_mem( - max_memory_pages, import->u.memory.init_page_count, - import->u.memory.max_page_count); - uint32 flags = import->u.memory.flags; + max_memory_pages, import->u.memory.mem_type.init_page_count, + import->u.memory.mem_type.max_page_count); + uint32 flags = import->u.memory.mem_type.flags; uint32 actual_heap_size = heap_size; #if WASM_ENABLE_MULTI_MODULE != 0 @@ -3181,7 +3182,7 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) if (!is_sub_inst) { #if WASM_ENABLE_WASI_NN != 0 - wasi_nn_destroy(module_inst); + wasi_nn_destroy((WASMModuleInstanceCommon *)module_inst); #endif wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst); } diff --git a/core/iwasm/libraries/wasi-nn/README.md b/core/iwasm/libraries/wasi-nn/README.md index fbc99ccbb2..56baf99c5a 100644 --- a/core/iwasm/libraries/wasi-nn/README.md +++ b/core/iwasm/libraries/wasi-nn/README.md @@ -16,23 +16,22 @@ By only including this file in your WASM application you will bind WASI-NN into To run the tests we assume that the current directory is the root of the repository. - ### Build the runtime Build the runtime image for your execution target type. `EXECUTION_TYPE` can be: -* `cpu` -* `nvidia-gpu` -* `vx-delegate` -* `tpu` + +- `cpu` +- `nvidia-gpu` +- `vx-delegate` +- `tpu` ``` EXECUTION_TYPE=cpu docker build -t wasi-nn-${EXECUTION_TYPE} -f core/iwasm/libraries/wasi-nn/test/Dockerfile.${EXECUTION_TYPE} . ``` - ### Build wasm app ``` @@ -43,7 +42,6 @@ docker build -t wasi-nn-compile -f core/iwasm/libraries/wasi-nn/test/Dockerfile. docker run -v $PWD/core/iwasm/libraries/wasi-nn:/wasi-nn wasi-nn-compile ``` - ### Run wasm app If all the tests have run properly you will the the following message in the terminal, @@ -52,7 +50,7 @@ If all the tests have run properly you will the the following message in the ter Tests: passed! ``` -* CPU +- CPU ``` docker run \ @@ -64,9 +62,9 @@ docker run \ /assets/test_tensorflow.wasm ``` -* (NVIDIA) GPU - * Requirements: - * [NVIDIA docker](https://github.com/NVIDIA/nvidia-docker). +- (NVIDIA) GPU + - Requirements: + - [NVIDIA docker](https://github.com/NVIDIA/nvidia-docker). ``` docker run \ @@ -79,7 +77,7 @@ docker run \ /assets/test_tensorflow.wasm ``` -* vx-delegate for NPU (x86 simulator) +- vx-delegate for NPU (x86 simulator) ``` docker run \ @@ -90,9 +88,9 @@ docker run \ /assets/test_tensorflow_quantized.wasm ``` -* (Coral) TPU - * Requirements: - * [Coral USB](https://coral.ai/products/accelerator/). +- (Coral) TPU + - Requirements: + - [Coral USB](https://coral.ai/products/accelerator/). ``` docker run \ @@ -109,6 +107,45 @@ docker run \ Supported: -* Graph encoding: `tensorflowlite`. -* Execution target: `cpu`, `gpu` and `tpu`. -* Tensor type: `fp32`. +- Graph encoding: `tensorflowlite`. +- Execution target: `cpu`, `gpu` and `tpu`. +- Tensor type: `fp32`. + +## Smoke test + +Use [classification-example](https://github.com/bytecodealliance/wasi-nn/tree/main/rust/examples/classification-example) as a smoke test case to make sure the wasi-nn support in WAMR is working properly. + +> [!Important] +> It requires openvino. + +### Prepare the model and the wasm + +``` bash +$ pwd +/workspaces/wasm-micro-runtime/core/iwasm/libraries/wasi-nn/test + +$ docker build -t wasi-nn-example:v1.0 -f Dockerfile.wasi-nn-example . +``` + +There are model files(*mobilenet\**) and wasm files(*wasi-nn-example.wasm*) in the directory */workspaces/wasi-nn/rust/examples/classification-example/build* in the image of wasi-nn-example:v1.0. + +### build iwasm and test + +*TODO: May need alternative steps to build the iwasm and test in the container of wasi-nn-example:v1.0* + +``` bash +$ pwd +/workspaces/wasm-micro-runtime + +$ docker run --rm -it -v $(pwd):/workspaces/wasm-micro-runtime wasi-nn-example:v1.0 /bin/bash +``` + +> [!Caution] +> The following steps are executed in the container of wasi-nn-example:v1.0. + +``` bash +$ cd /workspaces/wasm-micro-runtime/product-mini/platforms/linux +$ cmake -S . -B build -DWAMR_BUILD_WASI_NN=1 -DWAMR_BUILD_WASI_EPHEMERAL_NN=1 +$ cmake --build build +$ ./build/iwasm -v=5 --map-dir=/workspaces/wasi-nn/rust/examples/classification-example/build/::fixture /workspaces/wasi-nn/rust/examples/classification-example/build/wasi-nn-example.wasm +``` \ No newline at end of file diff --git a/core/iwasm/libraries/wasi-nn/include/wasi_nn.h b/core/iwasm/libraries/wasi-nn/include/wasi_nn.h index 2bf0a192c8..66e2ee02af 100644 --- a/core/iwasm/libraries/wasi-nn/include/wasi_nn.h +++ b/core/iwasm/libraries/wasi-nn/include/wasi_nn.h @@ -22,9 +22,9 @@ * @param encoding Model encoding. * @param target Execution target. * @param g Graph. - * @return error Execution status. + * @return wasi_nn_error Execution status. */ -error +wasi_nn_error load(graph_builder_array *builder, graph_encoding encoding, execution_target target, graph *g) __attribute__((import_module("wasi_nn"))); @@ -34,17 +34,14 @@ load(graph_builder_array *builder, graph_encoding encoding, * */ -// Bind a `graph` to the input and output tensors for an inference. -typedef uint32_t graph_execution_context; - /** * @brief Create an execution instance of a loaded graph. * * @param g Graph. * @param ctx Execution context. - * @return error Execution status. + * @return wasi_nn_error Execution status. */ -error +wasi_nn_error init_execution_context(graph g, graph_execution_context *ctx) __attribute__((import_module("wasi_nn"))); @@ -54,9 +51,9 @@ init_execution_context(graph g, graph_execution_context *ctx) * @param ctx Execution context. * @param index Input tensor index. * @param tensor Input tensor. - * @return error Execution status. + * @return wasi_nn_error Execution status. */ -error +wasi_nn_error set_input(graph_execution_context ctx, uint32_t index, tensor *tensor) __attribute__((import_module("wasi_nn"))); @@ -64,9 +61,9 @@ set_input(graph_execution_context ctx, uint32_t index, tensor *tensor) * @brief Compute the inference on the given inputs. * * @param ctx Execution context. - * @return error Execution status. + * @return wasi_nn_error Execution status. */ -error +wasi_nn_error compute(graph_execution_context ctx) __attribute__((import_module("wasi_nn"))); /** @@ -79,9 +76,9 @@ compute(graph_execution_context ctx) __attribute__((import_module("wasi_nn"))); * @param output_tensor_size Pointer to `output_tensor` maximum size. * After the function call it is updated with the * copied number of bytes. - * @return error Execution status. + * @return wasi_nn_error Execution status. */ -error +wasi_nn_error get_output(graph_execution_context ctx, uint32_t index, tensor_data output_tensor, uint32_t *output_tensor_size) __attribute__((import_module("wasi_nn"))); diff --git a/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h b/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h index 7cfc70f341..d3c56cb7d8 100644 --- a/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h +++ b/core/iwasm/libraries/wasi-nn/include/wasi_nn_types.h @@ -28,7 +28,7 @@ typedef enum { busy, // Runtime Error. runtime_error, -} error; +} wasi_nn_error; /** * TENSOR @@ -106,4 +106,7 @@ typedef enum { // Define where the graph should be executed. typedef enum execution_target { cpu = 0, gpu, tpu } execution_target; +// Bind a `graph` to the input and output tensors for an inference. +typedef uint32_t graph_execution_context; + #endif diff --git a/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c b/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c index 44aef53593..b1a7c327d6 100644 --- a/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c +++ b/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c @@ -5,7 +5,7 @@ #include "wasi_nn_app_native.h" -static error +static wasi_nn_error graph_builder_app_native(wasm_module_inst_t instance, graph_builder_wasm *builder_wasm, graph_builder *builder) @@ -27,12 +27,12 @@ graph_builder_app_native(wasm_module_inst_t instance, * builder_array_wasm is consisted of {builder_wasm, size} */ #if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 -error +wasi_nn_error graph_builder_array_app_native(wasm_module_inst_t instance, graph_builder_wasm *builder_wasm, uint32_t size, graph_builder_array *builder_array) #else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */ -error +wasi_nn_error graph_builder_array_app_native(wasm_module_inst_t instance, graph_builder_array_wasm *builder_array_wasm, graph_builder_array *builder_array) @@ -79,7 +79,7 @@ graph_builder_array_app_native(wasm_module_inst_t instance, return missing_memory; for (uint32_t i = 0; i < array_size; ++i) { - error res; + wasi_nn_error res; if (success != (res = graph_builder_app_native(instance, &builder_wasm[i], &builder[i]))) { @@ -97,7 +97,7 @@ graph_builder_array_app_native(wasm_module_inst_t instance, #undef array_size } -static error +static wasi_nn_error tensor_data_app_native(wasm_module_inst_t instance, uint32_t total_elements, tensor_wasm *input_tensor_wasm, tensor_data *data) { @@ -119,7 +119,7 @@ tensor_data_app_native(wasm_module_inst_t instance, uint32_t total_elements, #undef data_size } -static error +static wasi_nn_error tensor_dimensions_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor_wasm, tensor_dimensions **dimensions) @@ -159,7 +159,7 @@ tensor_dimensions_app_native(wasm_module_inst_t instance, return success; } -error +wasi_nn_error tensor_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor_wasm, tensor *input_tensor) { @@ -170,7 +170,7 @@ tensor_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor_wasm, return invalid_argument; } - error res; + wasi_nn_error res; tensor_dimensions *dimensions = NULL; if (success diff --git a/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h b/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h index f0930a8837..80c22784eb 100644 --- a/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h +++ b/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h @@ -12,7 +12,7 @@ #include #include -#include "wasi_nn.h" +#include "wasi_nn_types.h" #include "logger.h" #include "bh_platform.h" @@ -47,18 +47,18 @@ typedef struct { } tensor_wasm; #if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 -error +wasi_nn_error graph_builder_array_app_native(wasm_module_inst_t instance, graph_builder_wasm *builder_wasm, uint32_t size, graph_builder_array *builder_array); #else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */ -error +wasi_nn_error graph_builder_array_app_native(wasm_module_inst_t instance, graph_builder_array_wasm *builder, graph_builder_array *builder_native); #endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */ -error +wasi_nn_error tensor_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor, tensor *input_tensor_native); diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn.c b/core/iwasm/libraries/wasi-nn/src/wasi_nn.c index 1fbb944286..6c97940a16 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn.c +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn.c @@ -11,7 +11,6 @@ #include #include -#include "wasi_nn.h" #include "wasi_nn_private.h" #include "wasi_nn_app_native.h" #include "wasi_nn_tensorflowlite.hpp" @@ -24,14 +23,15 @@ /* Definition of 'wasi_nn.h' structs in WASM app format (using offset) */ -typedef error (*LOAD)(void *, graph_builder_array *, graph_encoding, - execution_target, graph *); -typedef error (*INIT_EXECUTION_CONTEXT)(void *, graph, - graph_execution_context *); -typedef error (*SET_INPUT)(void *, graph_execution_context, uint32_t, tensor *); -typedef error (*COMPUTE)(void *, graph_execution_context); -typedef error (*GET_OUTPUT)(void *, graph_execution_context, uint32_t, - tensor_data, uint32_t *); +typedef wasi_nn_error (*LOAD)(void *, graph_builder_array *, graph_encoding, + execution_target, graph *); +typedef wasi_nn_error (*INIT_EXECUTION_CONTEXT)(void *, graph, + graph_execution_context *); +typedef wasi_nn_error (*SET_INPUT)(void *, graph_execution_context, uint32_t, + tensor *); +typedef wasi_nn_error (*COMPUTE)(void *, graph_execution_context); +typedef wasi_nn_error (*GET_OUTPUT)(void *, graph_execution_context, uint32_t, + tensor_data, uint32_t *); typedef struct { LOAD load; @@ -177,7 +177,7 @@ is_encoding_implemented(graph_encoding encoding) && lookup[encoding].get_output; } -static error +static wasi_nn_error is_model_initialized(WASINNContext *wasi_nn_ctx) { if (!wasi_nn_ctx->is_model_loaded) { @@ -190,12 +190,12 @@ is_model_initialized(WASINNContext *wasi_nn_ctx) /* WASI-NN implementation */ #if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 -error +wasi_nn_error wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_wasm *builder, uint32_t builder_wasm_size, graph_encoding encoding, execution_target target, graph *g) #else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */ -error +wasi_nn_error wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, graph_encoding encoding, execution_target target, graph *g) #endif /* WASM_ENABLE_WASI_EPHEMERAL_NN != 0 */ @@ -211,7 +211,7 @@ wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); bh_assert(instance); - error res; + wasi_nn_error res; graph_builder_array builder_native = { 0 }; #if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 if (success @@ -249,7 +249,7 @@ wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, return res; } -error +wasi_nn_error wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph g, graph_execution_context *ctx) { @@ -259,7 +259,7 @@ wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph g, bh_assert(instance); WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); - error res; + wasi_nn_error res; if (success != (res = is_model_initialized(wasi_nn_ctx))) return res; @@ -278,7 +278,7 @@ wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph g, return res; } -error +wasi_nn_error wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx, uint32_t index, tensor_wasm *input_tensor) { @@ -289,7 +289,7 @@ wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx, bh_assert(instance); WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); - error res; + wasi_nn_error res; if (success != (res = is_model_initialized(wasi_nn_ctx))) return res; @@ -310,7 +310,7 @@ wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx, return res; } -error +wasi_nn_error wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx) { NN_DBG_PRINTF("Running wasi_nn_compute [ctx=%d]...", ctx); @@ -319,7 +319,7 @@ wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx) bh_assert(instance); WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); - error res; + wasi_nn_error res; if (success != (res = is_model_initialized(wasi_nn_ctx))) return res; @@ -330,12 +330,12 @@ wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx) } #if WASM_ENABLE_WASI_EPHEMERAL_NN != 0 -error +wasi_nn_error wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx, uint32_t index, tensor_data output_tensor, uint32_t output_tensor_len, uint32_t *output_tensor_size) #else /* WASM_ENABLE_WASI_EPHEMERAL_NN == 0 */ -error +wasi_nn_error wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx, uint32_t index, tensor_data output_tensor, uint32_t *output_tensor_size) @@ -348,7 +348,7 @@ wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx, bh_assert(instance); WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); - error res; + wasi_nn_error res; if (success != (res = is_model_initialized(wasi_nn_ctx))) return res; diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp index 65e38f867c..08c44bb5d6 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#include "wasi_nn.h" +#include "wasi_nn_types.h" #include "wasi_nn_tensorflowlite.hpp" #include "logger.h" @@ -50,7 +50,7 @@ typedef struct { /* Utils */ -static error +static wasi_nn_error initialize_g(TFLiteContext *tfl_ctx, graph *g) { os_mutex_lock(&tfl_ctx->g_lock); @@ -63,7 +63,7 @@ initialize_g(TFLiteContext *tfl_ctx, graph *g) os_mutex_unlock(&tfl_ctx->g_lock); return success; } -static error +static wasi_nn_error initialize_graph_ctx(TFLiteContext *tfl_ctx, graph g, graph_execution_context *ctx) { @@ -78,7 +78,7 @@ initialize_graph_ctx(TFLiteContext *tfl_ctx, graph g, return success; } -static error +static wasi_nn_error is_valid_graph(TFLiteContext *tfl_ctx, graph g) { if (g >= MAX_GRAPHS_PER_INST) { @@ -96,7 +96,7 @@ is_valid_graph(TFLiteContext *tfl_ctx, graph g) return success; } -static error +static wasi_nn_error is_valid_graph_execution_context(TFLiteContext *tfl_ctx, graph_execution_context ctx) { @@ -114,7 +114,7 @@ is_valid_graph_execution_context(TFLiteContext *tfl_ctx, /* WASI-NN (tensorflow) implementation */ -error +wasi_nn_error tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, graph_encoding encoding, execution_target target, graph *g) { @@ -135,7 +135,7 @@ tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, return invalid_argument; } - error res; + wasi_nn_error res; if (success != (res = initialize_g(tfl_ctx, g))) return res; @@ -168,13 +168,13 @@ tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, return success; } -error +wasi_nn_error tensorflowlite_init_execution_context(void *tflite_ctx, graph g, graph_execution_context *ctx) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; - error res; + wasi_nn_error res; if (success != (res = is_valid_graph(tfl_ctx, g))) return res; @@ -257,13 +257,13 @@ tensorflowlite_init_execution_context(void *tflite_ctx, graph g, return success; } -error +wasi_nn_error tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, uint32_t index, tensor *input_tensor) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; - error res; + wasi_nn_error res; if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx))) return res; @@ -328,12 +328,12 @@ tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, return success; } -error +wasi_nn_error tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; - error res; + wasi_nn_error res; if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx))) return res; @@ -341,14 +341,14 @@ tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx) return success; } -error +wasi_nn_error tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx, uint32_t index, tensor_data output_tensor, uint32_t *output_tensor_size) { TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; - error res; + wasi_nn_error res; if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx))) return res; @@ -472,6 +472,8 @@ tensorflowlite_destroy(void *tflite_ctx) #endif break; } + default: + break; } } wasm_runtime_free(tfl_ctx->models[i].model_pointer); diff --git a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp index 9605420ddb..6eea38be9f 100644 --- a/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp +++ b/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp @@ -6,28 +6,28 @@ #ifndef WASI_NN_TENSORFLOWLITE_HPP #define WASI_NN_TENSORFLOWLITE_HPP -#include "wasi_nn.h" +#include "wasi_nn_types.h" #ifdef __cplusplus extern "C" { #endif -error +wasi_nn_error tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, graph_encoding encoding, execution_target target, graph *g); -error +wasi_nn_error tensorflowlite_init_execution_context(void *tflite_ctx, graph g, graph_execution_context *ctx); -error +wasi_nn_error tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, uint32_t index, tensor *input_tensor); -error +wasi_nn_error tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx); -error +wasi_nn_error tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx, uint32_t index, tensor_data output_tensor, uint32_t *output_tensor_size); diff --git a/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-example b/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-example new file mode 100644 index 0000000000..020bfd20e3 --- /dev/null +++ b/core/iwasm/libraries/wasi-nn/test/Dockerfile.wasi-nn-example @@ -0,0 +1,57 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM mcr.microsoft.com/devcontainers/rust:1-1-bullseye + +ARG DEBIAN_FRONTEND=noninteractive +ENV TZ=Asian/Shanghai + +# hadolint ignore=DL3009 +RUN apt-get update \ + && apt-get upgrade -y + +# +# Rust targets +RUN rustup target add wasm32-wasi wasm32-unknown-unknown + +# +# Openvino +# Refer to +# - https://docs.openvino.ai/2022.3/openvino_docs_install_guides_installing_openvino_from_archive_linux.html +# - https://docs.openvino.ai/2023.3/openvino_docs_install_guides_installing_openvino_from_archive_linux.html +# - https://docs.openvino.ai/2024/get-started/install-openvino/install-openvino-archive-linux.html +# +# FIXME: upgrade to 2024.1 or latest after wasi-nn(rust binding) is ready +WORKDIR /opt/intel +RUN wget -q https://storage.openvinotoolkit.org/repositories/openvino/packages/2022.3.2/linux/l_openvino_toolkit_ubuntu20_2022.3.2.9279.e2c7e4d7b4d_x86_64.tgz +RUN tar -xf l_openvino_toolkit_ubuntu20_2022.3.2.9279.e2c7e4d7b4d_x86_64.tgz \ + && rm l_openvino_toolkit_ubuntu20_2022.3.2.9279.e2c7e4d7b4d_x86_64.tgz \ + && mv l_openvino_toolkit_ubuntu20_2022.3.2.9279.e2c7e4d7b4d_x86_64 /opt/intel/openvino + +WORKDIR /opt/intel/openvino +RUN ./install_dependencies/install_openvino_dependencies.sh -y \ + && ./setupvars.sh + +# +# wasmtime +WORKDIR /opt +RUN wget -q https://github.com/bytecodealliance/wasmtime/releases/download/v21.0.0/wasmtime-v21.0.0-x86_64-linux.tar.xz +RUN tar -xf wasmtime-v21.0.0-x86_64-linux.tar.xz \ + && rm wasmtime-v21.0.0-x86_64-linux.tar.xz \ + && ln -sf "$(realpath ./wasmtime-v21.0.0-x86_64-linux/wasmtime)" /usr/local/bin/wasmtime + +# +# wasi-nn +WORKDIR /workspaces/wasi-nn +RUN git clone --depth 1 https://github.com/bytecodealliance/wasi-nn.git . +# hadolint ignore=DL3059 +RUN ./build.sh rust + +# There are model files(mobilenet*) and wasm files(wasi-nn-example.wasm) in the directory, +# /workspaces/wasi-nn/rust/examples/classification-example/build + +RUN apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /tmp/* + +WORKDIR /workspaces diff --git a/core/iwasm/libraries/wasi-nn/test/utils.c b/core/iwasm/libraries/wasi-nn/test/utils.c index 7b4f65d16b..f19ec0f8ea 100644 --- a/core/iwasm/libraries/wasi-nn/test/utils.c +++ b/core/iwasm/libraries/wasi-nn/test/utils.c @@ -9,7 +9,7 @@ #include #include -error +wasi_nn_error wasm_load(char *model_name, graph *g, execution_target target) { FILE *pFile = fopen(model_name, "r"); @@ -46,7 +46,7 @@ wasm_load(char *model_name, graph *g, execution_target target) arr.buf[0].size = result; arr.buf[0].buf = buffer; - error res = load(&arr, tensorflowlite, target, g); + wasi_nn_error res = load(&arr, tensorflowlite, target, g); fclose(pFile); free(buffer); @@ -54,13 +54,13 @@ wasm_load(char *model_name, graph *g, execution_target target) return res; } -error +wasi_nn_error wasm_init_execution_context(graph g, graph_execution_context *ctx) { return init_execution_context(g, ctx); } -error +wasi_nn_error wasm_set_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim) { tensor_dimensions dims; @@ -75,19 +75,19 @@ wasm_set_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim) tensor.dimensions->buf[i] = dim[i]; tensor.type = fp32; tensor.data = (uint8_t *)input_tensor; - error err = set_input(ctx, 0, &tensor); + wasi_nn_error err = set_input(ctx, 0, &tensor); free(dims.buf); return err; } -error +wasi_nn_error wasm_compute(graph_execution_context ctx) { return compute(ctx); } -error +wasi_nn_error wasm_get_output(graph_execution_context ctx, uint32_t index, float *out_tensor, uint32_t *out_size) { diff --git a/core/iwasm/libraries/wasi-nn/test/utils.h b/core/iwasm/libraries/wasi-nn/test/utils.h index 0b2328406e..8b139a9b10 100644 --- a/core/iwasm/libraries/wasi-nn/test/utils.h +++ b/core/iwasm/libraries/wasi-nn/test/utils.h @@ -23,19 +23,19 @@ typedef struct { /* wasi-nn wrappers */ -error +wasi_nn_error wasm_load(char *model_name, graph *g, execution_target target); -error +wasi_nn_error wasm_init_execution_context(graph g, graph_execution_context *ctx); -error +wasi_nn_error wasm_set_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim); -error +wasi_nn_error wasm_compute(graph_execution_context ctx); -error +wasi_nn_error wasm_get_output(graph_execution_context ctx, uint32_t index, float *out_tensor, uint32_t *out_size); diff --git a/core/shared/platform/common/posix/platform_api_posix.cmake b/core/shared/platform/common/posix/platform_api_posix.cmake index 15d6daf3f5..2553a7d04a 100644 --- a/core/shared/platform/common/posix/platform_api_posix.cmake +++ b/core/shared/platform/common/posix/platform_api_posix.cmake @@ -9,6 +9,11 @@ if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1) list(REMOVE_ITEM source_all ${PLATFORM_COMMON_POSIX_DIR}/posix_file.c ${PLATFORM_COMMON_POSIX_DIR}/posix_clock.c + ) +endif() + +if ((NOT WAMR_BUILD_LIBC_WASI EQUAL 1) AND (NOT WAMR_BUILD_DEBUG_INTERP EQUAL 1)) + list(REMOVE_ITEM source_all ${PLATFORM_COMMON_POSIX_DIR}/posix_socket.c ) else() diff --git a/core/shared/platform/riot/platform_internal.h b/core/shared/platform/riot/platform_internal.h index e88b25d403..24a1d6c868 100644 --- a/core/shared/platform/riot/platform_internal.h +++ b/core/shared/platform/riot/platform_internal.h @@ -94,4 +94,12 @@ os_get_invalid_handle() return -1; } +/* There is no MMU in RIOT so the function return 1024 to make the compiler + happy */ +static inline int +os_getpagesize() +{ + return 1024; +} + #endif /* end of _BH_PLATFORM_H */ diff --git a/core/shared/platform/riot/riot_platform.c b/core/shared/platform/riot/riot_platform.c index ad5927e513..9c1fbfa451 100644 --- a/core/shared/platform/riot/riot_platform.c +++ b/core/shared/platform/riot/riot_platform.c @@ -57,6 +57,12 @@ os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) return BH_MALLOC((unsigned)size); } +void * +os_mremap(void *old_addr, size_t old_size, size_t new_size) +{ + return os_mremap_slow(old_addr, old_size, new_size); +} + void os_munmap(void *addr, size_t size) { diff --git a/core/version.h b/core/version.h index de3f56abcf..e321744e3b 100644 --- a/core/version.h +++ b/core/version.h @@ -6,6 +6,6 @@ #ifndef _WAMR_VERSION_H_ #define _WAMR_VERSION_H_ #define WAMR_VERSION_MAJOR 2 -#define WAMR_VERSION_MINOR 0 +#define WAMR_VERSION_MINOR 1 #define WAMR_VERSION_PATCH 0 #endif diff --git a/product-mini/platforms/android/CMakeLists.txt b/product-mini/platforms/android/CMakeLists.txt index db60e8649a..5c05259176 100644 --- a/product-mini/platforms/android/CMakeLists.txt +++ b/product-mini/platforms/android/CMakeLists.txt @@ -105,6 +105,8 @@ 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_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index d951de2c9d..b2f929c6a7 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -535,21 +535,23 @@ void * timeout_thread(void *vp) { const struct timeout_arg *arg = vp; - uint32 left = arg->timeout_ms; + const uint64 end_time = + os_time_get_boot_us() + (uint64)arg->timeout_ms * 1000; while (!arg->cancel) { - uint32 ms; - if (left >= 100) { - ms = 100; - } - else { - ms = left; - } - os_usleep((uint64)ms * 1000); - left -= ms; - if (left == 0) { + const uint64 now = os_time_get_boot_us(); + if ((int64)(now - end_time) > 0) { wasm_runtime_terminate(arg->inst); break; } + const uint64 left_us = end_time - now; + uint32 us; + if (left_us >= 100 * 1000) { + us = 100 * 1000; + } + else { + us = left_us; + } + os_usleep(us); } return NULL; } diff --git a/test-tools/aot-analyzer/src/main.cc b/test-tools/aot-analyzer/src/main.cc index fa9582cd7e..7b71e30050 100644 --- a/test-tools/aot-analyzer/src/main.cc +++ b/test-tools/aot-analyzer/src/main.cc @@ -272,9 +272,9 @@ DumpDetails(AoTFile *aot) AOTImportMemory memory = import_memories[index]; printf(" -[%u] num_bytes_per_page:%5u init_page_count:%5u " "max_page_count:%5u module_name: %s memory_name: %s\n", - index, memory.num_bytes_per_page, memory.mem_init_page_count, - memory.mem_max_page_count, memory.module_name, - memory.memory_name); + index, memory.memory.num_bytes_per_page, + memory.memory.init_page_count, memory.memory.max_page_count, + memory.module_name, memory.memory_name); } printf("\n"); @@ -365,10 +365,10 @@ DumpDetails(AoTFile *aot) for (uint32_t index = 0; index < memory_count; index++) { AOTMemory memory = memories[index]; - printf(" -[%u] memory_flags:%5u bytes_per_page:%5u " + printf(" -[%u] flags:%5u bytes_per_page:%5u " "init_page_count:%5u max_page_count:%5u\n", - index, memory.memory_flags, memory.num_bytes_per_page, - memory.mem_init_page_count, memory.mem_max_page_count); + index, memory.flags, memory.num_bytes_per_page, + memory.init_page_count, memory.max_page_count); } printf("\n\n"); diff --git a/test-tools/wamr-ide/VSCode-Extension/tsconfig.json b/test-tools/wamr-ide/VSCode-Extension/tsconfig.json index c75039eee9..9ecb219db3 100644 --- a/test-tools/wamr-ide/VSCode-Extension/tsconfig.json +++ b/test-tools/wamr-ide/VSCode-Extension/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "module": "commonjs", + "moduleResolution": "node16", "target": "es6", "outDir": "out", "lib": ["es6"], diff --git a/tests/fuzz/wasm-mutator-fuzz/CMakeLists.txt b/tests/fuzz/wasm-mutator-fuzz/CMakeLists.txt index 2b6ddae760..084b399112 100644 --- a/tests/fuzz/wasm-mutator-fuzz/CMakeLists.txt +++ b/tests/fuzz/wasm-mutator-fuzz/CMakeLists.txt @@ -58,12 +58,12 @@ endif () if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) # Enable libc builtin support by default - set (WAMR_BUILD_LIBC_BUILTIN 1) + set (WAMR_BUILD_LIBC_BUILTIN 0) endif () if (NOT DEFINED WAMR_BUILD_LIBC_WASI) # Enable libc wasi support by default - set (WAMR_BUILD_LIBC_WASI 1) + set (WAMR_BUILD_LIBC_WASI 0) endif () if (NOT DEFINED WAMR_BUILD_FAST_INTERP) @@ -92,8 +92,8 @@ if (NOT DEFINED WAMR_BUILD_SIMD) endif () if (NOT DEFINED WAMR_BUILD_REF_TYPES) - # Disable reference types by default - set (WAMR_BUILD_REF_TYPES 0) + # Enable reference type by default + set (WAMR_BUILD_REF_TYPES 1) endif () if (NOT DEFINED WAMR_BUILD_DEBUG_INTERP) @@ -113,7 +113,7 @@ message([ceith]:REPO_ROOT_DIR, ${REPO_ROOT_DIR}) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") -add_definitions(-DWAMR_USE_MEM_POOL=0) +add_definitions(-DWAMR_USE_MEM_POOL=0 -DWASM_ENABLE_FUZZ_TEST=1) # Enable fuzzer add_compile_options(-fsanitize=fuzzer) diff --git a/tests/fuzz/wasm-mutator-fuzz/smith_wasm.sh b/tests/fuzz/wasm-mutator-fuzz/smith_wasm.sh index 6e9fa10fa1..29d24dbd08 100755 --- a/tests/fuzz/wasm-mutator-fuzz/smith_wasm.sh +++ b/tests/fuzz/wasm-mutator-fuzz/smith_wasm.sh @@ -8,51 +8,61 @@ # 1.check parameter if [ ! $1 ]; then echo "Parameter is empty, please enter parameter !" - exit + exit fi +EXPECTED_NUM=$1 # 2.check dir buildPath="./build" corpusPath="$buildPath/CORPUS_DIR" -if [[ ! -d "$buildPath" ]]; then - echo "auto create the build folder !" - mkdir build -else # build Folder exists - if [[ -d "$buildPath" ]]; then # CORPUS_DIR exists - rm -rf $corpusPath - fi -fi +rm -rf "${corpusPath}" +mkdir -p "${corpusPath}" # 3.change dir -# cd build && mkdir CORPUS_DIR && cd CORPUS_DIR -cd build && mkdir CORPUS_DIR && cd CORPUS_DIR +cd "${corpusPath}" # 4.generate *.wasm file -echo "Generate $@ files according to user requirements" +echo "Generating $EXPECTED_NUM Wasm files for each kind as required" -for((i=1; i<($@+1); i++)); -do -head -c 100 /dev/urandom | wasm-tools smith -o test_$i.wasm -done +# Generate wasm files with different features +# Try on and on until the generated wasm file exists +function try_generate_wasm() +{ + SMITH_OPTIONS=$1 + GENERATED_WASM_NAME=$2 + + local try_i=0 + until [[ -f $GENERATED_WASM_NAME ]]; do + head -c 100 /dev/urandom | wasm-tools smith $SMITH_OPTIONS -o $GENERATED_WASM_NAME >/dev/null 2>&1 + try_i=$((try_i+1)) + done + + printf -- "-- output ${GENERATED_WASM_NAME} in %d retries\n" $try_i +} -# 5.check wasm file -dir=$(pwd) -d=$(find . ! -name "." -type d -prune -o -type f -name "*.wasm" -print) -#echo "current dir=$dir" -num=0 +# try_generate_wasm "--min-memories=1 --min-tables=1" "test_min.wasm" -for((i=1; i<($@+1); i++)); +for i in $(seq 1 $EXPECTED_NUM) do - wasmFile="test_$i.wasm" - if [[ ! -f "$wasmFile" ]]; then - echo "The file $wasmFile is not exists !" - else - let "num++" - fi -done + # by default + try_generate_wasm "" test_$i.wasm -echo "$@ user requirements, $num actually generated !" + # with different features + # mvp + try_generate_wasm "--min-memories=1 --min-tables=1" test_min_$i.wasm + try_generate_wasm "--min-memories=1 --min-tables=1 --bulk-memory-enabled true" test_bulk_$i.wasm + try_generate_wasm "--min-memories=1 --min-tables=1 --reference-types-enabled true" test_ref_$i.wasm + try_generate_wasm "--min-memories=1 --min-tables=1 --multi-value-enabled true" test_multi_$i.wasm + try_generate_wasm "--min-memories=1 --min-tables=1 --simd-enabled true" test_simd_$i.wasm + try_generate_wasm "--min-memories=1 --min-tables=1 --tail-call-enabled true " test_tail_$i.wasm -if [ $num == $@ ]; then echo "Wasm file generated successfully !" -else echo "Wasm file generated faild !" -fi + # enable me when compiling iwasm with those features + #try_generate_wasm "--min-memories=1 --min-tables=1 --threads-enabled true" test_thread_$i.wasm + #try_generate_wasm "--min-memories=1 --min-tables=1 --memory64-enabled true" test_memory64_$i.wasm + #try_generate_wasm "--min-memories=1 --min-tables=1 --exceptions-enabled true" test_exception_$i.wasm + #try_generate_wasm "--min-memories=1 --min-tables=1 --gc-enabled true" test_gc_$i.wasm + # with custom-section + try_generate_wasm "--min-memories=1 --min-tables=1 --generate-custom-sections true" test_custom_$i.wasm +done + +printf "Done\n" diff --git a/tests/fuzz/wasm-mutator-fuzz/workspace/CMakeLists.txt b/tests/fuzz/wasm-mutator-fuzz/workspace/CMakeLists.txt index ec7eaff88a..5fa171a9cc 100644 --- a/tests/fuzz/wasm-mutator-fuzz/workspace/CMakeLists.txt +++ b/tests/fuzz/wasm-mutator-fuzz/workspace/CMakeLists.txt @@ -92,8 +92,8 @@ if (NOT DEFINED WAMR_BUILD_SIMD) endif () if (NOT DEFINED WAMR_BUILD_REF_TYPES) - # Disable reference types by default - set (WAMR_BUILD_REF_TYPES 0) + # Enable reference type by default + set (WAMR_BUILD_REF_TYPES 1) endif () if (NOT DEFINED WAMR_BUILD_DEBUG_INTERP) @@ -113,7 +113,7 @@ message([ceith]:REPO_ROOT_DIR, ${REPO_ROOT_DIR}) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") -add_definitions(-DWAMR_USE_MEM_POOL=0) +add_definitions(-DWAMR_USE_MEM_POOL=0 -DWASM_ENABLE_FUZZ_TEST=1) # Enable fuzzer add_compile_options(-fsanitize=fuzzer) diff --git a/tests/regression/ba-issues/issues/issue-3467/tt_unreachable.wasm b/tests/regression/ba-issues/issues/issue-3467/tt_unreachable.wasm new file mode 100644 index 0000000000..9f56fb5e54 Binary files /dev/null and b/tests/regression/ba-issues/issues/issue-3467/tt_unreachable.wasm differ diff --git a/tests/regression/ba-issues/issues/issue-3468/i64.add.wasm b/tests/regression/ba-issues/issues/issue-3468/i64.add.wasm new file mode 100644 index 0000000000..ea40df1714 Binary files /dev/null and b/tests/regression/ba-issues/issues/issue-3468/i64.add.wasm differ diff --git a/tests/regression/ba-issues/issues/issue-3491/nop_0LM_592_17171016522810388.wasm b/tests/regression/ba-issues/issues/issue-3491/nop_0LM_592_17171016522810388.wasm new file mode 100644 index 0000000000..5de7a3ce55 Binary files /dev/null and b/tests/regression/ba-issues/issues/issue-3491/nop_0LM_592_17171016522810388.wasm differ diff --git a/tests/regression/ba-issues/running_config.json b/tests/regression/ba-issues/running_config.json index 7ec213e4d5..e50b108bd0 100644 --- a/tests/regression/ba-issues/running_config.json +++ b/tests/regression/ba-issues/running_config.json @@ -912,7 +912,7 @@ "options": "", "argument": "", "expected return": { - "ret code": 57, + "ret code": 8, "stdout content": "", "description": "sock_shutdown on a non-socket file descriptor should fail with 57 notsock" } @@ -1674,6 +1674,54 @@ "stdout content": "Hello from Kotlin via WASI\nCurrent 'realtime' timestamp is:", "description": "no 'type mismatch: expect (ref null ht) but got other1 unknown type'" } + }, + { + "deprecated": false, + "ids": [ + 3467 + ], + "runtime": "iwasm-default-wasi-disabled", + "file": "tt_unreachable.wasm", + "mode": "fast-interp", + "options": "--heap-size=0 -f to_test", + "argument": "", + "expected return": { + "ret code": 1, + "stdout content": "Exception: unreachable", + "description": "no '-1.861157e+19:f32'" + } + }, + { + "deprecated": false, + "ids": [ + 3468 + ], + "runtime": "iwasm-default-wasi-disabled", + "file": "i64.add.wasm", + "mode": "fast-interp", + "options": "--heap-size=0 -f to_test", + "argument": "", + "expected return": { + "ret code": 255, + "stdout content": "WASM module load failed: unknown type", + "description": "no '0x0:i64'" + } + }, + { + "deprecated": false, + "ids": [ + 3491 + ], + "runtime": "iwasm-default-wasi-disabled", + "file": "nop_0LM_592_17171016522810388.wasm", + "mode": "fast-interp", + "options": "", + "argument": "", + "expected return": { + "ret code": 255, + "stdout content": "WASM module load failed: data count and data section have inconsistent lengths", + "description": "Check data segment count" + } } ] } diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index a9a7b8776c..40c9bb6aed 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -1,51 +1,52 @@ -# Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 3.14) +cmake_minimum_required(VERSION 2.9) -project (wamr_unit_tests) +project(unit-test) -include (CTest) +SET(CMAKE_BUILD_TYPE Debug) -if (NOT DEFINED WAMR_BUILD_INTERP) - # Enable Interpreter by default - set (WAMR_BUILD_INTERP 1) -endif () +# add_definitions (-m32) +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") -if (NOT DEFINED WAMR_BUILD_PLATFORM) - string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) -endif () +if(WAMR_BUILD_TARGET STREQUAL "X86_32") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") +endif() -set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) -include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) -add_library (vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +# Prevent overriding the parent project's compiler/linker +# settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +# Fetch Google test include (FetchContent) FetchContent_Declare ( googletest URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip ) -# For Windows: Prevent overriding the parent project's compiler/linker settings -set (gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable (googletest) -include (GoogleTest) - -add_library (wamr_gtest_main main.cpp) -target_link_libraries (wamr_gtest_main PUBLIC gtest vmlib) - -function (create_wamr_unit_test test_name) - set (sources ${ARGN}) - add_executable (${test_name} ${sources}) - target_link_libraries ( - ${test_name} - wamr_gtest_main - vmlib - ${LLVM_AVAILABLE_LIBS} - ) - gtest_discover_tests (${test_name}) - endfunction () - -if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1) - include (${IWASM_DIR}/libraries/lib-wasi-threads/unit-test/lib_wasi_threads_unit_tests.cmake) -endif () +SET(GOOGLETEST_INCLUDED 1) + +include(GoogleTest) +enable_testing() + +add_subdirectory(wasm-vm) +add_subdirectory(interpreter) +add_subdirectory(aot) +add_subdirectory(wasm-c-api) +add_subdirectory(libc-builtin) +add_subdirectory(shared-utils) +add_subdirectory(running-modes) +add_subdirectory(runtime-common) +add_subdirectory(custom-section) +add_subdirectory(compilation) +add_subdirectory(linear-memory-wasm) +add_subdirectory(linear-memory-aot) +add_subdirectory(aot-stack-frame) +add_subdirectory(linux-perf) +add_subdirectory(gc) +add_subdirectory(memory64) +add_subdirectory(tid-allocator) diff --git a/tests/unit/aot-stack-frame/CMakeLists.txt b/tests/unit/aot-stack-frame/CMakeLists.txt new file mode 100644 index 0000000000..9ff066f08c --- /dev/null +++ b/tests/unit/aot-stack-frame/CMakeLists.txt @@ -0,0 +1,55 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-aot-stack-frame) + +add_definitions (-DRUN_ON_LINUX) + +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_INTERP 0) +set (WAMR_BUILD_JIT 0) +set (WAMR_BUILD_SIMD 1) +set (WAMR_BUILD_REF_TYPES 1) +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_LIBC_BUILTIN 0) +set (WAMR_BUILD_MULTI_MODULE 0) +set (WAMR_DISABLE_HW_BOUND_CHECK 1) +set (WAMR_DISABLE_WRITE_GS_BASE 1) + +include (../unit_common.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +add_definitions (-DWASM_ENABLE_AOT_STACK_FRAME=1) +add_definitions (-DAOT_STACK_FRAME_DEBUG) +#add_definitions (-DWASM_ENABLE_DUMP_CALL_STACK=1) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ${IWASM_COMMON_SOURCE} + ${IWASM_INTERP_SOURCE} + ${IWASM_AOT_SOURCE} + ${WASM_APP_LIB_SOURCE_ALL} + ) + +# Automatically build wasm-apps for this test +add_subdirectory(wasm-apps) + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable (aot_stack_frame_test ${unit_test_sources}) + +add_dependencies (aot_stack_frame_test aot-stack-frame-test-wasm) + +target_link_libraries (aot_stack_frame_test ${LLVM_AVAILABLE_LIBS} gtest_main ) + +#gtest_discover_tests(aot_stack_frame_test) \ No newline at end of file diff --git a/tests/unit/aot-stack-frame/aot_stack_frame_test.cc b/tests/unit/aot-stack-frame/aot_stack_frame_test.cc new file mode 100644 index 0000000000..9bea2b2a03 --- /dev/null +++ b/tests/unit/aot-stack-frame/aot_stack_frame_test.cc @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "gtest/gtest.h" +#include "bh_platform.h" +#include "wasm_runtime_common.h" +#include "aot_runtime.h" +#include "test_helper.h" + +#ifndef __aligned +#define __aligned(n) +#endif +#include "wasm-apps/test_aot.h" + +typedef struct MyAOTFrame { + uintptr_t func_index; + + /* Instruction pointer: offset to the bytecode array */ + uintptr_t ip_offset; + + /* Operand stack top pointer of the current frame */ + uint32 *sp; + +#if WASM_ENABLE_GC != 0 + /* Frame ref flags (GC only) */ + uint8 *frame_ref; +#endif + + uint32 lp[1]; +} MyAOTFrame; + +class AOTStackFrameTest : public testing::Test +{ + protected: + virtual void SetUp() + { + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + ASSERT_EQ(wasm_runtime_full_init(&init_args), true); + } + + virtual void TearDown() + { + DestroyFrames(); + wasm_runtime_destroy(); + } + + public: + static void DestroyFrames() + { + if (my_frames) { + for (uint32 i = 0; i < my_frame_num; i++) { + if (my_frames[i]) + wasm_runtime_free(my_frames[i]); + } + wasm_runtime_free(my_frames); + my_frames = NULL; + my_frame_num = 0; + } + } + + public: + RuntimeInitArgs init_args; + wasm_module_t module = NULL; + wasm_module_inst_t module_inst = NULL; + wasm_function_inst_t func_inst = NULL; + wasm_exec_env_t exec_env = NULL; + static MyAOTFrame **my_frames; + static uint32 my_frame_num; + char error_buf[128]; + char global_heap_buf[512 * 1024]; + unsigned char test_aot_buf[16 * 1024]; + unsigned argv[8]; +}; + +MyAOTFrame **AOTStackFrameTest::my_frames = NULL; +uint32 AOTStackFrameTest::my_frame_num = 0; + +extern "C" { + +typedef void (*stack_frame_callback_t)(struct WASMExecEnv *exec_env); + +void +aot_set_stack_frame_callback(stack_frame_callback_t callback); + +void +aot_stack_frame_cb(struct WASMExecEnv *exec_env) +{ + AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst; + AOTModule *module = (AOTModule *)module_inst->module; + AOTFrame *frame = (AOTFrame *)exec_env->cur_frame; + MyAOTFrame *my_frame, **my_frames; + uint32 all_cell_num, max_local_cell_num, max_stack_cell_num; + uint32 frame_size_old, frame_size, i, frame_num = 0, aot_func_idx; + + AOTStackFrameTest::DestroyFrames(); + + while (frame) { + frame_num++; + frame = frame->prev_frame; + } + + my_frames = + (MyAOTFrame **)wasm_runtime_malloc(sizeof(MyAOTFrame *) * frame_num); + bh_assert(my_frames); + + frame = (AOTFrame *)exec_env->cur_frame; + for (i = 0; i < frame_num; i++) { + aot_func_idx = frame->func_index; + max_local_cell_num = module->max_local_cell_nums[aot_func_idx]; + max_stack_cell_num = module->max_stack_cell_nums[aot_func_idx]; + all_cell_num = max_local_cell_num + max_stack_cell_num; + + frame_size_old = (uint32)offsetof(AOTFrame, lp) + all_cell_num * 4; + frame_size = (uint32)offsetof(MyAOTFrame, lp) + all_cell_num * 4; + + my_frames[frame_num - 1 - i] = my_frame = + (MyAOTFrame *)wasm_runtime_malloc(frame_size); + + my_frame->func_index = aot_func_idx; + my_frame->ip_offset = frame->ip_offset; + my_frame->sp = my_frame->lp + (frame->sp - frame->lp); +#if WASM_ENABLE_GC != 0 + my_frame->frame_ref = + (uint8 *)my_frame->lp + (frame->frame_ref - (uint8 *)frame->lp); +#endif + + bh_memcpy_s(my_frame->lp, all_cell_num * 4, frame->lp, + all_cell_num * 4); + + frame = frame->prev_frame; + } + + AOTStackFrameTest::my_frames = my_frames; + AOTStackFrameTest::my_frame_num = frame_num; +} +} + +TEST_F(AOTStackFrameTest, test1) +{ + MyAOTFrame *frame, **frames; + uint32 frame_num; + + aot_set_stack_frame_callback(aot_stack_frame_cb); + + bh_memcpy_s(test_aot_buf, sizeof(test_aot_buf), test_aot, sizeof(test_aot)); + + module = wasm_runtime_load(test_aot_buf, sizeof(test_aot), error_buf, + sizeof(error_buf)); + ASSERT_TRUE(module != NULL); + + module_inst = wasm_runtime_instantiate(module, 16384, 0, error_buf, + sizeof(error_buf)); + ASSERT_TRUE(module_inst != NULL); + + exec_env = wasm_runtime_create_exec_env(module_inst, 8 * 1024); + ASSERT_TRUE(exec_env != NULL); + + func_inst = wasm_runtime_lookup_function(module_inst, "test1"); + ASSERT_TRUE(func_inst != NULL); + + argv[0] = 33; + argv[1] = 44; + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst)); + + frames = AOTStackFrameTest::my_frames; + frame_num = AOTStackFrameTest::my_frame_num; + + ASSERT_TRUE(frames != NULL); + ASSERT_TRUE(frame_num == 1); + + ASSERT_TRUE(frames[0]->lp[0] == 33); + ASSERT_TRUE(frames[0]->lp[1] == 44); + ASSERT_TRUE(frames[0]->lp[2] == 0x11223344); + ASSERT_TRUE(*(uint64 *)(frames[0]->lp + 3) == 0x12345678ABCDEF99LL); + ASSERT_TRUE(*(float *)(frames[0]->lp + 5) == 5566.7788f); + ASSERT_TRUE(*(double *)(frames[0]->lp + 6) == 99887766.55443322); + + wasm_runtime_destroy_exec_env(exec_env); + exec_env = NULL; + + wasm_runtime_deinstantiate(module_inst); + module_inst = NULL; + + wasm_runtime_unload(module); + module = NULL; +} + +TEST_F(AOTStackFrameTest, test2) +{ + MyAOTFrame *frame, **frames; + uint32 frame_num; + + aot_set_stack_frame_callback(aot_stack_frame_cb); + + bh_memcpy_s(test_aot_buf, sizeof(test_aot_buf), test_aot, sizeof(test_aot)); + + module = wasm_runtime_load(test_aot_buf, sizeof(test_aot), error_buf, + sizeof(error_buf)); + ASSERT_TRUE(module != NULL); + + module_inst = wasm_runtime_instantiate(module, 16384, 0, error_buf, + sizeof(error_buf)); + ASSERT_TRUE(module_inst != NULL); + + exec_env = wasm_runtime_create_exec_env(module_inst, 8 * 1024); + ASSERT_TRUE(exec_env != NULL); + + func_inst = wasm_runtime_lookup_function(module_inst, "test2"); + ASSERT_TRUE(func_inst != NULL); + + argv[0] = 1234; + argv[1] = 5678; + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst)); + + frames = AOTStackFrameTest::my_frames; + frame_num = AOTStackFrameTest::my_frame_num; + + ASSERT_TRUE(frames != NULL); + ASSERT_TRUE(frame_num == 1); + + ASSERT_TRUE(frames[0]->lp[0] == 1234); + ASSERT_TRUE(frames[0]->lp[1] == 5678); + ASSERT_TRUE(frames[0]->lp[2] == 0x11223344); + ASSERT_TRUE(*(uint64 *)(frames[0]->lp + 3) == 0x12345678ABCDEF99LL); + ASSERT_TRUE(*(float *)(frames[0]->lp + 5) == 5566.7788f); + ASSERT_TRUE(*(double *)(frames[0]->lp + 6) == 99887766.55443322); + ASSERT_TRUE(frames[0]->lp[8] == 0x1234); + ASSERT_TRUE(frames[0]->lp[9] == 0x5678); +} + +TEST_F(AOTStackFrameTest, test3) +{ + MyAOTFrame *frame, **frames; + uint32 frame_num; + + aot_set_stack_frame_callback(aot_stack_frame_cb); + + bh_memcpy_s(test_aot_buf, sizeof(test_aot_buf), test_aot, sizeof(test_aot)); + + module = wasm_runtime_load(test_aot_buf, sizeof(test_aot), error_buf, + sizeof(error_buf)); + ASSERT_TRUE(module != NULL); + + module_inst = wasm_runtime_instantiate(module, 16384, 0, error_buf, + sizeof(error_buf)); + ASSERT_TRUE(module_inst != NULL); + + exec_env = wasm_runtime_create_exec_env(module_inst, 8 * 1024); + ASSERT_TRUE(exec_env != NULL); + + func_inst = wasm_runtime_lookup_function(module_inst, "test3"); + ASSERT_TRUE(func_inst != NULL); + + argv[0] = 1234; + argv[1] = 5678; + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst)); + + frames = AOTStackFrameTest::my_frames; + frame_num = AOTStackFrameTest::my_frame_num; + + ASSERT_TRUE(frames != NULL); + ASSERT_TRUE(frame_num == 2); + + ASSERT_TRUE(frames[0]->sp - frames[0]->lp == 5); + ASSERT_TRUE(frames[0]->ip_offset == 24); + + ASSERT_TRUE(frames[0]->lp[0] == 1234); + ASSERT_TRUE(frames[0]->lp[1] == 5678); + ASSERT_TRUE(frames[0]->lp[2] == 0x11223344); + ASSERT_TRUE(*(uint64 *)(frames[0]->lp + 3) == 0x12345678ABCDEF99LL); + + ASSERT_TRUE(frames[1]->lp[0] == 0x1234); + ASSERT_TRUE(frames[1]->lp[1] == 0x5678); + ASSERT_TRUE(frames[1]->lp[2] == 0x11223344); + ASSERT_TRUE(*(uint64 *)(frames[1]->lp + 3) == 0x12345678ABCDEF99LL); + ASSERT_TRUE(*(float *)(frames[1]->lp + 5) == 5566.7788f); + ASSERT_TRUE(*(double *)(frames[1]->lp + 6) == 99887766.55443322); +} diff --git a/tests/unit/aot-stack-frame/wasm-apps/CMakeLists.txt b/tests/unit/aot-stack-frame/wasm-apps/CMakeLists.txt new file mode 100644 index 0000000000..9dd9565a5d --- /dev/null +++ b/tests/unit/aot-stack-frame/wasm-apps/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project(wasm-apps-aot-stack-frame) + +add_custom_target(aot-stack-frame-test-wasm ALL + COMMAND cmake -B ${CMAKE_CURRENT_BINARY_DIR}/build-wamrc + -S ${WAMR_ROOT_DIR}/wamr-compiler + && cmake --build ${CMAKE_CURRENT_BINARY_DIR}/build-wamrc + && /opt/wabt/bin/wat2wasm + -o ${CMAKE_CURRENT_BINARY_DIR}/test.wasm + ${CMAKE_CURRENT_LIST_DIR}/test.wast + && ${CMAKE_CURRENT_BINARY_DIR}/build-wamrc/wamrc + --enable-dump-call-stack --bounds-checks=1 + -o ${CMAKE_CURRENT_BINARY_DIR}/test.aot + ${CMAKE_CURRENT_BINARY_DIR}/test.wasm + && cmake -B ${CMAKE_CURRENT_BINARY_DIR}/build-binarydump + -S ${WAMR_ROOT_DIR}/test-tools/binarydump-tool + && cmake --build ${CMAKE_CURRENT_BINARY_DIR}/build-binarydump + && ${CMAKE_CURRENT_BINARY_DIR}/build-binarydump/binarydump + -o ${CMAKE_CURRENT_LIST_DIR}/test_aot.h -n test_aot + ${CMAKE_CURRENT_BINARY_DIR}/test.aot + +) + diff --git a/tests/unit/aot-stack-frame/wasm-apps/test.wast b/tests/unit/aot-stack-frame/wasm-apps/test.wast new file mode 100644 index 0000000000..1ef866efc6 --- /dev/null +++ b/tests/unit/aot-stack-frame/wasm-apps/test.wast @@ -0,0 +1,36 @@ +(module + (func $test1 (export "test1") (param i32 i32) (result i32) + i32.const 0x11223344 + i64.const 0x1234_5678_ABCD_EF99 + f32.const 5566.7788 + f64.const 99887766.55443322 + unreachable + ) + + (func $test2 (export "test2") (param f32 f32) (result i32) + i32.const 0x11223344 + i64.const 0x1234_5678_ABCD_EF99 + f32.const 5566.7788 + f64.const 99887766.55443322 + + loop + i32.const 0x1234 + i32.const 0x5678 + unreachable + end + + unreachable + ) + + (func $test3 (export "test3") (param i32 i32) (result i32) + i32.const 0x11223344 + i64.const 0x1234_5678_ABCD_EF99 + + i32.const 0x1234 + i32.const 0x5678 + call $test1 + + drop + drop + ) +) diff --git a/tests/unit/aot/CMakeLists.txt b/tests/unit/aot/CMakeLists.txt new file mode 100644 index 0000000000..6b9c70c888 --- /dev/null +++ b/tests/unit/aot/CMakeLists.txt @@ -0,0 +1,59 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-aot) + +add_definitions (-DRUN_ON_LINUX) + +add_definitions (-Dattr_container_malloc=malloc) +add_definitions (-Dattr_container_free=free) +add_definitions (-DWASM_ENABLE_WAMR_COMPILER=1) +add_definitions (-DWASM_ENABLE_DUMP_CALL_STACK=1) +add_definitions (-DWASM_ENABLE_AOT_STACK_FRAME=1) + +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 1) + +include (../unit_common.cmake) + +set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") +if (NOT EXISTS "${LLVM_SRC_ROOT}/build") + message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") +endif () +set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include (${IWASM_DIR}/compilation/iwasm_compl.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ${LIBC_BUILTIN_SOURCE} + ${IWASM_COMMON_SOURCE} + ${IWASM_INTERP_SOURCE} + ${IWASM_AOT_SOURCE} + ${IWASM_COMPL_SOURCE} + ) + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable (aot_test ${unit_test_sources}) + +target_link_libraries (aot_test ${LLVM_AVAILABLE_LIBS} gtest_main ) + +gtest_discover_tests(aot_test) + diff --git a/tests/unit/aot/aot_test.cc b/tests/unit/aot/aot_test.cc new file mode 100644 index 0000000000..261b378e46 --- /dev/null +++ b/tests/unit/aot/aot_test.cc @@ -0,0 +1,1190 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include "gtest/gtest.h" +#include "wasm_export.h" +#include "bh_platform.h" +#include "aot_llvm.h" +#include "aot_intrinsic.h" +#include "aot.h" + +#define G_INTRINSIC_COUNT (50u) +#define CONS(num) ("f##num##.const") + +const char *llvm_intrinsic_tmp[G_INTRINSIC_COUNT] = { + "llvm.experimental.constrained.fadd.f32", + "llvm.experimental.constrained.fadd.f64", + "llvm.experimental.constrained.fsub.f32", + "llvm.experimental.constrained.fsub.f64", + "llvm.experimental.constrained.fmul.f32", + "llvm.experimental.constrained.fmul.f64", + "llvm.experimental.constrained.fdiv.f32", + "llvm.experimental.constrained.fdiv.f64", + "llvm.fabs.f32", + "llvm.fabs.f64", + "llvm.ceil.f32", + "llvm.ceil.f64", + "llvm.floor.f32", + "llvm.floor.f64", + "llvm.trunc.f32", + "llvm.trunc.f64", + "llvm.rint.f32", + "llvm.rint.f64", + "llvm.sqrt.f32", + "llvm.sqrt.f64", + "llvm.copysign.f32", + "llvm.copysign.f64", + "llvm.minnum.f32", + "llvm.minnum.f64", + "llvm.maxnum.f32", + "llvm.maxnum.f64", + "llvm.ctlz.i32", + "llvm.ctlz.i64", + "llvm.cttz.i32", + "llvm.cttz.i64", + "llvm.ctpop.i32", + "llvm.ctpop.i64", + "f64_convert_i32_s", + "f64_convert_i32_u", + "f32_convert_i32_s", + "f32_convert_i32_u", + "f64_convert_i64_s", + "f64_convert_i64_u", + "f32_convert_i64_s", + "f32_convert_i64_u", + "i32_trunc_f32_u", + "i32_trunc_f32_s", + "i32_trunc_f64_u", + "i32_trunc_f64_s", + "f32_demote_f64", + "f64_promote_f32", + "f32_cmp", + "f64_cmp", + "f32.const", + "f64.const", +}; + +uint64 g_intrinsic_flag[G_INTRINSIC_COUNT] = { + AOT_INTRINSIC_FLAG_F32_FADD, AOT_INTRINSIC_FLAG_F64_FADD, + AOT_INTRINSIC_FLAG_F32_FSUB, AOT_INTRINSIC_FLAG_F64_FSUB, + AOT_INTRINSIC_FLAG_F32_FMUL, AOT_INTRINSIC_FLAG_F64_FMUL, + AOT_INTRINSIC_FLAG_F32_FDIV, AOT_INTRINSIC_FLAG_F64_FDIV, + AOT_INTRINSIC_FLAG_F32_FABS, AOT_INTRINSIC_FLAG_F64_FABS, + AOT_INTRINSIC_FLAG_F32_CEIL, AOT_INTRINSIC_FLAG_F64_CEIL, + AOT_INTRINSIC_FLAG_F32_FLOOR, AOT_INTRINSIC_FLAG_F64_FLOOR, + AOT_INTRINSIC_FLAG_F32_TRUNC, AOT_INTRINSIC_FLAG_F64_TRUNC, + AOT_INTRINSIC_FLAG_F32_RINT, AOT_INTRINSIC_FLAG_F64_RINT, + AOT_INTRINSIC_FLAG_F32_SQRT, AOT_INTRINSIC_FLAG_F64_SQRT, + AOT_INTRINSIC_FLAG_F32_COPYSIGN, AOT_INTRINSIC_FLAG_F64_COPYSIGN, + AOT_INTRINSIC_FLAG_F32_MIN, AOT_INTRINSIC_FLAG_F64_MIN, + AOT_INTRINSIC_FLAG_F32_MAX, AOT_INTRINSIC_FLAG_F64_MAX, + AOT_INTRINSIC_FLAG_I32_CLZ, AOT_INTRINSIC_FLAG_I64_CLZ, + AOT_INTRINSIC_FLAG_I32_CTZ, AOT_INTRINSIC_FLAG_I64_CTZ, + AOT_INTRINSIC_FLAG_I32_POPCNT, AOT_INTRINSIC_FLAG_I64_POPCNT, + AOT_INTRINSIC_FLAG_I32_TO_F64, AOT_INTRINSIC_FLAG_U32_TO_F64, + AOT_INTRINSIC_FLAG_I32_TO_F32, AOT_INTRINSIC_FLAG_U32_TO_F32, + AOT_INTRINSIC_FLAG_I32_TO_F64, AOT_INTRINSIC_FLAG_U64_TO_F64, + AOT_INTRINSIC_FLAG_I64_TO_F32, AOT_INTRINSIC_FLAG_U64_TO_F32, + AOT_INTRINSIC_FLAG_F32_TO_U32, AOT_INTRINSIC_FLAG_F32_TO_I32, + AOT_INTRINSIC_FLAG_F64_TO_U32, AOT_INTRINSIC_FLAG_F64_TO_I32, + AOT_INTRINSIC_FLAG_F64_TO_F32, AOT_INTRINSIC_FLAG_F32_TO_F64, + AOT_INTRINSIC_FLAG_F32_CMP, AOT_INTRINSIC_FLAG_F64_CMP, + AOT_INTRINSIC_FLAG_F32_CONST, AOT_INTRINSIC_FLAG_F64_CONST, +}; + +// To use a test fixture, derive a class from testing::Test. +class AOTTest : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() + { + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + ASSERT_EQ(wasm_runtime_full_init(&init_args), true); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() { wasm_runtime_destroy(); } + + public: + char global_heap_buf[512 * 1024]; + RuntimeInitArgs init_args; +}; + +TEST_F(AOTTest, aot_value_stack_push_pop) +{ + AOTValueStack *stack; + AOTValue *value1, *value2, *value3; + AOTCompContext comp_ctx = { 0 }; + + stack = (AOTValueStack *)wasm_runtime_malloc(sizeof(AOTValueStack)); + EXPECT_TRUE(stack != NULL); + + memset(stack, 0, sizeof(AOTValueStack)); + + value1 = (AOTValue *)wasm_runtime_malloc(sizeof(AOTValue)); + EXPECT_TRUE(value1 != NULL); + + memset(value1, 0, sizeof(AOTValue)); + value1->type = VALUE_TYPE_I32; + + aot_value_stack_push(&comp_ctx, stack, value1); + EXPECT_EQ(stack->value_list_head, value1); + EXPECT_EQ(stack->value_list_end, value1); + + value2 = (AOTValue *)wasm_runtime_malloc(sizeof(AOTValue)); + EXPECT_TRUE(value2 != NULL); + + memset(value2, 0, sizeof(AOTValue)); + value2->type = VALUE_TYPE_I64; + + aot_value_stack_push(&comp_ctx, stack, value2); + EXPECT_EQ(stack->value_list_head, value1); + EXPECT_EQ(stack->value_list_end, value2); + EXPECT_EQ(value2->prev, value1); + + value3 = aot_value_stack_pop(&comp_ctx, stack); + EXPECT_EQ(value3, value2); + EXPECT_EQ(stack->value_list_head, value1); + EXPECT_EQ(stack->value_list_end, value1); + EXPECT_TRUE(value3->prev == NULL); + + aot_value_stack_destroy(&comp_ctx, stack); + wasm_runtime_free(value3); + wasm_runtime_free(stack); +} + +TEST_F(AOTTest, aot_block_stack_push_pop) +{ + AOTBlockStack *stack; + AOTBlock *block1, *block2, *block3; + AOTCompContext comp_ctx = { 0 }; + + stack = (AOTBlockStack *)wasm_runtime_malloc(sizeof(AOTBlockStack)); + EXPECT_TRUE(stack != NULL); + + memset(stack, 0, sizeof(AOTBlockStack)); + + block1 = (AOTBlock *)wasm_runtime_malloc(sizeof(AOTBlock)); + EXPECT_TRUE(block1 != NULL); + + memset(block1, 0, sizeof(AOTBlock)); + block1->label_type = LABEL_TYPE_LOOP; + + aot_block_stack_push(stack, block1); + EXPECT_EQ(stack->block_list_head, block1); + EXPECT_EQ(stack->block_list_end, block1); + + block2 = (AOTBlock *)wasm_runtime_malloc(sizeof(AOTBlock)); + EXPECT_TRUE(block2 != NULL); + + memset(block2, 0, sizeof(AOTBlock)); + block2->label_type = LABEL_TYPE_IF; + + aot_block_stack_push(stack, block2); + EXPECT_EQ(stack->block_list_head, block1); + EXPECT_EQ(stack->block_list_end, block2); + EXPECT_EQ(block2->prev, block1); + + block3 = aot_block_stack_pop(stack); + EXPECT_EQ(block3, block2); + EXPECT_EQ(stack->block_list_head, block1); + EXPECT_EQ(stack->block_list_end, block1); + EXPECT_TRUE(block3->prev == NULL); + + aot_block_stack_destroy(&comp_ctx, stack); + wasm_runtime_free(block3); + wasm_runtime_free(stack); +} + +TEST_F(AOTTest, aot_intrinsic_fadd_f32) +{ + float32 a = 1.0; + float32 b = 1.0; + EXPECT_EQ(aot_intrinsic_fadd_f32(a, b), (a + b)); + + a = -1.0; + b = -1.0; + EXPECT_EQ(aot_intrinsic_fadd_f32(a, b), (a + b)); +} + +TEST_F(AOTTest, aot_intrinsic_fadd_f64) +{ + float64 a = 1.0; + float64 b = 1.0; + EXPECT_EQ(aot_intrinsic_fadd_f64(a, b), (a + b)); + + a = -1.0; + b = -1.0; + EXPECT_EQ(aot_intrinsic_fadd_f64(a, b), (a + b)); +} + +TEST_F(AOTTest, aot_intrinsic_fsub_f32) +{ + float32 a = 1.0; + float32 b = 1.0; + EXPECT_EQ(aot_intrinsic_fsub_f32(a, b), (a - b)); + + a = -1.0; + b = -1.0; + EXPECT_EQ(aot_intrinsic_fsub_f32(a, b), (a - b)); +} + +TEST_F(AOTTest, aot_intrinsic_fsub_f64) +{ + float64 a = 1.0; + float64 b = 1.0; + EXPECT_EQ(aot_intrinsic_fsub_f64(a, b), (a - b)); + + a = -1.0; + b = -1.0; + EXPECT_EQ(aot_intrinsic_fsub_f64(a, b), (a - b)); +} + +TEST_F(AOTTest, aot_intrinsic_fmul_f32) +{ + float32 a = 1.0; + float32 b = 1.0; + EXPECT_EQ(aot_intrinsic_fmul_f32(a, b), (a * b)); + + a = -1.0; + b = -1.0; + EXPECT_EQ(aot_intrinsic_fmul_f32(a, b), (a * b)); +} + +TEST_F(AOTTest, aot_intrinsic_fmul_f64) +{ + float64 a = 1.0; + float64 b = 1.0; + EXPECT_EQ(aot_intrinsic_fmul_f64(a, b), (a * b)); + + a = -1.0; + b = -1.0; + EXPECT_EQ(aot_intrinsic_fmul_f64(a, b), (a * b)); +} + +TEST_F(AOTTest, aot_intrinsic_fdiv_f32) +{ + float32 a = 1.0; + float32 b = 1.0; + EXPECT_EQ(aot_intrinsic_fdiv_f32(a, b), (a / b)); + + a = -1.0; + b = -1.0; + EXPECT_EQ(aot_intrinsic_fdiv_f32(a, b), (a / b)); + + a = -1.0; + b = 0.0; + EXPECT_EQ(aot_intrinsic_fdiv_f32(a, b), (a / b)); +} + +TEST_F(AOTTest, aot_intrinsic_fdiv_f64) +{ + float64 a = 1.0; + float64 b = 1.0; + EXPECT_EQ(aot_intrinsic_fdiv_f64(a, b), (a / b)); + + a = -1.0; + b = -1.0; + EXPECT_EQ(aot_intrinsic_fdiv_f64(a, b), (a / b)); + + a = -1.0; + b = 0.0; + EXPECT_EQ(aot_intrinsic_fdiv_f64(a, b), (a / b)); +} + +TEST_F(AOTTest, aot_intrinsic_fabs_f32) +{ + float32 a = 1.0; + EXPECT_EQ(aot_intrinsic_fabs_f32(a), fabs(a)); + + a = -1.0; + EXPECT_EQ(aot_intrinsic_fabs_f32(a), fabs(a)); + + a = -1.5; + EXPECT_EQ(aot_intrinsic_fabs_f32(a), fabs(a)); +} + +TEST_F(AOTTest, aot_intrinsic_fabs_f64) +{ + float64 a = 1.0; + EXPECT_EQ(aot_intrinsic_fabs_f64(a), fabs(a)); + + a = -1.0; + EXPECT_EQ(aot_intrinsic_fabs_f64(a), fabs(a)); + + a = -1.5; + EXPECT_EQ(aot_intrinsic_fabs_f64(a), fabs(a)); +} + +TEST_F(AOTTest, aot_intrinsic_ceil_f32) +{ + float32 a = 1.0; + EXPECT_EQ(aot_intrinsic_ceil_f32(a), ceilf(a)); + + a = 1.1; + EXPECT_EQ(aot_intrinsic_ceil_f32(a), 2); + + a = 1.9; + EXPECT_EQ(aot_intrinsic_ceil_f32(a), 2); + + a = -1.9; + EXPECT_EQ(aot_intrinsic_ceil_f32(a), -1); +} + +TEST_F(AOTTest, aot_intrinsic_ceil_f64) +{ + float64 a = 1.0; + EXPECT_EQ(aot_intrinsic_ceil_f64(a), ceil(a)); + + a = 1.1; + EXPECT_EQ(aot_intrinsic_ceil_f64(a), 2); + + a = 1.9; + EXPECT_EQ(aot_intrinsic_ceil_f64(a), 2); + + a = -1.9; + EXPECT_EQ(aot_intrinsic_ceil_f64(a), -1); +} + +TEST_F(AOTTest, aot_intrinsic_floor_f32) +{ + float32 a = 1.0; + EXPECT_EQ(aot_intrinsic_floor_f32(a), floorf(a)); + + a = 1.1; + EXPECT_EQ(aot_intrinsic_floor_f32(a), 1); + + a = 1.9; + EXPECT_EQ(aot_intrinsic_floor_f32(a), 1); + + a = -1.9; + EXPECT_EQ(aot_intrinsic_floor_f32(a), -2); +} + +TEST_F(AOTTest, aot_intrinsic_floor_f64) +{ + float64 a = 1.0; + EXPECT_EQ(aot_intrinsic_floor_f64(a), floor(a)); + + a = 1.1; + EXPECT_EQ(aot_intrinsic_floor_f64(a), 1); + + a = 1.9; + EXPECT_EQ(aot_intrinsic_floor_f64(a), 1); + + a = -1.9; + EXPECT_EQ(aot_intrinsic_floor_f64(a), -2); +} + +TEST_F(AOTTest, aot_intrinsic_trunc_f32) +{ + float32 a = 1.0; + EXPECT_EQ(aot_intrinsic_trunc_f32(a), trunc(a)); + + a = 1.1; + EXPECT_EQ(aot_intrinsic_trunc_f32(a), 1); + + a = 1.9; + EXPECT_EQ(aot_intrinsic_trunc_f32(a), 1); + + a = -1.9; + EXPECT_EQ(aot_intrinsic_trunc_f32(a), -1); +} + +TEST_F(AOTTest, aot_intrinsic_trunc_f64) +{ + float64 a = 1.0; + EXPECT_EQ(aot_intrinsic_trunc_f64(a), trunc(a)); + + a = 1.1; + EXPECT_EQ(aot_intrinsic_trunc_f64(a), 1); + + a = 1.9; + EXPECT_EQ(aot_intrinsic_trunc_f64(a), 1); + + a = -1.9; + EXPECT_EQ(aot_intrinsic_trunc_f64(a), -1); +} + +TEST_F(AOTTest, aot_intrinsic_rint_f32) +{ + float32 a = 1.0; + EXPECT_EQ(aot_intrinsic_rint_f32(a), rint(a)); + EXPECT_EQ(aot_intrinsic_rint_f32(a), 1); + + a = 1.1; + EXPECT_EQ(aot_intrinsic_rint_f32(a), 1); + + a = 1.9; + EXPECT_EQ(aot_intrinsic_rint_f32(a), 2); + + a = -1.9; + EXPECT_EQ(aot_intrinsic_rint_f32(a), -2); +} + +TEST_F(AOTTest, aot_intrinsic_rint_f64) +{ + float64 a = 1.0; + EXPECT_EQ(aot_intrinsic_rint_f64(a), rint(a)); + EXPECT_EQ(aot_intrinsic_rint_f64(a), 1); + + a = 1.1; + EXPECT_EQ(aot_intrinsic_rint_f64(a), 1); + + a = 1.9; + EXPECT_EQ(aot_intrinsic_rint_f64(a), 2); + + a = -1.9; + EXPECT_EQ(aot_intrinsic_rint_f64(a), -2); +} + +TEST_F(AOTTest, aot_intrinsic_sqrt_f32) +{ + float32 a = 2.0; + EXPECT_EQ(aot_intrinsic_sqrt_f32(a), sqrt(a)); + + a = 2; + EXPECT_EQ(aot_intrinsic_sqrt_f32(a), sqrt(a)); +} + +TEST_F(AOTTest, aot_intrinsic_sqrt_f64) +{ + float64 a = 2.0; + EXPECT_EQ(aot_intrinsic_sqrt_f64(a), sqrt(a)); + + a = 2; + EXPECT_EQ(aot_intrinsic_sqrt_f64(a), sqrt(a)); +} + +TEST_F(AOTTest, aot_intrinsic_copysign_f32) +{ + float32 a = 20.0; + float32 b = 2.0; + + EXPECT_EQ(aot_intrinsic_copysign_f32(a, b), fabs(a)); + + b = 1.5; + EXPECT_EQ(aot_intrinsic_copysign_f32(a, b), fabs(a)); + + b = -2.0; + EXPECT_EQ(aot_intrinsic_copysign_f32(a, b), -fabs(a)); + + a = -20.0; + b = -1.5; + EXPECT_EQ(aot_intrinsic_copysign_f32(a, b), -fabs(a)); +} + +TEST_F(AOTTest, aot_intrinsic_copysign_f64) +{ + float64 a = 20.0; + float64 b = 2.0; + + EXPECT_EQ(aot_intrinsic_copysign_f64(a, b), fabs(a)); + + b = 1.5; + EXPECT_EQ(aot_intrinsic_copysign_f64(a, b), fabs(a)); + + b = -2.0; + EXPECT_EQ(aot_intrinsic_copysign_f64(a, b), -fabs(a)); + + a = -20.0; + b = -1.5; + EXPECT_EQ(aot_intrinsic_copysign_f64(a, b), -fabs(a)); +} + +TEST_F(AOTTest, aot_intrinsic_fmin_f32) +{ + float32 a = 1.2; + float32 b = 2.5; + + EXPECT_EQ(aot_intrinsic_fmin_f32(a, b), a); + + a = -3; + b = -1; + EXPECT_EQ(aot_intrinsic_fmin_f32(a, b), a); + + b = 1; + EXPECT_EQ(aot_intrinsic_fmin_f32('a', b), b); + + a = 3; + EXPECT_EQ(aot_intrinsic_fmin_f32(a, 'b'), a); + + EXPECT_EQ(aot_intrinsic_fmin_f32('a', 'b'), 'a'); + + EXPECT_EQ(aot_intrinsic_fmin_f32('b', 'c'), 'b'); + EXPECT_EQ(aot_intrinsic_fmin_f32('c', 'b'), 'b'); + + EXPECT_EQ(aot_intrinsic_fmin_f32(true, 2.5), 1); + EXPECT_EQ(aot_intrinsic_fmin_f32(1.0, false), 0); + + EXPECT_NE(aot_intrinsic_fmin_f32(sqrt(-1), 3), 3); + EXPECT_NE(aot_intrinsic_fmin_f32(3, sqrt(-1)), 3); +} + +TEST_F(AOTTest, aot_intrinsic_fmin_f64) +{ + float64 a = 1.00000000; + float64 b = 3.00000000; + + EXPECT_EQ(aot_intrinsic_fmin_f64(a, b), a); + + EXPECT_EQ(aot_intrinsic_fmin_f64(-a, b), -a); + + EXPECT_EQ(aot_intrinsic_fmin_f64(-a, -b), -b); + + EXPECT_EQ(aot_intrinsic_fmin_f64(a, -b), -b); + + EXPECT_EQ(aot_intrinsic_fmin_f64(a, a), a); + + a = 0.0000; + EXPECT_EQ(aot_intrinsic_fmin_f64(-a, -a), -a); +} + +TEST_F(AOTTest, aot_intrinsic_fmax_f32) +{ + float32 a = 1.2; + float32 b = 2.5; + + EXPECT_EQ(aot_intrinsic_fmax_f32(a, b), b); + + a = -3; + b = -1; + EXPECT_EQ(aot_intrinsic_fmax_f32(a, b), b); + + b = 1; + EXPECT_EQ(aot_intrinsic_fmax_f32('a', b), 'a'); + + a = 3; + EXPECT_EQ(aot_intrinsic_fmax_f32(a, 'b'), 'b'); + + EXPECT_EQ(aot_intrinsic_fmax_f32('a', 'b'), 'b'); + + EXPECT_EQ(aot_intrinsic_fmax_f32(' ', 'b'), 'b'); + EXPECT_EQ(aot_intrinsic_fmax_f32('a', ' '), 'a'); + + EXPECT_NE(aot_intrinsic_fmax_f32(sqrt(-1), 3), 3); + EXPECT_NE(aot_intrinsic_fmax_f32(3, sqrt(-1)), 3); +} + +TEST_F(AOTTest, aot_intrinsic_fmax_f64) +{ + float64 a = 1.00000000; + float64 b = 3.00000000; + + EXPECT_EQ(aot_intrinsic_fmax_f64(a, b), b); + + EXPECT_EQ(aot_intrinsic_fmax_f64(-a, b), b); + + EXPECT_EQ(aot_intrinsic_fmax_f64(-a, -b), -a); + + EXPECT_EQ(aot_intrinsic_fmax_f64(a, -b), a); + + EXPECT_EQ(aot_intrinsic_fmax_f64(a, a), a); + + a = 0.0000; + EXPECT_EQ(aot_intrinsic_fmax_f64(-a, -a), -a); + + EXPECT_EQ(aot_intrinsic_fmax_f64(-0, -0), -0); +} + +TEST_F(AOTTest, aot_intrinsic_clz_i32) +{ + uint32 type = 0; + uint32 data = 0; + uint32 num = 0; + + EXPECT_EQ(aot_intrinsic_clz_i32(0), 32); + + for (uint32 i = 0; i < 0xFFFF; i++) { + /* Generate random numbers [1,0xFFFFFFFF] */ + type = 1 + (rand() % (0xFFFFFFFF - 1 + 1)); + data = type; + while (!(type & 0x80000000)) { + num++; + type <<= 1; + } + EXPECT_EQ(aot_intrinsic_clz_i32(data), num); + num = 0; + } + + EXPECT_EQ(aot_intrinsic_clz_i32(0xFFFFFFFF), 0); +} + +TEST_F(AOTTest, aot_intrinsic_clz_i64) +{ + uint64 type = 0; + uint64 data = 0; + uint64 num = 0; + + EXPECT_EQ(aot_intrinsic_clz_i64(0), 64); + + for (uint32 i = 0; i < 0xFFFFF; i++) { + /* Generate random numbers [1,0xFFFFFFFFFFFFFFFF] */ + type = 1 + (rand() % (0xFFFFFFFFFFFFFFFF - 1 + 1)); + data = type; + while (!(type & 0x8000000000000000LL)) { + num++; + type <<= 1; + } + EXPECT_EQ(aot_intrinsic_clz_i64(data), num); + num = 0; + } + + EXPECT_EQ(aot_intrinsic_clz_i64(0xFFFFFFFFFFFFFFFF), 0); +} + +TEST_F(AOTTest, ast_intrinsic_ctz_i32) +{ + uint32 type = 0; + uint32 data = 0; + uint32 num = 0; + + EXPECT_EQ(aot_intrinsic_ctz_i32(0), 32); + + for (uint32 i = 0; i < 0xFFFF; i++) { + type = 1 + (rand() % (0xFFFFFFFF - 1 + 1)); + data = type; + while (!(type & 1)) { + num++; + type >>= 1; + } + EXPECT_EQ(aot_intrinsic_ctz_i32(data), num); + num = 0; + } + + EXPECT_EQ(aot_intrinsic_ctz_i32(0xFFFFFFFF), 0); +} + +TEST_F(AOTTest, ast_intrinsic_ctz_i64) +{ + uint64 type = 0; + uint64 data = 0; + uint64 num = 0; + + EXPECT_EQ(aot_intrinsic_ctz_i64(0), 64); + + for (uint32 i = 0; i < 0xFFFFF; i++) { + type = 1 + (rand() % (0xFFFFFFFFFFFFFFFF - 1 + 1)); + data = type; + while (!(type & 1)) { + num++; + type >>= 1; + } + EXPECT_EQ(aot_intrinsic_ctz_i64(data), num); + num = 0; + } + + EXPECT_EQ(aot_intrinsic_ctz_i64(0xFFFFFFFFFFFFFFFF), 0); +} + +TEST_F(AOTTest, aot_intrinsic_popcnt_i32) +{ + uint32 data = 0; + uint32 num = 0; + uint32 temp = 0; + + EXPECT_EQ(aot_intrinsic_popcnt_i32(0), 0); + + for (uint32 i = 0; i < 0xFFFF; i++) { + temp = 1 + (rand() % (0x100000000 - 1 + 1)); + data = temp; + + while (temp) { + if (temp & 0x01) + num++; + temp >>= 1; + } + EXPECT_EQ(aot_intrinsic_popcnt_i32(data), num); + num = 0; + } + + EXPECT_EQ(aot_intrinsic_popcnt_i32(0xFFFFFFFF), 32); +} + +TEST_F(AOTTest, aot_intrinsic_popcnt_i64) +{ + uint64 data = 0; + uint64 num = 0; + uint64 temp = 0; + + EXPECT_EQ(aot_intrinsic_popcnt_i64(0x00), 0); + + for (uint32 i = 0; i < 0xFFFFF; i++) { + temp = 1 + (rand() % (0xFFFFFFFFFFFFFFFFLL - 1 + 1)); + data = temp; + + while (temp) { + if (temp & 0x01) + num++; + temp >>= 1; + } + EXPECT_EQ(aot_intrinsic_popcnt_i64(data), num); + num = 0; + } + + EXPECT_EQ(aot_intrinsic_popcnt_i64(0xFFFFFFFFFFFFFFFF), 64); +} + +TEST_F(AOTTest, aot_intrinsic_i32_to_f32) +{ + int32 idata = 0; + + EXPECT_EQ(aot_intrinsic_i32_to_f32(idata), (float32)idata); + + for (uint32 i = 0; i < 0xFFFF; i++) { + idata = (int32)(1 + (rand() % (0xFFFFFFFF - 1 + 1))); + EXPECT_EQ(aot_intrinsic_i32_to_f32(idata), (float32)idata); + } + + idata = 0xFFFFFFFF; + EXPECT_EQ(aot_intrinsic_i32_to_f32(idata), (float32)idata); +} + +TEST_F(AOTTest, aot_intrinsic_u32_to_f32) +{ + uint32 udata = 0; + + EXPECT_EQ(aot_intrinsic_u32_to_f32(udata), (float32)udata); + + for (uint32 i = 0; i < 0xFFFF; i++) { + udata = (uint32)(1 + (rand() % (0xFFFFFFFF - 1 + 1))); + EXPECT_EQ(aot_intrinsic_u32_to_f32(udata), (float32)udata); + } + + udata = 0xFFFFFFFF; + EXPECT_EQ(aot_intrinsic_u32_to_f32(udata), (float32)udata); +} + +TEST_F(AOTTest, aot_intrinsic_i32_to_f64) +{ + int32 idata = 0; + + EXPECT_EQ(aot_intrinsic_i32_to_f64(idata), (float64)idata); + + for (uint32 i = 0; i < 0xFFFF; i++) { + idata = (int32)(1 + (rand() % (0xFFFFFFFF - 1 + 1))); + EXPECT_EQ(aot_intrinsic_i32_to_f64(idata), (float64)idata); + } + + idata = 0xFFFFFFFF; + EXPECT_EQ(aot_intrinsic_i32_to_f64(idata), (float64)idata); +} + +TEST_F(AOTTest, aot_intrinsic_u32_to_f64) +{ + uint32 udata = 0; + + EXPECT_EQ(aot_intrinsic_u32_to_f64(udata), (float64)udata); + + for (uint32 i = 0; i < 0xFFFFF; i++) { + udata = (uint32)(1 + (rand() % (0xFFFFFFFF - 1 + 1))); + EXPECT_EQ(aot_intrinsic_u32_to_f64(udata), (float64)udata); + } + + udata = 0xFFFFFFFF; + EXPECT_EQ(aot_intrinsic_u32_to_f64(udata), (float64)udata); +} + +TEST_F(AOTTest, aot_intrinsic_i64_to_f32) +{ + int64 idata = 0LL; + + EXPECT_EQ(aot_intrinsic_i64_to_f32(idata), (float32)idata); + + for (uint32 i = 0; i < 0xFFFFF; i++) { + idata = (int64)(1 + (rand() % (0xFFFFFFFF - 1 + 1))); + EXPECT_EQ(aot_intrinsic_i64_to_f32(idata), (float32)idata); + } + + idata = 0xFFFFFFFFFFFFFFFFLL; + EXPECT_EQ(aot_intrinsic_i64_to_f32(idata), (float32)idata); +} + +TEST_F(AOTTest, aot_intrinsic_u64_to_f32) +{ + uint64 udata = 0LL; + + EXPECT_EQ(aot_intrinsic_u64_to_f32(udata), (float32)udata); + + for (uint32 i = 0; i < 0xFFFFF; i++) { + udata = (uint64)(1 + (rand() % (0xFFFFFFFF - 1 + 1))); + EXPECT_EQ(aot_intrinsic_u64_to_f32(udata), (float32)udata); + } + + udata = 0xFFFFFFFFFFFFFFFFLL; + EXPECT_EQ(aot_intrinsic_u64_to_f32(udata), (float32)udata); +} + +TEST_F(AOTTest, aot_intrinsic_i64_to_f64) +{ + int64 idata = 0LL; + + EXPECT_EQ(aot_intrinsic_i64_to_f64(idata), float64(idata)); + + for (uint32_t i = 0; i < 0xFFFFF; i++) { + idata = (int64)(1 + (rand() % (0xFFFFFFFFFFFFFFFLL - 1 + 1))); + EXPECT_EQ(aot_intrinsic_i64_to_f64(idata), (float64)idata); + } + + idata = 0xFFFFFFFFFFFFFFFFLL; + EXPECT_EQ(aot_intrinsic_i64_to_f64(idata), (float64)idata); +} + +TEST_F(AOTTest, aot_intrinsic_u64_to_f64) +{ + uint64 udata = 0LL; + + EXPECT_EQ(aot_intrinsic_u64_to_f64(udata), float64(udata)); + + for (uint32_t i = 0; i < 0xFFFFF; i++) { + udata = (uint64)(1 + (rand() % (0xFFFFFFFFFFFFFFFLL - 1 + 1))); + EXPECT_EQ(aot_intrinsic_u64_to_f64(udata), (float64)udata); + } + + udata = 0xFFFFFFFFFFFFFFFFLL; + EXPECT_EQ(aot_intrinsic_u64_to_f64(udata), (float64)udata); +} + +TEST_F(AOTTest, aot_intrinsic_f32_to_i32) +{ + float32 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f32_to_i32(data), (int32)data); + + for (uint32 i = 0; i < 0xFFFF; i++) { + data = (float32)((1 + (rand() % (100 - 1 + 1))) - 0.05); + EXPECT_EQ(aot_intrinsic_f32_to_i32(data), (int32)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f32_to_u32) +{ + float32 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f32_to_u32(data), (uint32)data); + + for (uint32 i = 0; i < 0xFFFF; i++) { + data = (float32)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + EXPECT_EQ(aot_intrinsic_f32_to_u32(data), (uint32)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f32_to_i64) +{ + float32 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f32_to_i64(data), (int64)data); + + for (uint32 i = 0; i < 0xFFFF; i++) { + data = (float32)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + EXPECT_EQ(aot_intrinsic_f32_to_i64(data), (int64)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f32_to_u64) +{ + float32 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f32_to_u64(data), (uint64)data); + + for (uint32 i = 0; i < 0xFFFF; i++) { + data = (float32)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + EXPECT_EQ(aot_intrinsic_f32_to_u64(data), (uint64)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f64_to_i32) +{ + float64 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f64_to_i32(data), (int32)data); + + for (uint32 i = 0; i < 0xFFFFFF; i++) { + data = (float64)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + EXPECT_EQ(aot_intrinsic_f64_to_i32(data), (int32)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f64_to_u32) +{ + float64 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f64_to_u32(data), (uint32)data); + + for (uint32 i = 0; i < 0xFFFFFF; i++) { + data = (float64)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + EXPECT_EQ(aot_intrinsic_f64_to_u32(data), (uint32)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f64_to_i64) +{ + float64 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f64_to_i64(data), (int64)data); + + for (uint32 i = 0; i < 0xFFFFFF; i++) { + data = (float64)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + EXPECT_EQ(aot_intrinsic_f64_to_i64(data), (int64)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f64_to_u64) +{ + float64 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f64_to_u64(data), (uint64)data); + + for (uint32 i = 0; i < 0xFFFFFF; i++) { + data = (float64)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + EXPECT_EQ(aot_intrinsic_f64_to_u64(data), (uint64)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f32_to_f64) +{ + float32 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f32_to_f64(data), (float64)data); + + for (uint32 i = 0; i < 0xFFFF; i++) { + data = (float32)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + EXPECT_EQ(aot_intrinsic_f32_to_f64(data), (float64)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f64_to_f32) +{ + float64 data = 0.0; + + EXPECT_EQ(aot_intrinsic_f64_to_f32(data), (float32)data); + + for (uint32 i = 0; i < 0xFFFFFF; i++) { + data = (float64)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.06); + EXPECT_EQ(aot_intrinsic_f32_to_f64(data), (float32)data); + } +} + +TEST_F(AOTTest, aot_intrinsic_f32_cmp) +{ + float32 lhs = 0.0; + float32 rhs = 0.0; + AOTFloatCond index = FLOAT_EQ; + uint32 res = 0; + + for (uint32 i = 0; i < 0xFFFFFF; i++) { + index = (AOTFloatCond)(1 + (rand() % (6 - 1 + 1))); + lhs = (float32)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + rhs = (float32)((1 + (rand() % (0xFFFFFFFF - 1 + 1))) - 0.05); + + /* cond : 0 */ + EXPECT_EQ(aot_intrinsic_f32_cmp(FLOAT_EQ, lhs, rhs), + lhs == rhs ? 1 : 0); + + /* cond : 1-6 */ + switch (index) { + case FLOAT_LT: // 2 + res = (lhs < rhs ? 1 : 0); + break; + case FLOAT_GT: // 3 + res = (lhs > rhs ? 1 : 0); + break; + case FLOAT_LE: // 4 + res = (lhs <= rhs ? 1 : 0); + break; + case FLOAT_GE: // 5 + res = (lhs >= rhs ? 1 : 0); + break; + case FLOAT_NE: // 1 + res = (isnan(lhs) || isnan(rhs) || lhs != rhs) ? 1 : 0; + break; + case FLOAT_UNO: // 6 + res = (isnan(lhs) || isnan(rhs)) ? 1 : 0; + break; + + default: + break; + } + + EXPECT_EQ(aot_intrinsic_f32_cmp(index, lhs, rhs), res); + index = FLOAT_EQ; + + /* cond : > 6 */ + EXPECT_EQ(aot_intrinsic_f32_cmp((AOTFloatCond)(i + 7), lhs, rhs), 0); + } + + EXPECT_EQ(aot_intrinsic_f32_cmp(FLOAT_NE, true, false), 1); + EXPECT_EQ(aot_intrinsic_f32_cmp(FLOAT_NE, true, true), 0); + + EXPECT_EQ(aot_intrinsic_f32_cmp(FLOAT_UNO, true, false), 0); + EXPECT_EQ(aot_intrinsic_f32_cmp(FLOAT_UNO, true, true), 0); + + EXPECT_EQ(aot_intrinsic_f32_cmp(FLOAT_UNO, 'a', 'b'), 0); +} + +TEST_F(AOTTest, aot_intrinsic_f64_cmp) +{ + float64 lhs = 0.0; + float64 rhs = 0.0; + AOTFloatCond index = FLOAT_EQ; + uint32 res = 0; + + for (uint32 i = 0; i < 0xFFFFFF; i++) { + index = (AOTFloatCond)(1 + (rand() % (6 - 1 + 1))); + lhs = (float32)((1 + (rand() % (0xFFFFFFFFFFFFFFFF - 1 + 1))) - 0.05); + rhs = (float32)((1 + (rand() % (0xFFFFFFFFFFFFFFFF - 1 + 1))) - 0.05); + + /* cond : 0 */ + EXPECT_EQ(aot_intrinsic_f64_cmp(FLOAT_EQ, lhs, rhs), + lhs == rhs ? 1 : 0); + + /* cond : 1-6 */ + switch (index) { + case FLOAT_LT: // 2 + res = (lhs < rhs ? 1 : 0); + break; + case FLOAT_GT: // 3 + res = (lhs > rhs ? 1 : 0); + break; + case FLOAT_LE: // 4 + res = (lhs <= rhs ? 1 : 0); + break; + case FLOAT_GE: // 5 + res = (lhs >= rhs ? 1 : 0); + break; + case FLOAT_NE: // 1 + res = (isnan(lhs) || isnan(rhs) || lhs != rhs) ? 1 : 0; + break; + case FLOAT_UNO: // 6 + res = (isnan(lhs) || isnan(rhs)) ? 1 : 0; + break; + + default: + break; + } + + EXPECT_EQ(aot_intrinsic_f64_cmp(index, lhs, rhs), res); + index = FLOAT_EQ; + + /* cond : > 6 */ + EXPECT_EQ(aot_intrinsic_f64_cmp((AOTFloatCond)(i + 7), lhs, rhs), 0); + } + + EXPECT_EQ(aot_intrinsic_f64_cmp(FLOAT_NE, true, false), 1); + EXPECT_EQ(aot_intrinsic_f64_cmp(FLOAT_NE, true, true), 0); + + EXPECT_EQ(aot_intrinsic_f64_cmp(FLOAT_UNO, true, false), 0); + EXPECT_EQ(aot_intrinsic_f64_cmp(FLOAT_UNO, true, true), 0); + + EXPECT_EQ(aot_intrinsic_f64_cmp(FLOAT_UNO, 'a', 'b'), 0); +} + +TEST_F(AOTTest, aot_intrinsic_get_symbol) +{ + const char *llvm_intrinsic_t = NULL; + + for (int i = 0; i < 2; i++) { + if (i == 0) + llvm_intrinsic_t = CONS(32); + else + llvm_intrinsic_t = CONS(64); + + EXPECT_EQ((const char *)aot_intrinsic_get_symbol(llvm_intrinsic_t), + (const char *)NULL); + } + + for (int i = 0; i < G_INTRINSIC_COUNT - 2; i++) { + EXPECT_NE((const char *)aot_intrinsic_get_symbol(llvm_intrinsic_tmp[i]), + (const char *)NULL); + } +} + +TEST_F(AOTTest, aot_intrinsic_check_capability) +{ + AOTCompContext *comp_ctx = NULL; + AOTCompContext scomp_ctx = { 0 }; + const char *llvm_intrinsic_t = "f64_cmp"; + bool res = false; + uint64 flag = 0; + uint64 group = 0; + + comp_ctx = &scomp_ctx; + memset(comp_ctx->flags, 0, sizeof(comp_ctx->flags)); + + /* + EXPECT_FALSE(aot_intrinsic_check_capability(comp_ctx, (const char + *)NULL)); EXPECT_FALSE(aot_intrinsic_check_capability((const + AOTCompContext *)NULL, llvm_intrinsic_t)); + */ + + EXPECT_FALSE(aot_intrinsic_check_capability(comp_ctx, llvm_intrinsic_t)); + for (int i = 0; i < G_INTRINSIC_COUNT; i++) { + EXPECT_FALSE( + aot_intrinsic_check_capability(comp_ctx, llvm_intrinsic_tmp[i])); + } + + memset(comp_ctx->flags, 1, sizeof(comp_ctx->flags)); + EXPECT_FALSE(aot_intrinsic_check_capability(comp_ctx, llvm_intrinsic_t)); + for (int i = 0; i < G_INTRINSIC_COUNT; i++) { + flag = g_intrinsic_flag[i]; + group = AOT_INTRINSIC_GET_GROUP_FROM_FLAG(flag); + flag &= AOT_INTRINSIC_FLAG_MASK; + + res = aot_intrinsic_check_capability(comp_ctx, llvm_intrinsic_tmp[i]); + if ((flag & 0x01) || (flag & 0x100) || (flag & 0x10000) + || (flag & 0x1000000)) + EXPECT_TRUE(res); + else + EXPECT_FALSE(res); + } +} + +TEST_F(AOTTest, aot_intrinsic_fill_capability_flags) +{ + // AOTCompContext *comp_ctx = NULL; + AOTCompContext scomp_ctx = { 0 }; + + // comp_ctx = &scomp_ctx; + aot_intrinsic_fill_capability_flags(&scomp_ctx); + + AOTCompContext scomp_ctx_1{ + .target_cpu = (char *)"cortex-m7", + }; + strncpy(scomp_ctx_1.target_arch, "thumb", strlen("thumb")); + aot_intrinsic_fill_capability_flags(&scomp_ctx_1); + + AOTCompContext scomp_ctx_2{ + .target_cpu = (char *)"cortex-m4", + }; + strncpy(scomp_ctx_2.target_arch, "thumb", strlen("thumb")); + aot_intrinsic_fill_capability_flags(&scomp_ctx_2); + + AOTCompContext scomp_ctx_3{ + .target_cpu = (char *)"cortex-m4", + }; + strncpy(scomp_ctx_3.target_arch, "riscv", strlen("riscv")); + aot_intrinsic_fill_capability_flags(&scomp_ctx_3); + + AOTCompContext scomp_ctx_4{ + .target_cpu = (char *)"cortex-m4", + }; + strncpy(scomp_ctx_4.target_arch, "intrinsic", strlen("intrinsic")); + aot_intrinsic_fill_capability_flags(&scomp_ctx_4); +} diff --git a/tests/unit/common/mock_allocator.h b/tests/unit/common/mock_allocator.h new file mode 100644 index 0000000000..a57e2dea39 --- /dev/null +++ b/tests/unit/common/mock_allocator.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "wasm_export.h" +#include + +template +class MockAllocator +{ + private: + RuntimeInitArgs init_args; + + public: + MockAllocator() + { + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = (void *)my_malloc; + init_args.mem_alloc_option.allocator.realloc_func = (void *)realloc; + init_args.mem_alloc_option.allocator.free_func = (void *)free; + + /* Set count to INT32_MIN so the initialization will not fail */ + alloc_count = INT32_MIN; + + wasm_runtime_full_init(&init_args); + reset_count(); + } + + ~MockAllocator() { wasm_runtime_destroy(); } + + void reset_count() { alloc_count = 0; } + + protected: + static int32_t alloc_count; + static void *my_malloc(int32_t size) + { + if (alloc_count >= MaxAllocCount) { + return nullptr; + } + + alloc_count++; + + return malloc(size); + } +}; + +template +int32_t MockAllocator::alloc_count = 0; + +class DumpAllocUsage : public MockAllocator +{ + public: + DumpAllocUsage() + : MockAllocator() + {} + + ~DumpAllocUsage() + { + std::cout << "Alloc usage count: " << alloc_count << std::endl; + } +}; + +template +void +LIMIT_MALLOC_COUNT(std::function func) +{ + { + MockAllocator allocator; + func(); + } + + if (AllocRequired > 1) + LIMIT_MALLOC_COUNT(func); +} + +template<> +void +LIMIT_MALLOC_COUNT<0>(std::function func) +{ + { + MockAllocator<0> allocator; + func(); + } +} diff --git a/tests/unit/common/test_helper.h b/tests/unit/common/test_helper.h new file mode 100644 index 0000000000..4db465fc8d --- /dev/null +++ b/tests/unit/common/test_helper.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "wasm_export.h" +#include "gtest/gtest.h" + +#include +#include +#include + +template +class WAMRRuntimeRAII +{ + private: + char global_heap_buf[Size]; + RuntimeInitArgs init_args; + + public: + WAMRRuntimeRAII() + { + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + wasm_runtime_full_init(&init_args); + } + + ~WAMRRuntimeRAII() { wasm_runtime_destroy(); } +}; + +class WAMRModule +{ + private: + wasm_module_t module_; + + public: + WAMRModule(uint8_t *buffer, uint32_t size) + { + module_ = wasm_runtime_load(buffer, size, NULL, 0); + } + + ~WAMRModule() { wasm_runtime_unload(module_); } + + wasm_module_t get() const { return module_; } +}; + +class WAMRInstance +{ + private: + wasm_module_inst_t module_inst_; + + public: + WAMRInstance(WAMRModule &module, uint32_t stack_size = 8192, + uint32_t heap_size = 8192) + { + module_inst_ = wasm_runtime_instantiate(module.get(), stack_size, + heap_size, NULL, 0); + } + + ~WAMRInstance() { wasm_runtime_deinstantiate(module_inst_); } + + wasm_module_inst_t get() const { return module_inst_; } +}; + +class WAMRExecEnv +{ + private: + wasm_exec_env_t exec_env_; + + public: + WAMRExecEnv(WAMRInstance &instance, uint32_t stack_size = 8192) + { + exec_env_ = wasm_runtime_create_exec_env(instance.get(), stack_size); + } + + ~WAMRExecEnv() { wasm_runtime_destroy_exec_env(exec_env_); } + + wasm_exec_env_t get() const { return exec_env_; } + wasm_module_inst_t get_inst() const + { + return wasm_runtime_get_module_inst(exec_env_); + } +}; + +static uint8_t dummy_wasm_buffer[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, 0x01, 0x00, + 0x02, 0x06, 0x08, 0x01, 0x7F, 0x01, 0x41, 0x80, 0x88, 0x04, 0x0B, 0x07, + 0x0A, 0x01, 0x06, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x00, + 0x19, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x07, 0x12, 0x01, 0x00, 0x0F, 0x5F, + 0x5F, 0x73, 0x74, 0x61, 0x63, 0x6B, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, + 0x65, 0x72, 0x00, 0x76, 0x09, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, + 0x72, 0x73, 0x01, 0x0C, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x2D, 0x62, 0x79, 0x01, 0x05, 0x63, 0x6C, 0x61, 0x6E, 0x67, 0x56, + 0x31, 0x33, 0x2E, 0x30, 0x2E, 0x30, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3A, 0x2F, 0x2F, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, + 0x6F, 0x6D, 0x2F, 0x6C, 0x6C, 0x76, 0x6D, 0x2F, 0x6C, 0x6C, 0x76, 0x6D, + 0x2D, 0x70, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x66, 0x64, 0x31, + 0x64, 0x38, 0x63, 0x32, 0x66, 0x30, 0x34, 0x64, 0x64, 0x65, 0x32, 0x33, + 0x62, 0x65, 0x65, 0x30, 0x66, 0x62, 0x33, 0x61, 0x37, 0x64, 0x30, 0x36, + 0x39, 0x61, 0x39, 0x62, 0x31, 0x30, 0x34, 0x36, 0x64, 0x61, 0x39, 0x37, + 0x39, 0x29 +}; + +class DummyExecEnv +{ + private: + std::shared_ptr dummy_exec_env_; + std::shared_ptr inst_; + std::shared_ptr mod_; + std::vector my_wasm_buffer; + + private: + void construct(uint8_t *buf, uint32_t len) + { + std::vector buffer(buf, buf + len); + my_wasm_buffer = buffer; + + mod_ = std::make_shared(my_wasm_buffer.data(), + my_wasm_buffer.size()); + EXPECT_NE(mod_.get(), nullptr); + inst_ = std::make_shared(*mod_); + EXPECT_NE(inst_.get(), nullptr); + dummy_exec_env_ = std::make_shared(*inst_); + EXPECT_NE(dummy_exec_env_.get(), nullptr); + } + + public: + DummyExecEnv() { construct(dummy_wasm_buffer, sizeof(dummy_wasm_buffer)); } + + DummyExecEnv(uint8_t *buf, uint32_t len) { construct(buf, len); } + + DummyExecEnv(std::string filename) + { + std::ifstream wasm_file(filename, std::ios::binary); + std::vector buffer(std::istreambuf_iterator(wasm_file), + {}); + + construct(buffer.data(), buffer.size()); + } + + ~DummyExecEnv() {} + + wasm_exec_env_t get() const { return dummy_exec_env_->get(); } + + void *app_to_native(uint32_t app_addr) const + { + return wasm_runtime_addr_app_to_native(inst_->get(), app_addr); + } + + uint32_t native_to_app(void *ptr) const + { + return wasm_runtime_addr_native_to_app(inst_->get(), ptr); + } + + const char *get_exception() const + { + return wasm_runtime_get_exception(inst_->get()); + } + + void set_exception(std::string str) const + { + wasm_runtime_set_exception(inst_->get(), str.c_str()); + } + + void clear_exception() const { wasm_runtime_clear_exception(inst_->get()); } + + bool execute(const char *func_name, uint32_t argc, uint32_t argv[]) + { + wasm_function_inst_t func; + + if (!(func = wasm_runtime_lookup_function(inst_->get(), func_name))) { + return false; + } + + return wasm_runtime_call_wasm(dummy_exec_env_->get(), func, argc, argv); + } +}; + +class WAMRVaList +{ + private: + void *buffer_; + uint32_t current_loc_; + uint32_t capacity_; + wasm_exec_env_t exec_env_; + + void _append(void *ptr, uint32_t size) + { + if (current_loc_ + size >= capacity_) { + capacity_ *= 2; + buffer_ = realloc(buffer_, capacity_); + ASSERT_NE(buffer_, nullptr); + } + + memcpy((void *)((uintptr_t)buffer_ + current_loc_), ptr, size); + current_loc_ += size; + } + + public: + explicit WAMRVaList(wasm_exec_env_t exec_env) + : exec_env_(exec_env) + { + capacity_ = 64; + buffer_ = malloc(capacity_); + EXPECT_NE(buffer_, nullptr); + current_loc_ = 0; + } + + ~WAMRVaList() + { + current_loc_ = 0; + free(buffer_); + } + + template + void add(T arg) + { + if (std::is_floating_point::value) { + /* float data should be 8 bytes aligned */ + current_loc_ = ((current_loc_ + 7) & ~7); + _append(&arg, sizeof(T)); + } + else if (std::is_integral::value) { + if (sizeof(T) > 4) { + current_loc_ = ((current_loc_ + 7) & ~7); + } + _append(&arg, sizeof(T)); + } + } + + void add(std::string arg) + { + void *native_addr; + auto inst = wasm_runtime_get_module_inst(exec_env_); + uint32_t addr = + wasm_runtime_module_malloc(inst, arg.size() + 1, &native_addr); + ASSERT_NE(addr, 0); + memcpy(native_addr, arg.data(), arg.size()); + *(char *)((uintptr_t)native_addr + arg.size()) = 0; + _append(&addr, sizeof(uint32_t)); + } + + void add(const char *arg) { add(std::string(arg)); } + + char *get() const + { + auto inst = wasm_runtime_get_module_inst(exec_env_); + uint32_t addr = wasm_runtime_module_dup_data( + inst, (const char *)buffer_, current_loc_); + EXPECT_NE(addr, 0); + return (char *)wasm_runtime_addr_app_to_native(inst, addr); + } +}; + +/* Get memory space in app */ +class AppMemory +{ + private: + wasm_exec_env_t exec_env_; + void *native_addr_; + uint32_t app_addr_; + + public: + AppMemory(wasm_exec_env_t exec_env, uint32_t size) + : exec_env_(exec_env) + { + app_addr_ = wasm_runtime_module_malloc(get_module_inst(exec_env_), size, + &native_addr_); + } + + ~AppMemory() + { + wasm_runtime_module_free(get_module_inst(exec_env_), app_addr_); + } + + void *get_native_addr() const + { + return wasm_runtime_addr_app_to_native(get_module_inst(exec_env_), + app_addr_); + } + uint32_t get_app_addr() const { return app_addr_; } +}; + +/* Put the data to app */ +class AppData +{ + private: + wasm_exec_env_t exec_env_; + void *native_addr_; + uint32_t app_addr_; + + public: + AppData(wasm_exec_env_t exec_env, void *data, uint32_t size) + : exec_env_(exec_env) + { + app_addr_ = wasm_runtime_module_dup_data(get_module_inst(exec_env_), + (const char *)data, size); + } + + AppData(wasm_exec_env_t exec_env, std::string str) + : exec_env_(exec_env) + { + app_addr_ = wasm_runtime_module_dup_data(get_module_inst(exec_env_), + (const char *)str.c_str(), + str.size() + 1); + } + + ~AppData() + { + wasm_runtime_module_free(get_module_inst(exec_env_), app_addr_); + } + + void *get_native_addr() const + { + return wasm_runtime_addr_app_to_native(get_module_inst(exec_env_), + app_addr_); + } + uint32_t get_app_addr() const { return app_addr_; } +}; \ No newline at end of file diff --git a/tests/unit/compilation/CMakeLists.txt b/tests/unit/compilation/CMakeLists.txt new file mode 100644 index 0000000000..0941a39ccf --- /dev/null +++ b/tests/unit/compilation/CMakeLists.txt @@ -0,0 +1,72 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-compilation) + +add_definitions (-DRUN_ON_LINUX) + +add_definitions (-Dattr_container_malloc=malloc) +add_definitions (-Dattr_container_free=free) +add_definitions (-DWASM_ENABLE_WAMR_COMPILER=1) +add_definitions (-DWASM_ENABLE_DUMP_CALL_STACK=1) +add_definitions (-DWASM_ENABLE_AOT_STACK_FRAME=1) + +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 0) +set (WAMR_BUILD_THREAD_MGR 1) +set (WAMR_BUILD_AOT 1) + +include (../unit_common.cmake) + +set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") +if (NOT EXISTS "${LLVM_SRC_ROOT}/build") + message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") +endif () +set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include (${IWASM_DIR}/compilation/iwasm_compl.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} + ${UNCOMMON_SHARED_SOURCE} + ${SRC_LIST} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${LIB_HOST_AGENT_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ${LIBC_BUILTIN_SOURCE} + ${IWASM_COMMON_SOURCE} + ${IWASM_INTERP_SOURCE} + ${IWASM_AOT_SOURCE} + ${IWASM_COMPL_SOURCE} + ${WASM_APP_LIB_SOURCE_ALL} + ) + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable (compilation_test ${unit_test_sources}) + +target_link_libraries (compilation_test ${LLVM_AVAILABLE_LIBS} gtest_main ) + +add_custom_command(TARGET compilation_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_LIST_DIR}/wasm-apps/main.wasm + ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copy main.wasm to the directory: build/compilation." +) + +gtest_discover_tests(compilation_test) diff --git a/tests/unit/compilation/aot_compiler_test.cc b/tests/unit/compilation/aot_compiler_test.cc new file mode 100644 index 0000000000..8592a4b610 --- /dev/null +++ b/tests/unit/compilation/aot_compiler_test.cc @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "wasm_export.h" +#include "aot_export.h" +#include "bh_read_file.h" + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static char *WASM_FILE; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +extern "C" { +char * +aot_generate_tempfile_name(const char *prefix, const char *extension, + char *buffer, uint32 len); +} + +class aot_compiler_test_suit : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE = strdup((CWD + MAIN_WASM).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + static void TearDownTestCase() { free(WASM_FILE); } + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +void +test_aot_emit_object_file_with_option(AOTCompOption *option_ptr) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + aot_comp_data_t comp_data = nullptr; + aot_comp_context_t comp_ctx = nullptr; + char out_file_name[] = "test.aot"; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data(wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + + comp_ctx = aot_create_comp_context(comp_data, option_ptr); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_STREQ(aot_get_last_error(), ""); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + + EXPECT_TRUE(aot_emit_object_file(comp_ctx, out_file_name)); +} + +TEST_F(aot_compiler_test_suit, aot_emit_object_file) +{ + AOTCompOption option = { 0 }; + uint32_t i = 0; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + // Test opt_level in range from 0 to 3. + for (i = 0; i <= 3; i++) { + option.opt_level = i; + test_aot_emit_object_file_with_option(&option); + } + + // Test size_level in range from 0 to 3. + option.opt_level = 3; + for (i = 0; i <= 3; i++) { + option.size_level = i; + test_aot_emit_object_file_with_option(&option); + } + + // Test output_format in range from AOT_FORMAT_FILE to AOT_LLVMIR_OPT_FILE. + option.size_level = 3; + for (i = AOT_FORMAT_FILE; i <= AOT_LLVMIR_OPT_FILE; i++) { + option.output_format = i; + test_aot_emit_object_file_with_option(&option); + } + + // Test bounds_checks in range 0 to 2. + option.output_format = AOT_FORMAT_FILE; + for (i = 0; i <= 2; i++) { + option.bounds_checks = i; + test_aot_emit_object_file_with_option(&option); + } + + // Test all enable option is false. + option.bounds_checks = 2; + option.enable_simd = false; + option.enable_aux_stack_check = false; + option.enable_bulk_memory = false; + option.enable_ref_types = false; + test_aot_emit_object_file_with_option(&option); +} + +TEST_F(aot_compiler_test_suit, aot_emit_llvm_file) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + aot_comp_data_t comp_data = nullptr; + aot_comp_context_t comp_ctx = nullptr; + AOTCompOption option = { 0 }; + char out_file_name[] = "out_file_name_test"; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data(wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_STREQ(aot_get_last_error(), ""); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + + EXPECT_EQ(true, aot_emit_llvm_file(comp_ctx, out_file_name)); +} + +TEST_F(aot_compiler_test_suit, aot_generate_tempfile_name) +{ + char obj_file_name[64]; + + // Test common case. + aot_generate_tempfile_name("wamrc-obj", "o", obj_file_name, + sizeof(obj_file_name)); + EXPECT_NE(nullptr, strstr(obj_file_name, ".o")); + + // Test abnormal cases. + EXPECT_EQ(nullptr, + aot_generate_tempfile_name("wamrc-obj", "o", obj_file_name, 0)); + char obj_file_name_1[20]; + EXPECT_EQ(nullptr, aot_generate_tempfile_name( + "wamrc-obj", "12345678901234567890", obj_file_name_1, + sizeof(obj_file_name_1))); +} diff --git a/tests/unit/compilation/aot_emit_aot_file_test.cc b/tests/unit/compilation/aot_emit_aot_file_test.cc new file mode 100644 index 0000000000..64c5533bb2 --- /dev/null +++ b/tests/unit/compilation/aot_emit_aot_file_test.cc @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "wasm_export.h" +#include "aot_export.h" +#include "bh_read_file.h" + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static char *WASM_FILE; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +extern "C" { +uint8 * +aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data, + uint32 *p_aot_file_size); +} + +class aot_emit_aot_file_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE = strdup((CWD + MAIN_WASM).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + static void TearDownTestCase() { free(WASM_FILE); } + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(aot_emit_aot_file_test_suite, aot_emit_aot_file) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + aot_comp_data_t comp_data = nullptr; + aot_comp_context_t comp_ctx = nullptr; + AOTCompOption option = { 0 }; + char out_file_name[] = "test.aot"; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = false; + option.enable_aux_stack_check = false; + option.enable_bulk_memory = false; + option.enable_ref_types = false; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data(wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + + EXPECT_EQ(false, aot_emit_aot_file(comp_ctx, comp_data, nullptr)); +} diff --git a/tests/unit/compilation/aot_emit_compare_test.cc b/tests/unit/compilation/aot_emit_compare_test.cc new file mode 100644 index 0000000000..dfd125f9ab --- /dev/null +++ b/tests/unit/compilation/aot_emit_compare_test.cc @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "gtest/gtest.h" +#include "aot_emit_compare.h" + +class compilation_aot_emit_compare_test : public testing::Test +{ + protected: + virtual void SetUp() {} + virtual void TearDown() {} + + public: +}; + +TEST_F(compilation_aot_emit_compare_test, aot_compile_op_i32_compare) +{ + AOTCompContext comp_ctx = { 0 }; + AOTFuncContext func_ctx = { 0 }; + IntCond cond = INT_EQZ; + IntCond cond1 = INT_EQZ; + + /* false cond = 0 */ + EXPECT_FALSE(aot_compile_op_i32_compare(&comp_ctx, &func_ctx, cond)); + + /* false cond = -1 */ + EXPECT_FALSE( + aot_compile_op_i32_compare(&comp_ctx, &func_ctx, (IntCond)(-1))); + + /* false cond = [1:10] || [11:100] */ + for (int i = 0; i < 0xFFFF; i++) { + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + cond = (IntCond)(1 + (rand() % (INT_GE_U - 1 + 1))); + cond1 = (IntCond)((INT_GE_U + 1) + (rand() % (100 - 1 + 1))); + EXPECT_FALSE(aot_compile_op_i32_compare(&comp_ctx, &func_ctx, cond)); + EXPECT_FALSE(aot_compile_op_i32_compare(&comp_ctx, &func_ctx, cond1)); + } +} + +TEST_F(compilation_aot_emit_compare_test, aot_compile_op_i64_compare) +{ + AOTCompContext comp_ctx = { 0 }; + AOTFuncContext func_ctx = { 0 }; + IntCond cond = INT_EQZ; + IntCond cond1 = INT_EQZ; + + /* false cond = 0 */ + // EXPECT_FALSE(aot_compile_op_i64_compare(&comp_ctx, &func_ctx, cond)); + + /* false cond = -1 */ + EXPECT_FALSE( + aot_compile_op_i64_compare(&comp_ctx, &func_ctx, (IntCond)(-1))); + + /* false cond = [1:10] || [11:100] */ + for (int i = 0; i < 0xFFFF; i++) { + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + cond = (IntCond)(1 + (rand() % (INT_GE_U - 1 + 1))); + cond1 = (IntCond)((INT_GE_U + 1) + (rand() % (100 - 1 + 1))); + EXPECT_FALSE(aot_compile_op_i64_compare(&comp_ctx, &func_ctx, cond)); + EXPECT_FALSE(aot_compile_op_i64_compare(&comp_ctx, &func_ctx, cond1)); + } +} + +TEST_F(compilation_aot_emit_compare_test, aot_compile_op_f32_compare) +{ + AOTCompContext comp_ctx = { 0 }; + AOTFuncContext func_ctx = { 0 }; + FloatCond cond = FLOAT_EQ; + FloatCond cond1 = FLOAT_EQ; + + /* false cond = 0 */ + EXPECT_FALSE(aot_compile_op_f32_compare(&comp_ctx, &func_ctx, cond)); + + /* false cond = -1 */ + EXPECT_FALSE( + aot_compile_op_f32_compare(&comp_ctx, &func_ctx, (FloatCond)(-1))); + + /* false cond = [1:10] || [7:100] */ + for (int i = 0; i < 0xFFFF; i++) { + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + cond = (FloatCond)(1 + (rand() % (FLOAT_UNO - 1 + 1))); + cond1 = (FloatCond)((FLOAT_UNO + 1) + (rand() % (100 - 1 + 1))); + EXPECT_FALSE(aot_compile_op_f32_compare(&comp_ctx, &func_ctx, cond)); + EXPECT_FALSE(aot_compile_op_f32_compare(&comp_ctx, &func_ctx, cond1)); + } +} + +TEST_F(compilation_aot_emit_compare_test, aot_compile_op_f64_compare) +{ + AOTCompContext comp_ctx = { 0 }; + AOTFuncContext func_ctx = { 0 }; + FloatCond cond = FLOAT_EQ; + FloatCond cond1 = FLOAT_EQ; + + /* false cond = 0 */ + EXPECT_FALSE(aot_compile_op_f64_compare(&comp_ctx, &func_ctx, cond)); + + /* false cond = -1 */ + EXPECT_FALSE( + aot_compile_op_f64_compare(&comp_ctx, &func_ctx, (FloatCond)(-1))); + + /* false cond = [1:10] || [7:100] */ + for (int i = 0; i < 0xFFFF; i++) { + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + cond = (FloatCond)(1 + (rand() % (FLOAT_UNO - 1 + 1))); + cond1 = (FloatCond)((FLOAT_UNO + 1) + (rand() % (100 - 1 + 1))); + EXPECT_FALSE(aot_compile_op_f64_compare(&comp_ctx, &func_ctx, cond)); + EXPECT_FALSE(aot_compile_op_f64_compare(&comp_ctx, &func_ctx, cond1)); + } +} diff --git a/tests/unit/compilation/aot_emit_control_test.cc b/tests/unit/compilation/aot_emit_control_test.cc new file mode 100644 index 0000000000..a269f51ebc --- /dev/null +++ b/tests/unit/compilation/aot_emit_control_test.cc @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_read_file.h" +#include "aot.h" +#include "aot_llvm.h" +#include "aot_emit_control.h" + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static char *WASM_FILE; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +class aot_emit_control_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE = strdup((CWD + MAIN_WASM).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + static void TearDownTestCase() { free(WASM_FILE); } + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(aot_emit_control_test_suite, check_suspend_flags) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTFuncContext *func_ctx = nullptr; + AOTCompOption option = { 0 }; + char out_file_name[] = "out_file_name_test"; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + + func_ctx = comp_ctx->func_ctxes[1]; + EXPECT_EQ(true, check_suspend_flags(comp_ctx, func_ctx, false)); +} + +TEST_F(aot_emit_control_test_suite, aot_compile_op_block) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTFuncContext *func_ctx = nullptr; + AOTCompOption option = { 0 }; + char out_file_name[] = "out_file_name_test"; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + + func_ctx = comp_ctx->func_ctxes[1]; + func_ctx->block_stack.block_list_end = nullptr; + EXPECT_EQ(false, aot_compile_op_block(comp_ctx, func_ctx, nullptr, nullptr, + 0, 0, nullptr, 0, nullptr)); +} + +TEST_F(aot_emit_control_test_suite, aot_compile_op_else) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTFuncContext *func_ctx = nullptr; + AOTCompOption option = { 0 }; + char out_file_name[] = "out_file_name_test"; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + + func_ctx = comp_ctx->func_ctxes[1]; + func_ctx->block_stack.block_list_end = nullptr; + EXPECT_EQ(false, aot_compile_op_else(comp_ctx, func_ctx, nullptr)); + + AOTBlock block_list_end_test; + block_list_end_test.label_type = LABEL_TYPE_FUNCTION; + func_ctx->block_stack.block_list_end = &block_list_end_test; + EXPECT_EQ(false, aot_compile_op_else(comp_ctx, func_ctx, nullptr)); + + block_list_end_test.label_type = LABEL_TYPE_IF; + block_list_end_test.llvm_else_block = nullptr; + EXPECT_EQ(false, aot_compile_op_else(comp_ctx, func_ctx, nullptr)); +} diff --git a/tests/unit/compilation/aot_emit_function_test.cc b/tests/unit/compilation/aot_emit_function_test.cc new file mode 100644 index 0000000000..8c4c93fcea --- /dev/null +++ b/tests/unit/compilation/aot_emit_function_test.cc @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_read_file.h" +#include "aot_emit_control.h" +#include "aot_emit_function.h" + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static char *WASM_FILE; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +class aot_emit_function_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE = strdup((CWD + MAIN_WASM).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + static void TearDownTestCase() { free(WASM_FILE); } + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(aot_emit_function_test_suite, aot_compile_op_call) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTFuncContext *func_ctx = nullptr; + AOTCompOption option = { 0 }; + char out_file_name[] = "out_file_name_test"; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + + func_ctx = comp_ctx->func_ctxes[1]; + EXPECT_EQ(false, aot_compile_op_call(comp_ctx, func_ctx, 9999, true)); +} diff --git a/tests/unit/compilation/aot_emit_memory_test.cc b/tests/unit/compilation/aot_emit_memory_test.cc new file mode 100644 index 0000000000..26a6a79bac --- /dev/null +++ b/tests/unit/compilation/aot_emit_memory_test.cc @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "gtest/gtest.h" +#include "bh_platform.h" +#include "bh_read_file.h" +#include "aot_emit_memory.h" +#include "test_helper.h" + +#define DEFAULT_CYCLE_TIMES 0xFFFF +#define DEFAULT_MAX_RAND_NUM 0xFFFFFFFF + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static char *WASM_FILE; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +class compilation_aot_emit_memory_test : public testing::Test +{ + protected: + void SetUp() override + { + CWD = get_binary_path(); + WASM_FILE = strdup((CWD + MAIN_WASM).c_str()); + AOTCompOption option = { 0 }; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + /* default value, enable or disable depends on the platform */ + option.stack_bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = reinterpret_cast(wasm_runtime_load( + wasm_file_buf, wasm_file_size, error_buf, sizeof(error_buf))); + EXPECT_NE(wasm_module, nullptr); + comp_data = aot_create_comp_data(wasm_module, NULL, false); + EXPECT_NE(comp_data, nullptr); + + // properly init compilation and function context, to do that, + // use as a dummy module(instead of compile the function in it, simply + // test the APIs) + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + func_ctx = comp_ctx->func_ctxes[0]; + EXPECT_NE(func_ctx, nullptr); + } + + void TearDown() override + { + aot_destroy_comp_context(comp_ctx); + aot_destroy_comp_data(comp_data); + wasm_runtime_unload(reinterpret_cast(wasm_module)); + } + + public: + WASMModule *wasm_module = nullptr; + AOTCompData *comp_data = nullptr; + AOTCompContext *comp_ctx = nullptr; + AOTFuncContext *func_ctx = nullptr; + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(compilation_aot_emit_memory_test, aot_check_memory_overflow) +{ + uint32 offset = 64; + uint32 bytes = 4; + + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + offset = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + aot_check_memory_overflow(comp_ctx, func_ctx, offset, bytes, false); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_i32_load) +{ + uint32 align = 0; + uint32 offset = 1024; + uint32 bytes = 0; + bool sign = false; + bool atomic = false; + + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + align = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + offset = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + bytes = (1 + (rand() % (4 - 1 + 1))); + printf("---%d", aot_compile_op_i32_load(comp_ctx, func_ctx, align, + offset, bytes, sign, atomic)); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_i64_load) +{ + uint32 align = 0; + uint32 offset = 1024; + uint32 bytes = 0; + bool sign = false; + bool atomic = false; + + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + align = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + offset = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + bytes = (1 + (rand() % (4 - 1 + 1))); + sign = !sign; + atomic = !atomic; + aot_compile_op_i64_load(comp_ctx, func_ctx, align, offset, bytes, sign, + atomic); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_f32_load) +{ + uint32 align = 10; + uint32 offset = 10; + + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + align = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + offset = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + aot_compile_op_f32_load(comp_ctx, func_ctx, align, offset); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_f64_load) +{ + uint32 align = 10; + uint32 offset = 10; + + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + align = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + offset = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + aot_compile_op_f64_load(comp_ctx, func_ctx, align, offset); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_i32_store) +{ + uint32 align = 0; + uint32 offset = 0; + uint32 bytes = 0; + bool atomic = false; + + EXPECT_FALSE(aot_compile_op_i32_store(comp_ctx, func_ctx, align, offset, + bytes, atomic)); + + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + bytes = (1 + (rand() % (4 - 1 + 1))); + offset = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + align = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + atomic = !atomic; + + EXPECT_FALSE(aot_compile_op_i32_store(comp_ctx, func_ctx, align, offset, + bytes, atomic)); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_i64_store) +{ + uint32 align = 0; + uint32 offset = 0; + uint32 bytes = 0; + bool atomic = false; + + EXPECT_FALSE(aot_compile_op_i64_store(comp_ctx, func_ctx, align, offset, + bytes, atomic)); + + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + bytes = (1 + (rand() % (8 - 1 + 1))); + offset = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + align = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + atomic = !atomic; + + EXPECT_FALSE(aot_compile_op_i64_store(comp_ctx, func_ctx, align, offset, + bytes, atomic)); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_f32_store) +{ + uint32 align = 0; + uint32 offset = 0; + + EXPECT_FALSE(aot_compile_op_f32_store(comp_ctx, func_ctx, align, offset)); + + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + offset = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + align = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + + EXPECT_FALSE( + aot_compile_op_f32_store(comp_ctx, func_ctx, align, offset)); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_f64_store) +{ + uint32 align = 0; + uint32 offset = 0; + + EXPECT_FALSE(aot_compile_op_f64_store(comp_ctx, func_ctx, align, offset)); + + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + offset = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + align = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + + EXPECT_FALSE( + aot_compile_op_f64_store(comp_ctx, func_ctx, align, offset)); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_memory_size) +{ + aot_compile_op_memory_size(comp_ctx, func_ctx); +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_memory_grow) +{ + aot_compile_op_memory_grow(comp_ctx, func_ctx); +} + +#if WASM_ENABLE_BULK_MEMORY != 0 +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_memory_init) +{ + uint32 seg_index = 0; + + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + seg_index = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + aot_compile_op_memory_init(comp_ctx, func_ctx, seg_index); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_data_drop) +{ + uint32 seg_index = 0; + + /* Generate random number range:[m,n] int a=m+rand()%(n-m+1); */ + for (uint32 i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + seg_index = (1 + (rand() % (0xFFFFFFFF - 1 + 1))); + aot_compile_op_data_drop(comp_ctx, func_ctx, seg_index); + } +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_memory_copy) +{ + aot_compile_op_memory_copy(comp_ctx, func_ctx); +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_memory_fill) +{ + aot_compile_op_memory_fill(comp_ctx, func_ctx); +} +#endif + +#if WASM_ENABLE_SHARED_MEMORY != 0 +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_atomic_rmw) +{ + uint8 atomic_op = LLVMAtomicRMWBinOpAdd; + uint8 op_type = VALUE_TYPE_I32; + uint32 align = 4; + uint32 offset = 64; + uint32 bytes = 4; + + aot_compile_op_atomic_rmw(comp_ctx, func_ctx, atomic_op, op_type, align, + offset, bytes); +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_atomic_cmpxchg) +{ + + uint8 op_type = VALUE_TYPE_I32; + uint32 align = 4; + uint32 offset = 64; + uint32 bytes = 4; + + aot_compile_op_atomic_cmpxchg(comp_ctx, func_ctx, op_type, align, offset, + bytes); +} + +TEST_F(compilation_aot_emit_memory_test, aot_compile_op_atomic_wait) +{ + + uint8 op_type = VALUE_TYPE_I32; + uint32 align = 4; + uint32 offset = 64; + uint32 bytes = 4; + + aot_compile_op_atomic_wait(comp_ctx, func_ctx, op_type, align, offset, + bytes); +} + +TEST_F(compilation_aot_emit_memory_test, aot_compiler_op_atomic_notify) +{ + + uint32 align = 4; + uint32 offset = 64; + uint32 bytes = 4; + + aot_compiler_op_atomic_notify(comp_ctx, func_ctx, align, offset, bytes); +} +#endif diff --git a/tests/unit/compilation/aot_emit_numberic_test.cc b/tests/unit/compilation/aot_emit_numberic_test.cc new file mode 100644 index 0000000000..f7e6e8ee78 --- /dev/null +++ b/tests/unit/compilation/aot_emit_numberic_test.cc @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_read_file.h" +#include "aot_llvm.h" +#include "aot_emit_numberic.h" +#include "aot_compiler.h" + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static char *WASM_FILE; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +class aot_emit_numberic_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE = strdup((CWD + MAIN_WASM).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + static void TearDownTestCase() { free(WASM_FILE); } + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(aot_emit_numberic_test_suite, aot_compile_op_functions) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTFuncContext *func_ctx = nullptr; + AOTCompOption option = { 0 }; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + func_ctx = comp_ctx->func_ctxes[1]; + + EXPECT_EQ(false, + aot_compile_op_f32_arithmetic(comp_ctx, func_ctx, FLOAT_SUB)); + EXPECT_EQ(false, aot_compile_op_f32_copysign(comp_ctx, func_ctx)); + EXPECT_EQ(false, aot_compile_op_f32_math(comp_ctx, func_ctx, FLOAT_NEG)); + EXPECT_EQ(false, + aot_compile_op_f64_arithmetic(comp_ctx, func_ctx, FLOAT_SUB)); + EXPECT_EQ(false, aot_compile_op_f64_copysign(comp_ctx, func_ctx)); + EXPECT_EQ(false, aot_compile_op_f64_math(comp_ctx, func_ctx, FLOAT_NEG)); + EXPECT_EQ(false, aot_compile_op_i32_clz(comp_ctx, func_ctx)); + EXPECT_EQ(false, aot_compile_op_i32_ctz(comp_ctx, func_ctx)); + EXPECT_EQ(false, aot_compile_op_i32_popcnt(comp_ctx, func_ctx)); + EXPECT_EQ(false, aot_compile_op_i32_shift(comp_ctx, func_ctx, INT_SHR_S)); + EXPECT_EQ(false, aot_compile_op_i64_arithmetic(comp_ctx, func_ctx, INT_SUB, + nullptr)); + EXPECT_EQ(false, aot_compile_op_i64_bitwise(comp_ctx, func_ctx, INT_OR)); + EXPECT_EQ(false, aot_compile_op_i64_clz(comp_ctx, func_ctx)); + EXPECT_EQ(false, aot_compile_op_i64_ctz(comp_ctx, func_ctx)); + EXPECT_EQ(false, aot_compile_op_i64_popcnt(comp_ctx, func_ctx)); + EXPECT_EQ(false, aot_compile_op_i64_shift(comp_ctx, func_ctx, INT_SHR_S)); +} diff --git a/tests/unit/compilation/aot_emit_parametric_test.cc b/tests/unit/compilation/aot_emit_parametric_test.cc new file mode 100644 index 0000000000..f9dabe1c81 --- /dev/null +++ b/tests/unit/compilation/aot_emit_parametric_test.cc @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_read_file.h" +#include "aot_llvm.h" +#include "aot_emit_parametric.h" + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static char *WASM_FILE; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +class aot_emit_parametric_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE = strdup((CWD + MAIN_WASM).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + static void TearDownTestCase() { free(WASM_FILE); } + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(aot_emit_parametric_test_suite, aot_compile_op_select) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTFuncContext *func_ctx = nullptr; + AOTCompOption option = { 0 }; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + func_ctx = comp_ctx->func_ctxes[1]; + + EXPECT_FALSE(aot_compile_op_select(comp_ctx, func_ctx, true)); + EXPECT_FALSE(aot_compile_op_select(comp_ctx, func_ctx, false)); +} + +TEST_F(aot_emit_parametric_test_suite, aot_compile_op_drop) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTFuncContext *func_ctx = nullptr; + AOTCompOption option = { 0 }; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + func_ctx = comp_ctx->func_ctxes[1]; + func_ctx->block_stack.block_list_end = nullptr; + + EXPECT_FALSE(aot_compile_op_drop(comp_ctx, func_ctx, true)); + EXPECT_FALSE(aot_compile_op_drop(comp_ctx, func_ctx, false)); +} diff --git a/tests/unit/compilation/aot_emit_table_test.cc b/tests/unit/compilation/aot_emit_table_test.cc new file mode 100644 index 0000000000..fc4bfe2f1f --- /dev/null +++ b/tests/unit/compilation/aot_emit_table_test.cc @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_read_file.h" +#include "aot_llvm.h" +#include "aot_emit_table.h" + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static char *WASM_FILE; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +class aot_emit_table_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE = strdup((CWD + MAIN_WASM).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + static void TearDownTestCase() { free(WASM_FILE); } + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(aot_emit_table_test_suite, get_tbl_inst_offset) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTFuncContext *func_ctx = nullptr; + AOTCompOption option = { 0 }; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + func_ctx = comp_ctx->func_ctxes[1]; + + EXPECT_NE(0, get_tbl_inst_offset(comp_ctx, func_ctx, 6)); + EXPECT_NE(0, get_tbl_inst_offset(comp_ctx, func_ctx, 1)); + EXPECT_NE(0, get_tbl_inst_offset(comp_ctx, func_ctx, 0)); + ((AOTCompData *)comp_ctx->comp_data)->import_table_count = 1; + AOTImportTable import_tables_test; + ((AOTCompData *)comp_ctx->comp_data)->import_tables = &import_tables_test; + EXPECT_NE(0, get_tbl_inst_offset(comp_ctx, func_ctx, 6)); +} diff --git a/tests/unit/compilation/aot_emit_variable_test.cc b/tests/unit/compilation/aot_emit_variable_test.cc new file mode 100644 index 0000000000..11cc238f00 --- /dev/null +++ b/tests/unit/compilation/aot_emit_variable_test.cc @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "gtest/gtest.h" +#include "aot_emit_variable.h" + +#define DEFAULT_CYCLE_TIMES 0xFFFF +#define DEFAULT_MAX_RAND_NUM 0xFFFFFFFF + +class compilation_aot_emit_variable_test : public testing::Test +{ + protected: + virtual void SetUp() {} + virtual void TearDown() {} + + public: + AOTCompContext comp_ctx = { 0 }; + AOTFuncContext func_ctx = { 0 }; +}; + +TEST_F(compilation_aot_emit_variable_test, aot_compile_op_get_local) +{ + AOTCompContext *pcomp_ctx = &comp_ctx; + AOTFuncContext *pfunc_ctx = &func_ctx; + uint32 local_idx = 0; + + // aot_compile_op_get_local(NULL, pfunc_ctx, local_idx); + + // for (uint32_t i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + // local_idx = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + // aot_compile_op_get_local(pcomp_ctx, pfunc_ctx, local_idx); + // } +} + +TEST_F(compilation_aot_emit_variable_test, aot_compile_op_set_local) +{ + + AOTCompContext *pcomp_ctx = &comp_ctx; + AOTFuncContext *pfunc_ctx = &func_ctx; + uint32 local_idx = 0; + + // aot_compile_op_set_local(pcomp_ctx, pfunc_ctx, local_idx); + + // for (uint32_t i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + // local_idx = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + // aot_compile_op_set_local(pcomp_ctx, pfunc_ctx, local_idx); + // } +} + +TEST_F(compilation_aot_emit_variable_test, aot_compile_op_tee_local) +{ + + AOTCompContext *pcomp_ctx = &comp_ctx; + AOTFuncContext *pfunc_ctx = &func_ctx; + uint32 local_idx = 0; + + // aot_compile_op_tee_local(pcomp_ctx, pfunc_ctx, local_idx); + + // for (uint32_t i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + // local_idx = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + // aot_compile_op_tee_local(pcomp_ctx, pfunc_ctx, local_idx); + // } +} + +TEST_F(compilation_aot_emit_variable_test, aot_compile_op_get_global) +{ + AOTCompContext *pcomp_ctx = &comp_ctx; + AOTFuncContext *pfunc_ctx = &func_ctx; + uint32 global_idx = 0; + + // aot_compile_op_get_global(pcomp_ctx, pfunc_ctx, global_idx); + + // for (uint32_t i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + // local_idx = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + // aot_compile_op_get_global(pcomp_ctx, pfunc_ctx, global_idx); + // } +} + +TEST_F(compilation_aot_emit_variable_test, aot_compile_op_set_global) +{ + AOTCompContext *pcomp_ctx = &comp_ctx; + AOTFuncContext *pfunc_ctx = &func_ctx; + uint32 global_idx = 0; + bool is_aux_stack = false; + + // aot_compile_op_set_global(pcomp_ctx, pfunc_ctx, global_idx, + // is_aux_stack); + + // for (uint32_t i = 0; i < DEFAULT_CYCLE_TIMES; i++) { + // is_aux_stack = is_aux_stack ? false : ture; + // local_idx = (1 + (rand() % (DEFAULT_MAX_RAND_NUM - 1 + 1))); + // aot_compile_op_set_global(pcomp_ctx, pfunc_ctx, + // global_idx,is_aux_stack); + // } +} \ No newline at end of file diff --git a/tests/unit/compilation/aot_llvm_test.cc b/tests/unit/compilation/aot_llvm_test.cc new file mode 100644 index 0000000000..dcebe04b47 --- /dev/null +++ b/tests/unit/compilation/aot_llvm_test.cc @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_read_file.h" +#include "aot_llvm.h" +#include "aot_compiler.h" + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static char *WASM_FILE; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +class aot_llvm_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE = strdup((CWD + MAIN_WASM).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + static void TearDownTestCase() { free(WASM_FILE); } + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(aot_llvm_test_suite, aot_functions) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTCompOption option = { 0 }; + AOTFuncContext *func_ctx = nullptr; + WASMValue wasm_value; + LLVMTypeRef param_types[1]; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + func_ctx = comp_ctx->func_ctxes[1]; + + param_types[0] = F64_TYPE; + EXPECT_TRUE(aot_call_llvm_intrinsic(comp_ctx, func_ctx, "f32_demote_f64", + F32_TYPE, param_types, 0)); + + /* Test function aot_get_native_symbol_index. */ + AOTNativeSymbol elem_insert_1; + elem_insert_1.index = -1; + bh_list_insert(&comp_ctx->native_symbols, &elem_insert_1); + + AOTNativeSymbol elem_insert_2; + strcpy(elem_insert_2.symbol, "f64#_test"); + elem_insert_2.index = -1; + bh_list_insert(&comp_ctx->native_symbols, &elem_insert_2); + comp_ctx->pointer_size = sizeof(uint32); + strcpy(comp_ctx->target_arch, "i386"); + EXPECT_NE(-1, aot_get_native_symbol_index(comp_ctx, "f64#_test")); +} + +TEST_F(aot_llvm_test_suite, wasm_type_to_llvm_type) {} + +TEST_F(aot_llvm_test_suite, aot_build_zero_function_ret) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTCompOption option = { 0 }; + AOTFuncContext *func_ctx = nullptr; + AOTFuncType func_type; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = false; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + func_ctx = comp_ctx->func_ctxes[1]; + + func_type.result_count = 1; + func_type.param_count = 0; + func_type.types[func_type.param_count] = VALUE_TYPE_I32; + EXPECT_NE(0, aot_build_zero_function_ret(comp_ctx, func_ctx, &func_type)); + func_type.types[func_type.param_count] = VALUE_TYPE_I64; + EXPECT_NE(0, aot_build_zero_function_ret(comp_ctx, func_ctx, &func_type)); + func_type.types[func_type.param_count] = VALUE_TYPE_F32; + EXPECT_NE(0, aot_build_zero_function_ret(comp_ctx, func_ctx, &func_type)); + func_type.types[func_type.param_count] = VALUE_TYPE_F64; + EXPECT_NE(0, aot_build_zero_function_ret(comp_ctx, func_ctx, &func_type)); + func_type.types[func_type.param_count] = VALUE_TYPE_V128; + EXPECT_NE(0, aot_build_zero_function_ret(comp_ctx, func_ctx, &func_type)); + /* THe current optimization, if not actually use ref_types in wasm module, + * it will set to false, so test false condition */ + func_type.types[func_type.param_count] = VALUE_TYPE_FUNCREF; + EXPECT_DEATH(aot_build_zero_function_ret(comp_ctx, func_ctx, &func_type), + ".*"); + func_type.types[func_type.param_count] = VALUE_TYPE_EXTERNREF; + EXPECT_DEATH(aot_build_zero_function_ret(comp_ctx, func_ctx, &func_type), + ".*"); + func_type.types[func_type.param_count] = 0xFF; + EXPECT_DEATH(aot_build_zero_function_ret(comp_ctx, func_ctx, &func_type), + ".*"); +} + +TEST_F(aot_llvm_test_suite, aot_destroy_comp_context) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTCompOption option = { 0 }; + AOTFuncContext *func_ctx = nullptr; + AOTFuncType func_type; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + + AOTNativeSymbol elem_insert_1; + elem_insert_1.index = -1; + bh_list_insert(&comp_ctx->native_symbols, &elem_insert_1); + aot_destroy_comp_context(comp_ctx); + + aot_destroy_comp_context(nullptr); +} + +TEST_F(aot_llvm_test_suite, aot_create_comp_context) +{ + const char *wasm_file = WASM_FILE; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + char error_buf[128] = { 0 }; + wasm_module_t wasm_module = nullptr; + + struct AOTCompData *comp_data = nullptr; + struct AOTCompContext *comp_ctx = nullptr; + AOTCompOption option = { 0 }; + + option.opt_level = 3; + option.size_level = 3; + option.output_format = AOT_FORMAT_FILE; + /* default value, enable or disable depends on the platform */ + option.bounds_checks = 2; + option.enable_simd = true; + option.enable_aux_stack_check = true; + option.enable_bulk_memory = true; + option.enable_ref_types = true; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + comp_data = aot_create_comp_data((WASMModule *)wasm_module, NULL, false); + EXPECT_NE(nullptr, comp_data); + + option.enable_thread_mgr = true; + option.enable_tail_call = true; + option.is_indirect_mode = true; + option.disable_llvm_intrinsics = true; + option.disable_llvm_lto = true; + option.is_jit_mode = true; + + option.target_arch = (char *)"arm"; + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + option.output_format = 100; + comp_ctx = aot_create_comp_context(comp_data, &option); + + // Test every target_arch. + option.is_jit_mode = false; + option.target_arch = (char *)"arm"; + comp_ctx = aot_create_comp_context(comp_data, &option); + option.target_arch = (char *)"armeb"; + comp_ctx = aot_create_comp_context(comp_data, &option); + option.target_arch = (char *)"thumb"; + comp_ctx = aot_create_comp_context(comp_data, &option); + option.target_arch = (char *)"thumbeb"; + comp_ctx = aot_create_comp_context(comp_data, &option); + option.target_arch = (char *)"aarch64"; + comp_ctx = aot_create_comp_context(comp_data, &option); + option.target_arch = (char *)"aarch64_be"; + comp_ctx = aot_create_comp_context(comp_data, &option); + option.target_arch = (char *)"help"; + comp_ctx = aot_create_comp_context(comp_data, &option); + + // Test every target_abi. + option.target_arch = (char *)"arm"; + option.target_abi = (char *)"test"; + comp_ctx = aot_create_comp_context(comp_data, &option); + option.target_abi = (char *)"help"; + comp_ctx = aot_create_comp_context(comp_data, &option); + option.target_abi = (char *)"msvc"; + option.target_arch = (char *)"i386"; + comp_ctx = aot_create_comp_context(comp_data, &option); + + option.cpu_features = (char *)"test"; + comp_ctx = aot_create_comp_context(comp_data, &option); + option.is_sgx_platform = true; + comp_ctx = aot_create_comp_context(comp_data, &option); + comp_data->func_count = 0; + comp_ctx = aot_create_comp_context(comp_data, &option); +} diff --git a/tests/unit/compilation/wasm-apps/main.wasm b/tests/unit/compilation/wasm-apps/main.wasm new file mode 100644 index 0000000000..28af80e405 Binary files /dev/null and b/tests/unit/compilation/wasm-apps/main.wasm differ diff --git a/tests/unit/custom-section/CMakeLists.txt b/tests/unit/custom-section/CMakeLists.txt new file mode 100644 index 0000000000..1529d0ea6b --- /dev/null +++ b/tests/unit/custom-section/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-custom-section) + +add_definitions (-DRUN_ON_LINUX) + +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_LIBC_BUILTIN 0) +set (WAMR_BUILD_JIT 0) +set (WAMR_BUILD_LAZY_JIT 0) +set (WAMR_BUILD_AOT 1) + +add_definitions(-DWASM_ENABLE_WAMR_COMPILER=1) +add_definitions (-DWASM_ENABLE_DUMP_CALL_STACK=1) +add_definitions (-DWASM_ENABLE_AOT_STACK_FRAME=1) + +# Feature to test +set (WAMR_BUILD_LOAD_CUSTOM_SECTION 1) + +include (../unit_common.cmake) + +set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") +if (NOT EXISTS "${LLVM_SRC_ROOT}/build") + message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") +endif () +set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include (${IWASM_DIR}/compilation/iwasm_compl.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ${IWASM_COMMON_SOURCE} + ${IWASM_INTERP_SOURCE} + ${IWASM_AOT_SOURCE} + ${IWASM_COMPL_SOURCE} + ${WASM_APP_LIB_SOURCE_ALL} + ) + +# Automatically build wasm-apps for this test +add_subdirectory(wasm-apps) + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable (custom_section_test ${unit_test_sources}) + +target_link_libraries (custom_section_test ${LLVM_AVAILABLE_LIBS} gtest_main ) + +gtest_discover_tests(custom_section_test) diff --git a/tests/unit/custom-section/custom_section_test.cc b/tests/unit/custom-section/custom_section_test.cc new file mode 100644 index 0000000000..9bf04664ab --- /dev/null +++ b/tests/unit/custom-section/custom_section_test.cc @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "gtest/gtest.h" +#include "bh_platform.h" +#include +#include "test_helper.h" +#include "aot_export.h" + +class CustomSectionTest : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + public: + WAMRRuntimeRAII<1 * 1024 * 1024> runtime; +}; + +TEST_F(CustomSectionTest, get_custom_section_from_wasm_module_t) +{ + uint32_t length, len_from_aot; + const uint8_t *content, *content_from_aot; + std::ifstream wasm_file("wasm-apps/app.wasm", std::ios::binary); + std::vector buffer(std::istreambuf_iterator(wasm_file), + {}); + { + WAMRModule module(buffer.data(), buffer.size()); + aot_comp_data_t comp_data = NULL; + aot_comp_context_t comp_ctx = NULL; + std::vector sections_to_emit{ + "name", + ".debug_info", + ".debug_abbrev", + /* skip ".debug_line" section in AoT module */ + ".debug_str", + "producers", + }; + + AOTCompOption option = { 0 }; + option.custom_sections = (char **)sections_to_emit.data(); + option.custom_sections_count = 5; + + { + /* Compile an AoT module */ + comp_data = aot_create_comp_data(module.get(), NULL, false); + EXPECT_NE(comp_data, nullptr); + + comp_ctx = aot_create_comp_context(comp_data, &option); + EXPECT_NE(comp_ctx, nullptr); + + EXPECT_TRUE(aot_compile_wasm(comp_ctx)); + + EXPECT_TRUE(aot_emit_aot_file(comp_ctx, comp_data, "temp.aot")); + } + + std::ifstream aot_file("temp.aot", std::ios::binary); + std::vector aot_buffer( + std::istreambuf_iterator(aot_file), {}); + WAMRModule aot_module(aot_buffer.data(), aot_buffer.size()); + + /* name */ + content = + wasm_runtime_get_custom_section(module.get(), "name", &length); + EXPECT_NE(content, nullptr); + EXPECT_GT(length, 0); + + /* TODO: aot_emit_name_section don't + EMIT_U32(AOT_CUSTOM_SECTION_RAW);* + EMIT_STR("name"); + but instead + EMIT_U32(AOT_CUSTOM_SECTION_NAME); + can't use get_custom_section to get it + */ + // content_from_aot = wasm_runtime_get_custom_section( + // aot_module.get(), "name", &len_from_aot); + // EXPECT_NE(content_from_aot, nullptr); + // EXPECT_EQ(len_from_aot, length); + // EXPECT_EQ(memcmp(content_from_aot, content, length), 0); + + /* .debug_info */ + content = wasm_runtime_get_custom_section(module.get(), ".debug_info", + &length); + EXPECT_NE(content, nullptr); + EXPECT_GT(length, 0); + + content_from_aot = wasm_runtime_get_custom_section( + aot_module.get(), ".debug_info", &len_from_aot); + EXPECT_NE(content_from_aot, nullptr); + EXPECT_EQ(len_from_aot, length); + EXPECT_EQ(memcmp(content_from_aot, content, length), 0); + + /* .debug_abbrev */ + content = wasm_runtime_get_custom_section(module.get(), ".debug_abbrev", + &length); + EXPECT_NE(content, nullptr); + EXPECT_GT(length, 0); + + content_from_aot = wasm_runtime_get_custom_section( + aot_module.get(), ".debug_abbrev", &len_from_aot); + EXPECT_NE(content_from_aot, nullptr); + EXPECT_EQ(len_from_aot, length); + EXPECT_EQ(memcmp(content_from_aot, content, length), 0); + + /* .debug_line */ + content = wasm_runtime_get_custom_section(module.get(), ".debug_line", + &length); + EXPECT_NE(content, nullptr); + EXPECT_GT(length, 0); + + content_from_aot = wasm_runtime_get_custom_section( + aot_module.get(), ".debug_line", &len_from_aot); + EXPECT_EQ(content_from_aot, nullptr); + + /* .debug_str */ + content = wasm_runtime_get_custom_section(module.get(), ".debug_str", + &length); + EXPECT_NE(content, nullptr); + EXPECT_GT(length, 0); + + content_from_aot = wasm_runtime_get_custom_section( + aot_module.get(), ".debug_str", &len_from_aot); + EXPECT_NE(content_from_aot, nullptr); + EXPECT_EQ(len_from_aot, length); + EXPECT_EQ(memcmp(content_from_aot, content, length), 0); + + /* producers */ + content = + wasm_runtime_get_custom_section(module.get(), "producers", &length); + EXPECT_NE(content, nullptr); + EXPECT_GT(length, 0); + + content_from_aot = wasm_runtime_get_custom_section( + aot_module.get(), "producers", &len_from_aot); + EXPECT_NE(content_from_aot, nullptr); + EXPECT_EQ(len_from_aot, length); + EXPECT_EQ(memcmp(content_from_aot, content, length), 0); + + /* Not exist */ + content = wasm_runtime_get_custom_section(module.get(), "producers1", + &length); + EXPECT_EQ(content, nullptr); + + content_from_aot = wasm_runtime_get_custom_section( + aot_module.get(), "producers1", &len_from_aot); + EXPECT_EQ(content_from_aot, nullptr); + } +} diff --git a/tests/unit/custom-section/wasm-apps/CMakeLists.txt b/tests/unit/custom-section/wasm-apps/CMakeLists.txt new file mode 100644 index 0000000000..a539dd2361 --- /dev/null +++ b/tests/unit/custom-section/wasm-apps/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project(wasm-apps-custom-section) + +# Add -g option so there will be debugger related custom sections +add_custom_target(app.wasm ALL + COMMAND /opt/wasi-sdk/bin/clang -g -nostdlib + -Wl,--no-entry,--export-all + -o ${CMAKE_CURRENT_BINARY_DIR}/app.wasm + ${CMAKE_CURRENT_LIST_DIR}/app.c +) diff --git a/tests/unit/custom-section/wasm-apps/app.c b/tests/unit/custom-section/wasm-apps/app.c new file mode 100644 index 0000000000..3820e3c7cc --- /dev/null +++ b/tests/unit/custom-section/wasm-apps/app.c @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +int +main(int argc, char const *argv[]) +{ + return 0; +} diff --git a/tests/unit/gc/CMakeLists.txt b/tests/unit/gc/CMakeLists.txt new file mode 100644 index 0000000000..e0f70d1427 --- /dev/null +++ b/tests/unit/gc/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-wamr-gc) + +add_definitions (-DRUN_ON_LINUX) + +set (WAMR_BUILD_GC 1) +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_AOT 0) +set (WAMR_BUILD_APP_FRAMEWORK 0) + +include (../unit_common.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} + ${UNCOMMON_SHARED_SOURCE} + ${SRC_LIST} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${LIB_HOST_AGENT_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ${LIBC_BUILTIN_SOURCE} + ${IWASM_COMMON_SOURCE} + ${IWASM_INTERP_SOURCE} + ${IWASM_AOT_SOURCE} + ${IWASM_COMPL_SOURCE} + ${WASM_APP_LIB_SOURCE_ALL} +) + +add_executable (gc_test ${unit_test_sources}) +target_link_libraries (gc_test gtest_main) + +add_custom_command(TARGET gc_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_LIST_DIR}/wasm-apps/*.was* + ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copy wasm files to directory ${CMAKE_CURRENT_BINARY_DIR}" +) + +#gtest_discover_tests(gc_test) \ No newline at end of file diff --git a/tests/unit/gc/gc_test.cc b/tests/unit/gc/gc_test.cc new file mode 100644 index 0000000000..196ddba65a --- /dev/null +++ b/tests/unit/gc/gc_test.cc @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "gtest/gtest.h" +#include "bh_platform.h" +#include "bh_read_file.h" +#include "wasm_export.h" + +class WasmGCTest : public testing::Test +{ + private: + std::string get_binary_path() + { + char cwd[1024] = { 0 }; + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + return NULL; + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); + } + + protected: + void SetUp() + { + CWD = get_binary_path(); + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + ASSERT_EQ(wasm_runtime_full_init(&init_args), true); + + cleanup = true; + } + + void TearDown() + { + if (cleanup) { + wasm_runtime_destroy(); + } + } + + public: + bool load_wasm_file(const char *wasm_file) + { + const char *file; + unsigned char *wasm_file_buf; + uint32 wasm_file_size; + + file = strdup((CWD + "/" + wasm_file).c_str()); + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(file, &wasm_file_size); + if (!wasm_file_buf) + return false; + + module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + if (!module) + return false; + + return true; + } + + public: + std::string CWD; + RuntimeInitArgs init_args; + wasm_module_t module = NULL; + wasm_module_inst_t module_inst = NULL; + wasm_function_inst_t func_inst = NULL; + wasm_exec_env_t exec_env = NULL; + char error_buf[128]; + char global_heap_buf[512 * 1024]; + bool cleanup = true; +}; + +TEST_F(WasmGCTest, Test_app1) +{ + ASSERT_TRUE(load_wasm_file("test1.wasm")); + ASSERT_TRUE(load_wasm_file("test2.wasm")); + ASSERT_TRUE(load_wasm_file("test3.wasm")); + ASSERT_TRUE(load_wasm_file("test4.wasm")); + ASSERT_TRUE(load_wasm_file("test5.wasm")); + ASSERT_TRUE(load_wasm_file("test6.wasm")); + + ASSERT_TRUE(load_wasm_file("struct1.wasm")); + ASSERT_TRUE(load_wasm_file("struct2.wasm")); + ASSERT_TRUE(load_wasm_file("struct3.wasm")); + + ASSERT_TRUE(load_wasm_file("func1.wasm")); + ASSERT_TRUE(load_wasm_file("func2.wasm")); +} diff --git a/tests/unit/gc/wasm-apps/func1.wasm b/tests/unit/gc/wasm-apps/func1.wasm new file mode 100644 index 0000000000..51b316b54e Binary files /dev/null and b/tests/unit/gc/wasm-apps/func1.wasm differ diff --git a/tests/unit/gc/wasm-apps/func1.wast b/tests/unit/gc/wasm-apps/func1.wast new file mode 100644 index 0000000000..1b4941787d --- /dev/null +++ b/tests/unit/gc/wasm-apps/func1.wast @@ -0,0 +1,35 @@ +(module + (type $t (func)) + + (func (export "test") (param structref i31ref) + (local funcref) + (local funcref) + (local funcref) + (local externref) + (local externref) + (local externref) + (local anyref) + (local eqref) + (local structref) + (local arrayref) + (local i31ref) + (local (ref null 0)) + (local (ref null 0)) + (local (ref null 0)) + (local (ref null 1)) + (local (ref null func)) + (local (ref null 0)) + (local (ref null extern)) + (local (ref null any)) + (local (ref null eq)) + (local (ref null i31)) + (local (ref null struct)) + + local.get 0 + ref.test null array + drop + local.get 1 + ref.cast i31 + drop + ) +) diff --git a/tests/unit/gc/wasm-apps/func2.wasm b/tests/unit/gc/wasm-apps/func2.wasm new file mode 100644 index 0000000000..e5d852ce46 Binary files /dev/null and b/tests/unit/gc/wasm-apps/func2.wasm differ diff --git a/tests/unit/gc/wasm-apps/func2.wast b/tests/unit/gc/wasm-apps/func2.wast new file mode 100644 index 0000000000..bfe588dd56 --- /dev/null +++ b/tests/unit/gc/wasm-apps/func2.wast @@ -0,0 +1,78 @@ +(module + (type $t0 (func)) + (type $t1 (func (param (ref null 1)))) + (type $t2 (func (param funcref externref (ref func)(ref extern) + anyref eqref structref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 1) (ref $t0) (ref null func) + (ref null extern) (ref null 2) (ref null $t0)) + (result (ref null func)))) + (type $t3 (func (param i32 i32) (result (ref null 3)))) + + (type $t4 (func)) + (type $t5 (func (param (ref null 3)))) + (type $t6 (func (param funcref externref (ref func)(ref extern) + anyref eqref structref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 5) (ref null $t0)) + (result (ref null func)))) + (type $t7 (func (param i32 i32) (result (ref null 4)))) + + (type $t11 (struct (field i8 (mut i16) (mut i32) i64 f32 f64 + funcref externref (ref func)(ref extern) + anyref eqref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null struct) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 5) (ref null $t0)))) + + (type $t12 (struct)) + (type $t13 (struct (field))) + (type $t14 (struct (field i8))) + (type $t15 (struct (field i8 i8 i8 i8))) + (type $t16 (struct (field $x1 i32) (field $y1 i32))) + (type $t17 (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1)))) + (type $t18 (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) + (type $t19 (struct (field $x2 i32) (field f32 f64) (field $y2 i32))) + + (type $t20 (struct (field i8 (mut i16) (mut i32) i64 f32 f64 + funcref externref (ref func)(ref extern) + anyref eqref structref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 5) (ref null $t0)))) + + (type $t21 (struct)) + (type $t22 (struct (field))) + (type $t23 (struct (field i8))) + (type $t24 (struct (field i8 i8 i8 i8))) + (type $t25 (struct (field $x3 i32) (field $y3 i32))) + (type $t26 (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1)))) + (type $t27 (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) + (type $t28 (struct (field $x4 i32) (field f32 f64) (field $y4 i32))) + + (type $t31 (array i8)) + (type $t32 (array i16)) + (type $t33 (array i32)) + (type $t34 (array i64)) + (type $t35 (array f32)) + (type $t36 (array f64)) + (type $t37 (array anyref)) + (type $t38 (array (ref i31))) + (type $t39 (array (ref 0))) + (type $t40 (array (ref null 1))) + (type $t43 (array (mut i8))) + (type $t44 (array (mut i16))) + (type $t45 (array (mut i32))) + (type $t46 (array (mut i64))) + (type $t47 (array (mut i32))) + (type $t48 (array (mut i64))) + (type $t49 (array (mut anyref))) + (type $t50 (array (mut (ref struct)))) + (type $t51 (array (mut (ref 0)))) + (type $t52 (array (mut (ref null i31)))) +) diff --git a/tests/unit/gc/wasm-apps/global1.wasm b/tests/unit/gc/wasm-apps/global1.wasm new file mode 100644 index 0000000000..706cc954c4 Binary files /dev/null and b/tests/unit/gc/wasm-apps/global1.wasm differ diff --git a/tests/unit/gc/wasm-apps/global1.wast b/tests/unit/gc/wasm-apps/global1.wast new file mode 100644 index 0000000000..9842f8d930 --- /dev/null +++ b/tests/unit/gc/wasm-apps/global1.wast @@ -0,0 +1,91 @@ +(module + (type $ftype0 (func (param i32))) + (type $ftype1 (func (param i32 i64) (result i32))) + (type $ftype2 (func (param f32 f64) (result f64))) + (type $t0 (func (param (ref 1) (ref 2) (ref null 1) (ref null 2)))) + (type $t1 (func (param funcref externref (ref func)(ref extern) + anyref eqref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 3) (ref null $t0)) + (result (ref null func)))) + (type $t2 (func (param i32 i32) (result (ref null 4)))) + + ;; Duplicated types + (type $t3 (func)) + (type $t4 (func (param (ref 1) (ref 2) (ref null 1) (ref null 2)))) + (type $t5 (func (param funcref externref (ref func)(ref extern) + anyref eqref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 3) (ref null $t0)) + (result (ref null func)))) + (type $t6 (func (param i32 i32) (result (ref null 4)))) + + (type (struct (field i8 (mut i16) (mut i32) i64 f32 f64 + funcref externref (ref func)(ref extern) + anyref eqref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 5) (ref null $t0)))) + + (type (struct)) + (type (struct (field))) + (type (struct (field i8))) + (type (struct (field i8 i8 i8 i8))) + (type (struct (field $x1 i32) (field $y1 i32))) + (type (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1)))) + (type (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) + (type (struct (field $x2 i32) (field f32 f64) (field $y2 i32))) + + ;; Duplicated types + (type (struct (field i8 (mut i16) (mut i32) i64 f32 f64 + funcref externref (ref func)(ref extern) + anyref eqref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 5) (ref null $t0)))) + + (type (struct)) + (type (struct (field))) + (type (struct (field i8))) + (type (struct (field i8 i8 i8 i8))) + (type (struct (field $x3 i32) (field $y3 i32))) + (type (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1)))) + (type (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) + (type (struct (field $x4 i32) (field f32 f64) (field $y4 i32))) + + (type (array i8)) + (type (array i16)) + (type (array i32)) + (type (array i64)) + (type (array f32)) + (type (array f64)) + (type (array anyref)) + (type (array (ref array))) + (type (array (ref 0))) + (type (array (ref null 1))) + (type (array (mut i8))) + (type (array (mut i16))) + (type (array (mut i32))) + (type (array (mut i64))) + (type (array (mut i32))) + (type (array (mut i64))) + (type (array (mut anyref))) + (type (array (mut (ref array)))) + (type (array (mut (ref 0)))) + (type (array (mut (ref null i31)))) + + (global $g0 funcref (ref.func $f0)) + (global $g1 externref (ref.null extern)) + (global $g2 anyref (ref.null any)) + (global $g3 eqref (ref.null array)) + (global $g4 arrayref (ref.null array)) + (global $g5 i31ref (ref.null i31)) + + (func $f0) +) diff --git a/tests/unit/gc/wasm-apps/struct1.wasm b/tests/unit/gc/wasm-apps/struct1.wasm new file mode 100644 index 0000000000..513442f96f Binary files /dev/null and b/tests/unit/gc/wasm-apps/struct1.wasm differ diff --git a/tests/unit/gc/wasm-apps/struct1.wast b/tests/unit/gc/wasm-apps/struct1.wast new file mode 100644 index 0000000000..3ce6fde6bf --- /dev/null +++ b/tests/unit/gc/wasm-apps/struct1.wast @@ -0,0 +1,10 @@ +(module + (type (struct)) + (type (struct (field))) + (type (struct (field i8))) + (type (struct (field i8 i8 i8 i8))) + (type (struct (field $x1 i32) (field $y1 i32))) + (type (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1)))) + (type (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) + (type (struct (field $x2 i32) (field f32 f64) (field $y2 i32))) +) diff --git a/tests/unit/gc/wasm-apps/struct2.wasm b/tests/unit/gc/wasm-apps/struct2.wasm new file mode 100644 index 0000000000..497a964419 Binary files /dev/null and b/tests/unit/gc/wasm-apps/struct2.wasm differ diff --git a/tests/unit/gc/wasm-apps/struct2.wast b/tests/unit/gc/wasm-apps/struct2.wast new file mode 100644 index 0000000000..266841d62e --- /dev/null +++ b/tests/unit/gc/wasm-apps/struct2.wast @@ -0,0 +1,33 @@ +(module + (type $vec (struct (field f32) (field $y (mut f32)) (field $z f32))) + + ;;(global (ref $vec) (struct.new_canon $vec (f32.const 1) (f32.const 2) (f32.const 3))) + (global (ref $vec) (struct.new_canon_default $vec)) + + (func (export "new") (result anyref) + (struct.new_canon_default $vec) + ) + + (func $get_0 (param $v (ref $vec)) (result f32) + (struct.get $vec 0 (local.get $v)) + ) + (func (export "get_0") (result f32) + (call $get_0 (struct.new_canon_default $vec)) + ) + + (func $set_get_y (param $v (ref $vec)) (param $y f32) (result f32) + (struct.set $vec $y (local.get $v) (local.get $y)) + (struct.get $vec $y (local.get $v)) + ) + (func (export "set_get_y") (param $y f32) (result f32) + (call $set_get_y (struct.new_canon_default $vec) (local.get $y)) + ) + + (func $set_get_1 (param $v (ref $vec)) (param $y f32) (result f32) + (struct.set $vec 1 (local.get $v) (local.get $y)) + (struct.get $vec $y (local.get $v)) + ) + (func (export "set_get_1") (param $y f32) (result f32) + (call $set_get_1 (struct.new_canon_default $vec) (local.get $y)) + ) +) diff --git a/tests/unit/gc/wasm-apps/struct3.wasm b/tests/unit/gc/wasm-apps/struct3.wasm new file mode 100644 index 0000000000..0da32361a7 Binary files /dev/null and b/tests/unit/gc/wasm-apps/struct3.wasm differ diff --git a/tests/unit/gc/wasm-apps/struct3.wast b/tests/unit/gc/wasm-apps/struct3.wast new file mode 100644 index 0000000000..b7678ba78f --- /dev/null +++ b/tests/unit/gc/wasm-apps/struct3.wast @@ -0,0 +1,9 @@ +(module + (type $t (struct (field i32 (mut i32)))) + (func (export "struct.get-null") + (local (ref null $t)) (drop (struct.get $t 1 (local.get 0))) + ) + (func (export "struct.set-null") + (local (ref null $t)) (struct.set $t 1 (local.get 0) (i32.const 0)) + ) +) diff --git a/tests/unit/gc/wasm-apps/table1.wasm b/tests/unit/gc/wasm-apps/table1.wasm new file mode 100644 index 0000000000..f43b425398 Binary files /dev/null and b/tests/unit/gc/wasm-apps/table1.wasm differ diff --git a/tests/unit/gc/wasm-apps/table1.wast b/tests/unit/gc/wasm-apps/table1.wast new file mode 100644 index 0000000000..8e00618357 --- /dev/null +++ b/tests/unit/gc/wasm-apps/table1.wast @@ -0,0 +1,108 @@ +(module + (type $ftype0 (func (param i32))) + (type $ftype1 (func (param i32 i64) (result i32))) + (type $ftype2 (func (param f32 f64) (result f64))) + (type $t0 (func (param (ref 1) (ref 2) (ref null 1) (ref null 2)))) + (type $t1 (func (param funcref externref (ref func)(ref extern) + anyref eqref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 3) (ref null $t0)) + (result (ref null func)))) + (type $t2 (func (param i32 i32) (result (ref null 4)))) + + ;; Duplicated types + (type $t3 (func)) + (type $t4 (func (param (ref 1) (ref 2) (ref null 1) (ref null 2)))) + (type $t5 (func (param funcref externref (ref func)(ref extern) + anyref eqref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 3) (ref null $t0)) + (result (ref null func)))) + (type $t6 (func (param i32 i32) (result (ref null 4)))) + + (type (struct (field i8 (mut i16) (mut i32) i64 f32 f64 + funcref externref (ref func)(ref extern) + anyref eqref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 5) (ref null $t0)))) + (type (struct)) + (type (struct (field))) + (type (struct (field i8))) + (type (struct (field i8 i8 i8 i8))) + (type (struct (field $x1 i32) (field $y1 i32))) + (type (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1)))) + (type (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) + (type (struct (field $x2 i32) (field f32 f64) (field $y2 i32))) + + ;; Duplicated types + (type (struct (field i8 (mut i16) (mut i32) i64 f32 f64 + funcref externref (ref func)(ref extern) + anyref eqref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 5) (ref null $t0)))) + + (type (struct)) + (type (struct (field))) + (type (struct (field i8))) + (type (struct (field i8 i8 i8 i8))) + (type (struct (field $x3 i32) (field $y3 i32))) + (type (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1)))) + (type (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) + (type (struct (field $x4 i32) (field f32 f64) (field $y4 i32))) + + (type (array i8)) + (type (array i16)) + (type (array i32)) + (type (array i64)) + (type (array f32)) + (type (array f64)) + (type (array anyref)) + (type (array (ref array))) + (type (array (ref 0))) + (type (array (ref null 1))) + (type (array (mut i8))) + (type (array (mut i16))) + (type (array (mut i32))) + (type (array (mut i64))) + (type (array (mut i32))) + (type (array (mut i64))) + (type (array (mut anyref))) + (type (array (mut (ref array)))) + (type (array (mut (ref 0)))) + (type (array (mut (ref null i31)))) + + (table 10 funcref) + (table 20 externref) + ;; non-defaultable element type + ;; (table 30 (ref func)) + ;; (table 40 (ref extern)) + (table 50 anyref) + (table 60 eqref) + (table 100 arrayref) + (table 100 i31ref) + (table 100 (ref null 0)) + (table 100 (ref null 2)) + (table 100 (ref null func)) + (table 100 (ref null extern)) + (table 100 (ref null any)) + (table 100 (ref null eq)) + (table 100 (ref null i31)) + (table 100 (ref null array)) + ;; non-defaultable element type + ;; (table 100 (ref 0)) + ;; (table 100 (ref $t0)) + ;; (table 100 (ref 3)) + ;; (table 100 (ref $t0)) + (table 100 (ref null func)) + (table 100 (ref null extern)) + (table 100 (ref null 5)) + (table 100 (ref null $t0)) +) diff --git a/tests/unit/gc/wasm-apps/test1.wasm b/tests/unit/gc/wasm-apps/test1.wasm new file mode 100644 index 0000000000..d907e457f5 Binary files /dev/null and b/tests/unit/gc/wasm-apps/test1.wasm differ diff --git a/tests/unit/gc/wasm-apps/test1.wast b/tests/unit/gc/wasm-apps/test1.wast new file mode 100644 index 0000000000..0f282895c0 --- /dev/null +++ b/tests/unit/gc/wasm-apps/test1.wast @@ -0,0 +1,117 @@ +(module + (type $t (func)) + (type $t0 (func (param (ref null $t) (ref $t) (ref null 0) (ref 0) (ref null 1) (ref 1)))) + (type $t1 (func (param funcref externref anyref eqref + i31ref structref arrayref + nullref nullfuncref nullexternref + (ref null func) (ref null extern) (ref null any) (ref null eq) + (ref null i31) (ref null struct) (ref null array) + (ref null none) (ref null nofunc) (ref null noextern) + (ref func) (ref extern) (ref any) (ref eq) + (ref i31) (ref struct) (ref array) + (ref none) (ref nofunc) (ref noextern) + + (ref null 0) (ref null $t0) (ref null $t1) + (ref null func) (ref null extern) (ref null any) (ref null eq) + (ref null i31) (ref null struct) (ref null array) + (ref $t) (ref $t0) (ref $t1) + (ref func) (ref extern) (ref any) (ref eq) + (ref i31) (ref struct) (ref array)) + (result (ref null func) (ref null extern) (ref $t0)))) + (type $t2 (func (param i32 i32) (result (ref null $t1)))) + + ;; Duplicated types + (type $t3 (func)) + (type $t4 (func (param (ref null $t) (ref $t) (ref null 0) (ref 0) (ref null 1) (ref 1)))) + (type $t5 (func (param funcref externref anyref eqref + i31ref structref arrayref + nullref nullfuncref nullexternref + (ref null func) (ref null extern) (ref null any) (ref null eq) + (ref null i31) (ref null struct) (ref null array) + (ref null none) (ref null nofunc) (ref null noextern) + (ref func) (ref extern) (ref any) (ref eq) + (ref i31) (ref struct) (ref array) + (ref none) (ref nofunc) (ref noextern) + + (ref null 0) (ref null $t0) (ref null $t1) + (ref null func) (ref null extern) (ref null any) (ref null eq) + (ref null i31) (ref null struct) (ref null array) + (ref $t) (ref $t0) (ref $t1) + (ref func) (ref extern) (ref any) (ref eq) + (ref i31) (ref struct) (ref array)) + (result (ref null func) (ref null extern) (ref $t0)))) + (type $t6 (func (param i32 i32) (result (ref null $t1)))) + + (type (struct (field i8 (mut i16) (mut i32) i64 f32 f64 + funcref externref (ref func) (ref extern) + anyref eqref structref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null struct) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 5) (ref null $t0)))) + + (type (struct)) + (type (struct (field))) + (type (struct (field i8))) + (type (struct (field i8 i8 i8 i8))) + (type (struct (field $x1 i32) (field $y1 i32))) + (type (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1)))) + (type (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) + (type (struct (field $x2 i32) (field f32 f64) (field $y2 i32))) + + ;; Duplicated types + (type (struct (field i8 (mut i16) (mut i32) i64 f32 f64 + funcref externref (ref func) (ref extern) + anyref eqref structref arrayref i31ref + (ref null 0) (ref null 2) (ref null func) (ref null extern) + (ref null any) (ref null eq) (ref null i31) (ref null struct) (ref null array) + (ref 0) (ref $t0) (ref 3) (ref $t0) (ref null func) + (ref null extern) (ref null 5) (ref null $t0)))) + (type (struct)) + (type (struct (field))) + (type (struct (field i8))) + (type (struct (field i8 i8 i8 i8))) + (type (struct (field $x3 i32) (field $y3 i32))) + (type (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1)))) + (type (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref))) + (type (struct (field $x4 i32) (field f32 f64) (field $y4 i32))) + + (type (array i8)) + (type (array i16)) + (type (array i32)) + (type (array i64)) + (type (array f32)) + (type (array f64)) + (type (array anyref)) + (type (array (ref struct))) + (type (array (ref array))) + (type (array (ref null struct))) + (type (array (ref null array))) + (type (array (ref 0))) + (type (array (ref null 1))) + (type (array (mut i8))) + (type (array (mut i16))) + (type (array (mut i32))) + (type (array (mut i64))) + (type (array (mut i32))) + (type (array (mut i64))) + (type (array (mut anyref))) + (type (array (mut (ref struct)))) + (type (array (mut (ref array)))) + (type (array (mut (ref null struct)))) + (type (array (mut (ref null array)))) + (type (array (mut (ref 0)))) + (type (array (mut (ref null i31)))) + + ;; sub types + (type $e0 (sub (array i32))) + (type $e1 (sub $e0 (array i32))) + + (type $e2 (sub (array anyref))) + (type $e3 (sub (array (ref null $e0)))) + (type $e4 (sub (array (ref $e1)))) + (type $e5 (sub $e1 (array i32))) + + (type $m1 (sub (array (mut i32)))) + (type $m2 (sub $m1 (array (mut i32)))) +) diff --git a/tests/unit/gc/wasm-apps/test2.wasm b/tests/unit/gc/wasm-apps/test2.wasm new file mode 100644 index 0000000000..04507f1748 Binary files /dev/null and b/tests/unit/gc/wasm-apps/test2.wasm differ diff --git a/tests/unit/gc/wasm-apps/test2.wast b/tests/unit/gc/wasm-apps/test2.wast new file mode 100644 index 0000000000..c2f7f36365 --- /dev/null +++ b/tests/unit/gc/wasm-apps/test2.wast @@ -0,0 +1,104 @@ +(module + (type $ft (func)) + (type $st (struct)) + (type $at (array i8)) + + (table $ta 10 anyref) + (table $tf 10 funcref) + (table $te 10 externref) + + (elem declare func $f) + (func $f) + + (func (export "init") (param $x externref) + (table.set $ta (i32.const 0) (ref.null any)) + (table.set $ta (i32.const 1) (ref.null struct)) + (table.set $ta (i32.const 2) (ref.null none)) + (table.set $ta (i32.const 3) (i31.new (i32.const 7))) + (table.set $ta (i32.const 4) (struct.new_canon_default $st)) + (table.set $ta (i32.const 5) (array.new_canon_default $at (i32.const 0))) + (table.set $ta (i32.const 6) (extern.internalize (local.get $x))) + (table.set $ta (i32.const 7) (extern.internalize (ref.null extern))) + + (table.set $tf (i32.const 0) (ref.null nofunc)) + (table.set $tf (i32.const 1) (ref.null func)) + (table.set $tf (i32.const 2) (ref.func $f)) + + (table.set $te (i32.const 0) (ref.null noextern)) + (table.set $te (i32.const 1) (ref.null extern)) + (table.set $te (i32.const 2) (local.get $x)) + (table.set $te (i32.const 3) (extern.externalize (i31.new (i32.const 8)))) + (table.set $te (i32.const 4) (extern.externalize (struct.new_canon_default $st))) + (table.set $te (i32.const 5) (extern.externalize (ref.null any))) + ) + + (func (export "ref_test_null_data") (param $i i32) (result i32) + (i32.add + (ref.is_null (table.get $ta (local.get $i))) + (ref.test null none (table.get $ta (local.get $i))) + ) + ) + + (func (export "ref_test_any") (param $i i32) (result i32) + (i32.add + (ref.test any (table.get $ta (local.get $i))) + (ref.test null any (table.get $ta (local.get $i))) + ) + ) + + (func (export "ref_test_eq") (param $i i32) (result i32) + (i32.add + (ref.test eq (table.get $ta (local.get $i))) + (ref.test null eq (table.get $ta (local.get $i))) + ) + ) + + (func (export "ref_test_i31") (param $i i32) (result i32) + (i32.add + (ref.test i31 (table.get $ta (local.get $i))) + (ref.test null i31 (table.get $ta (local.get $i))) + ) + ) + + (func (export "ref_test_struct") (param $i i32) (result i32) + (i32.add + (ref.test struct (table.get $ta (local.get $i))) + (ref.test null struct (table.get $ta (local.get $i))) + ) + ) + + (func (export "ref_test_array") (param $i i32) (result i32) + (i32.add + (ref.test array (table.get $ta (local.get $i))) + (ref.test null array (table.get $ta (local.get $i))) + ) + ) + + (func (export "ref_test_null_func") (param $i i32) (result i32) + (i32.add + (ref.is_null (table.get $tf (local.get $i))) + (ref.test null nofunc (table.get $tf (local.get $i))) + ) + ) + + (func (export "ref_test_func") (param $i i32) (result i32) + (i32.add + (ref.test func (table.get $tf (local.get $i))) + (ref.test null func (table.get $tf (local.get $i))) + ) + ) + + (func (export "ref_test_null_extern") (param $i i32) (result i32) + (i32.add + (ref.is_null (table.get $te (local.get $i))) + (ref.test null noextern (table.get $te (local.get $i))) + ) + ) + + (func (export "ref_test_extern") (param $i i32) (result i32) + (i32.add + (ref.test extern (table.get $te (local.get $i))) + (ref.test null extern (table.get $te (local.get $i))) + ) + ) +) diff --git a/tests/unit/gc/wasm-apps/test3.wasm b/tests/unit/gc/wasm-apps/test3.wasm new file mode 100644 index 0000000000..8ee87dc812 Binary files /dev/null and b/tests/unit/gc/wasm-apps/test3.wasm differ diff --git a/tests/unit/gc/wasm-apps/test3.wast b/tests/unit/gc/wasm-apps/test3.wast new file mode 100644 index 0000000000..4df02ce8fc --- /dev/null +++ b/tests/unit/gc/wasm-apps/test3.wast @@ -0,0 +1,146 @@ +(module + (type $t0 (sub (struct))) + (type $t1 (sub $t0 (struct (field i32)))) + (type $t1' (sub $t0 (struct (field i32)))) + (type $t2 (sub $t1 (struct (field i32 i32)))) + (type $t2' (sub $t1' (struct (field i32 i32)))) + (type $t3 (sub $t0 (struct (field i32 i32)))) + (type $t0' (sub $t0 (struct))) + (type $t4 (sub $t0' (struct (field i32 i32)))) + + (table 20 (ref null struct)) + + (func $init + (table.set (i32.const 0) (struct.new_canon_default $t0)) + (table.set (i32.const 10) (struct.new_canon_default $t0)) + (table.set (i32.const 1) (struct.new_canon_default $t1)) + (table.set (i32.const 11) (struct.new_canon_default $t1')) + (table.set (i32.const 2) (struct.new_canon_default $t2)) + (table.set (i32.const 12) (struct.new_canon_default $t2')) + (table.set (i32.const 3) (struct.new_canon_default $t3)) + (table.set (i32.const 4) (struct.new_canon_default $t4)) + ) + + (func (export "test-sub") + (call $init) + (block $l + ;; must hold + (br_if $l (i32.eqz (ref.test null $t0 (ref.null struct)))) + (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t0)))) + (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t1)))) + (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t2)))) + (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t3)))) + (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t4)))) + (br_if $l (i32.eqz (ref.test null $t0 (table.get (i32.const 0))))) + (br_if $l (i32.eqz (ref.test null $t0 (table.get (i32.const 1))))) + (br_if $l (i32.eqz (ref.test null $t0 (table.get (i32.const 2))))) + (br_if $l (i32.eqz (ref.test null $t0 (table.get (i32.const 3))))) + (br_if $l (i32.eqz (ref.test null $t0 (table.get (i32.const 4))))) + + (br_if $l (i32.eqz (ref.test null $t1 (ref.null struct)))) + (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t0)))) + (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t1)))) + (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t2)))) + (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t3)))) + (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t4)))) + (br_if $l (i32.eqz (ref.test null $t1 (table.get (i32.const 1))))) + (br_if $l (i32.eqz (ref.test null $t1 (table.get (i32.const 2))))) + + (br_if $l (i32.eqz (ref.test null $t2 (ref.null struct)))) + (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t0)))) + (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t1)))) + (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t2)))) + (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t3)))) + (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t4)))) + (br_if $l (i32.eqz (ref.test null $t2 (table.get (i32.const 2))))) + + (br_if $l (i32.eqz (ref.test null $t3 (ref.null struct)))) + (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t0)))) + (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t1)))) + (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t2)))) + (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t3)))) + (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t4)))) + (br_if $l (i32.eqz (ref.test null $t3 (table.get (i32.const 3))))) + + (br_if $l (i32.eqz (ref.test null $t4 (ref.null struct)))) + (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t0)))) + (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t1)))) + (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t2)))) + (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t3)))) + (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t4)))) + (br_if $l (i32.eqz (ref.test null $t4 (table.get (i32.const 4))))) + + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 0))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 1))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 2))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 3))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 4))))) + + (br_if $l (i32.eqz (ref.test $t1 (table.get (i32.const 1))))) + (br_if $l (i32.eqz (ref.test $t1 (table.get (i32.const 2))))) + + (br_if $l (i32.eqz (ref.test $t2 (table.get (i32.const 2))))) + + (br_if $l (i32.eqz (ref.test $t3 (table.get (i32.const 3))))) + + (br_if $l (i32.eqz (ref.test $t4 (table.get (i32.const 4))))) + + ;; must not hold + (br_if $l (ref.test $t0 (ref.null struct))) + (br_if $l (ref.test $t1 (ref.null struct))) + (br_if $l (ref.test $t2 (ref.null struct))) + (br_if $l (ref.test $t3 (ref.null struct))) + (br_if $l (ref.test $t4 (ref.null struct))) + + (br_if $l (ref.test $t1 (table.get (i32.const 0)))) + (br_if $l (ref.test $t1 (table.get (i32.const 3)))) + (br_if $l (ref.test $t1 (table.get (i32.const 4)))) + + (br_if $l (ref.test $t2 (table.get (i32.const 0)))) + (br_if $l (ref.test $t2 (table.get (i32.const 1)))) + (br_if $l (ref.test $t2 (table.get (i32.const 3)))) + (br_if $l (ref.test $t2 (table.get (i32.const 4)))) + + (br_if $l (ref.test $t3 (table.get (i32.const 0)))) + (br_if $l (ref.test $t3 (table.get (i32.const 1)))) + (br_if $l (ref.test $t3 (table.get (i32.const 2)))) + (br_if $l (ref.test $t3 (table.get (i32.const 4)))) + + (br_if $l (ref.test $t4 (table.get (i32.const 0)))) + (br_if $l (ref.test $t4 (table.get (i32.const 1)))) + (br_if $l (ref.test $t4 (table.get (i32.const 2)))) + (br_if $l (ref.test $t4 (table.get (i32.const 3)))) + + (return) + ) + (unreachable) + ) + + (func (export "test-canon") + (call $init) + (block $l + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 0))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 1))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 2))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 3))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 4))))) + + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 10))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 11))))) + (br_if $l (i32.eqz (ref.test $t0 (table.get (i32.const 12))))) + + (br_if $l (i32.eqz (ref.test $t1' (table.get (i32.const 1))))) + (br_if $l (i32.eqz (ref.test $t1' (table.get (i32.const 2))))) + + (br_if $l (i32.eqz (ref.test $t1 (table.get (i32.const 11))))) + (br_if $l (i32.eqz (ref.test $t1 (table.get (i32.const 12))))) + + (br_if $l (i32.eqz (ref.test $t2' (table.get (i32.const 2))))) + + (br_if $l (i32.eqz (ref.test $t2 (table.get (i32.const 12))))) + + (return) + ) + (unreachable) + ) +) diff --git a/tests/unit/gc/wasm-apps/test4.wasm b/tests/unit/gc/wasm-apps/test4.wasm new file mode 100644 index 0000000000..b4841a82cb Binary files /dev/null and b/tests/unit/gc/wasm-apps/test4.wasm differ diff --git a/tests/unit/gc/wasm-apps/test4.wast b/tests/unit/gc/wasm-apps/test4.wast new file mode 100644 index 0000000000..8bf02e4307 --- /dev/null +++ b/tests/unit/gc/wasm-apps/test4.wast @@ -0,0 +1,46 @@ +(module + (type $ft (func)) + (type $st (struct)) + (type $at (array i8)) + + (table 10 anyref) + + (elem declare func $f) + (func $f) + + (func (export "init") (param $x externref) + (table.set (i32.const 0) (ref.null any)) + (table.set (i32.const 1) (i31.new (i32.const 7))) + (table.set (i32.const 2) (struct.new_canon_default $st)) + (table.set (i32.const 3) (array.new_canon_default $at (i32.const 0))) + (table.set (i32.const 4) (extern.internalize (local.get $x))) + (table.set (i32.const 5) (ref.null i31)) + (table.set (i32.const 6) (ref.null struct)) + (table.set (i32.const 7) (ref.null none)) + ) + + (func (export "ref_cast_non_null") (param $i i32) + (drop (ref.as_non_null (table.get (local.get $i)))) + (drop (ref.cast null any (table.get (local.get $i)))) + ) + (func (export "ref_cast_null") (param $i i32) + (drop (ref.cast null any (table.get (local.get $i)))) + (drop (ref.cast null struct (table.get (local.get $i)))) + (drop (ref.cast null array (table.get (local.get $i)))) + (drop (ref.cast null i31 (table.get (local.get $i)))) + (drop (ref.cast null none (table.get (local.get $i)))) + ) + (func (export "ref_cast_i31") (param $i i32) + (drop (ref.cast i31 (table.get (local.get $i)))) + (drop (ref.cast null i31 (table.get (local.get $i)))) + ) + (func (export "ref_cast_struct") (param $i i32) + (drop (ref.cast struct (table.get (local.get $i)))) + (drop (ref.cast null struct (table.get (local.get $i)))) + ) + (func (export "ref_cast_array") (param $i i32) + (drop (ref.cast array (table.get (local.get $i)))) + (drop (ref.cast null array (table.get (local.get $i)))) + ) +) + diff --git a/tests/unit/gc/wasm-apps/test5.wasm b/tests/unit/gc/wasm-apps/test5.wasm new file mode 100644 index 0000000000..050ead4ae9 Binary files /dev/null and b/tests/unit/gc/wasm-apps/test5.wasm differ diff --git a/tests/unit/gc/wasm-apps/test5.wast b/tests/unit/gc/wasm-apps/test5.wast new file mode 100644 index 0000000000..895473ce31 --- /dev/null +++ b/tests/unit/gc/wasm-apps/test5.wast @@ -0,0 +1,85 @@ +(module + (type $t0 (sub (struct))) + (type $t1 (sub $t0 (struct (field i32)))) + (type $t1' (sub $t0 (struct (field i32)))) + (type $t2 (sub $t1 (struct (field i32 i32)))) + (type $t2' (sub $t1' (struct (field i32 i32)))) + (type $t3 (sub $t0 (struct (field i32 i32)))) + (type $t0' (sub $t0 (struct))) + (type $t4 (sub $t0' (struct (field i32 i32)))) + + (table 20 (ref null struct)) + + (func $init + (table.set (i32.const 0) (struct.new_canon_default $t0)) + (table.set (i32.const 10) (struct.new_canon_default $t0)) + (table.set (i32.const 1) (struct.new_canon_default $t1)) + (table.set (i32.const 11) (struct.new_canon_default $t1')) + (table.set (i32.const 2) (struct.new_canon_default $t2)) + (table.set (i32.const 12) (struct.new_canon_default $t2')) + (table.set (i32.const 3) (struct.new_canon_default $t3)) + (table.set (i32.const 4) (struct.new_canon_default $t4)) + ) + + (func (export "test-sub") + (call $init) + + (drop (ref.cast null $t0 (ref.null struct))) + (drop (ref.cast null $t0 (table.get (i32.const 0)))) + (drop (ref.cast null $t0 (table.get (i32.const 1)))) + (drop (ref.cast null $t0 (table.get (i32.const 2)))) + (drop (ref.cast null $t0 (table.get (i32.const 3)))) + (drop (ref.cast null $t0 (table.get (i32.const 4)))) + + (drop (ref.cast null $t0 (ref.null struct))) + (drop (ref.cast null $t1 (table.get (i32.const 1)))) + (drop (ref.cast null $t1 (table.get (i32.const 2)))) + + (drop (ref.cast null $t0 (ref.null struct))) + (drop (ref.cast null $t2 (table.get (i32.const 2)))) + + (drop (ref.cast null $t0 (ref.null struct))) + (drop (ref.cast null $t3 (table.get (i32.const 3)))) + + (drop (ref.cast null $t4 (table.get (i32.const 4)))) + + (drop (ref.cast $t0 (table.get (i32.const 0)))) + (drop (ref.cast $t0 (table.get (i32.const 1)))) + (drop (ref.cast $t0 (table.get (i32.const 2)))) + (drop (ref.cast $t0 (table.get (i32.const 3)))) + (drop (ref.cast $t0 (table.get (i32.const 4)))) + + (drop (ref.cast $t1 (table.get (i32.const 1)))) + (drop (ref.cast $t1 (table.get (i32.const 2)))) + + (drop (ref.cast $t2 (table.get (i32.const 2)))) + + (drop (ref.cast $t3 (table.get (i32.const 3)))) + + (drop (ref.cast $t4 (table.get (i32.const 4)))) + ) + + (func (export "test-canon") + (call $init) + + (drop (ref.cast $t0 (table.get (i32.const 0)))) + (drop (ref.cast $t0 (table.get (i32.const 1)))) + (drop (ref.cast $t0 (table.get (i32.const 2)))) + (drop (ref.cast $t0 (table.get (i32.const 3)))) + (drop (ref.cast $t0 (table.get (i32.const 4)))) + + (drop (ref.cast $t0 (table.get (i32.const 10)))) + (drop (ref.cast $t0 (table.get (i32.const 11)))) + (drop (ref.cast $t0 (table.get (i32.const 12)))) + + (drop (ref.cast $t1' (table.get (i32.const 1)))) + (drop (ref.cast $t1' (table.get (i32.const 2)))) + + (drop (ref.cast $t1 (table.get (i32.const 11)))) + (drop (ref.cast $t1 (table.get (i32.const 12)))) + + (drop (ref.cast $t2' (table.get (i32.const 2)))) + + (drop (ref.cast $t2 (table.get (i32.const 12)))) + ) +) diff --git a/tests/unit/gc/wasm-apps/test6.wasm b/tests/unit/gc/wasm-apps/test6.wasm new file mode 100644 index 0000000000..b1abc14729 Binary files /dev/null and b/tests/unit/gc/wasm-apps/test6.wasm differ diff --git a/tests/unit/gc/wasm-apps/test6.wast b/tests/unit/gc/wasm-apps/test6.wast new file mode 100644 index 0000000000..0959b36f0c --- /dev/null +++ b/tests/unit/gc/wasm-apps/test6.wast @@ -0,0 +1,27 @@ +(module + (type $st (sub (struct))) + (type $st' (sub (struct (field i32)))) + (type $at (array i8)) + (type $st-sub1 (sub $st (struct))) + (type $st-sub2 (sub $st (struct))) + (type $st'-sub1 (sub $st' (struct (field i32)))) + (type $st'-sub2 (sub $st' (struct (field i32)))) + + (table 20 (ref null eq)) + + (func (export "init") + (table.set (i32.const 0) (ref.null eq)) + (table.set (i32.const 1) (ref.null i31)) + (table.set (i32.const 2) (i31.new (i32.const 7))) + (table.set (i32.const 3) (i31.new (i32.const 7))) + (table.set (i32.const 4) (i31.new (i32.const 8))) + (table.set (i32.const 5) (struct.new_canon_default $st)) + (table.set (i32.const 6) (struct.new_canon_default $st)) + (table.set (i32.const 7) (array.new_canon_default $at (i32.const 0))) + (table.set (i32.const 8) (array.new_canon_default $at (i32.const 0))) + ) + + (func (export "eq") (param $i i32) (param $j i32) (result i32) + (ref.eq (table.get (local.get $i)) (table.get (local.get $j))) + ) +) diff --git a/tests/unit/interpreter/.gitignore b/tests/unit/interpreter/.gitignore new file mode 100644 index 0000000000..d9b4f015d3 --- /dev/null +++ b/tests/unit/interpreter/.gitignore @@ -0,0 +1 @@ +/build/* diff --git a/tests/unit/interpreter/CMakeLists.txt b/tests/unit/interpreter/CMakeLists.txt new file mode 100644 index 0000000000..c99908b2ed --- /dev/null +++ b/tests/unit/interpreter/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-interpreter) + +add_definitions (-DRUN_ON_LINUX) + +add_definitions (-Dattr_container_malloc=malloc) +add_definitions (-Dattr_container_free=free) +# add_definitions (-DWASM_ENABLE_WAMR_COMPILER=1) + +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 1) +set (WAMR_BUILD_AOT 0) + +include (../unit_common.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ${LIBC_BUILTIN_SOURCE} + ${IWASM_COMMON_SOURCE} + ${IWASM_INTERP_SOURCE} + ) + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable (interpreter_test ${unit_test_sources}) + +target_link_libraries (interpreter_test ${LLVM_AVAILABLE_LIBS} gtest_main ) + +gtest_discover_tests(interpreter_test) diff --git a/tests/unit/interpreter/interpreter_test.cc b/tests/unit/interpreter/interpreter_test.cc new file mode 100644 index 0000000000..e9fa8f9e16 --- /dev/null +++ b/tests/unit/interpreter/interpreter_test.cc @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include "gtest/gtest.h" +#include "wasm_runtime_common.h" +#include "bh_platform.h" + +// To use a test fixture, derive a class from testing::Test. +class InterpreterTest : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() + { + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + ASSERT_EQ(wasm_runtime_full_init(&init_args), true); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() { wasm_runtime_destroy(); } + + public: + char global_heap_buf[512 * 1024]; + RuntimeInitArgs init_args; +}; + +TEST_F(InterpreterTest, wasm_runtime_is_built_in_module) +{ + bool ret = wasm_runtime_is_built_in_module("env"); + ASSERT_TRUE(ret); + + ret = ret = wasm_runtime_is_built_in_module("env1"); + ASSERT_FALSE(ret); +} \ No newline at end of file diff --git a/tests/unit/libc-builtin/CMakeLists.txt b/tests/unit/libc-builtin/CMakeLists.txt new file mode 100644 index 0000000000..4d88760e79 --- /dev/null +++ b/tests/unit/libc-builtin/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-libc-builtin) + +add_definitions (-DRUN_ON_LINUX) + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 0) + +include (../unit_common.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} + ) + +add_executable (libc_builtin_test ${unit_test_sources}) + +target_link_libraries (libc_builtin_test gtest_main) + +gtest_discover_tests(libc_builtin_test) diff --git a/tests/unit/libc-builtin/func_types.h b/tests/unit/libc-builtin/func_types.h new file mode 100644 index 0000000000..c653ee9c8f --- /dev/null +++ b/tests/unit/libc-builtin/func_types.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "bh_platform.h" +#include "wasm_export.h" + +extern "C" { +typedef char *_va_list; + +typedef int (*printf_func_type)(wasm_exec_env_t exec_env, const char *format, + _va_list va_args); + +typedef int (*sprintf_func_type)(wasm_exec_env_t exec_env, char *str, + const char *format, _va_list va_args); + +typedef int (*snprintf_func_type)(wasm_exec_env_t exec_env, char *str, + uint32 size, const char *format, + _va_list va_args); + +typedef int (*puts_func_type)(wasm_exec_env_t exec_env, const char *str); + +typedef int (*putchar_func_type)(wasm_exec_env_t exec_env, int c); + +typedef uint32 (*strdup_func_type)(wasm_exec_env_t exec_env, const char *str); + +typedef uint32 (*_strdup_func_type)(wasm_exec_env_t exec_env, const char *str); + +typedef int32 (*memcmp_func_type)(wasm_exec_env_t exec_env, const void *s1, + const void *s2, uint32 size); + +typedef uint32 (*memcpy_func_type)(wasm_exec_env_t exec_env, void *dst, + const void *src, uint32 size); + +typedef uint32 (*memmove_func_type)(wasm_exec_env_t exec_env, void *dst, + void *src, uint32 size); + +typedef uint32 (*memset_func_type)(wasm_exec_env_t exec_env, void *s, int32 c, + uint32 size); + +typedef uint32 (*strchr_func_type)(wasm_exec_env_t exec_env, const char *s, + int32 c); + +typedef int32 (*strcmp_func_type)(wasm_exec_env_t exec_env, const char *s1, + const char *s2); + +typedef int32 (*strncmp_func_type)(wasm_exec_env_t exec_env, const char *s1, + const char *s2, uint32 size); + +typedef uint32 (*strcpy_func_type)(wasm_exec_env_t exec_env, char *dst, + const char *src); + +typedef uint32 (*strncpy_func_type)(wasm_exec_env_t exec_env, char *dst, + const char *src, uint32 size); + +typedef uint32 (*strlen_func_type)(wasm_exec_env_t exec_env, const char *s); + +typedef uint32 (*malloc_func_type)(wasm_exec_env_t exec_env, uint32 size); + +typedef uint32 (*calloc_func_type)(wasm_exec_env_t exec_env, uint32 nmemb, + uint32 size); + +typedef uint32 (*realloc_func_type)(wasm_exec_env_t exec_env, uint32 ptr, + uint32 new_size); + +typedef void (*free_func_type)(wasm_exec_env_t exec_env, void *ptr); + +typedef int32 (*atoi_func_type)(wasm_exec_env_t exec_env, const char *s); + +typedef void (*exit_func_type)(wasm_exec_env_t exec_env, int32 status); + +typedef int32 (*strtol_func_type)(wasm_exec_env_t exec_env, const char *nptr, + char **endptr, int32 base); + +typedef uint32 (*strtoul_func_type)(wasm_exec_env_t exec_env, const char *nptr, + char **endptr, int32 base); + +typedef uint32 (*memchr_func_type)(wasm_exec_env_t exec_env, const void *s, + int32 c, uint32 n); + +typedef int32 (*strncasecmp_func_type)(wasm_exec_env_t exec_env, const char *s1, + const char *s2, uint32 n); +typedef uint32 (*strspn_func_type)(wasm_exec_env_t exec_env, const char *s, + const char *accept); + +typedef uint32 (*strcspn_func_type)(wasm_exec_env_t exec_env, const char *s, + const char *reject); + +typedef uint32 (*strstr_func_type)(wasm_exec_env_t exec_env, const char *s, + const char *find); + +typedef int32 (*isupper_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef int32 (*isalpha_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef int32 (*isspace_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef int32 (*isgraph_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef int32 (*isprint_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef int32 (*isdigit_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef int32 (*isxdigit_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef int32 (*tolower_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef int32 (*toupper_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef int32 (*isalnum_func_type)(wasm_exec_env_t exec_env, int32 c); + +typedef void (*setTempRet0_func_type)(wasm_exec_env_t exec_env, + uint32 temp_ret); + +typedef uint32 (*getTempRet0_func_type)(wasm_exec_env_t exec_env); + +typedef uint32 (*llvm_bswap_i16_func_type)(wasm_exec_env_t exec_env, + uint32 data); + +typedef uint32 (*llvm_bswap_i32_func_type)(wasm_exec_env_t exec_env, + uint32 data); + +typedef uint32 (*bitshift64Lshr_func_type)(wasm_exec_env_t exec_env, + uint32 uint64_part0, + uint32 uint64_part1, uint32 bits); + +typedef uint32 (*bitshift64Shl_func_type)(wasm_exec_env_t exec_env, + uint32 int64_part0, + uint32 int64_part1, uint32 bits); + +typedef void (*llvm_stackrestore_func_type)(wasm_exec_env_t exec_env, + uint32 llvm_stack); + +typedef uint32 (*llvm_stacksave_func_type)(wasm_exec_env_t exec_env); + +typedef uint32 (*emscripten_memcpy_big_func_type)(wasm_exec_env_t exec_env, + void *dst, const void *src, + uint32 size); + +typedef void (*abort_func_type)(wasm_exec_env_t exec_env, int32 code); + +typedef void (*abortStackOverflow_func_type)(wasm_exec_env_t exec_env, + int32 code); + +typedef void (*nullFunc_X_func_type)(wasm_exec_env_t exec_env, int32 code); + +typedef uint32 (*__cxa_allocate_exception_func_type)(wasm_exec_env_t exec_env, + uint32 thrown_size); + +typedef void (*__cxa_begin_catch_func_type)(wasm_exec_env_t exec_env, + void *exception_object); + +typedef void (*__cxa_throw_func_type)(wasm_exec_env_t exec_env, + void *thrown_exception, void *tinfo, + uint32 table_elem_idx); + +struct timespec_app { + int64 tv_sec; + int32 tv_nsec; +}; + +typedef uint32 (*clock_gettime_func_type)(wasm_exec_env_t exec_env, + uint32 clk_id, + struct timespec_app *ts_app); + +typedef uint64 (*clock_func_type)(wasm_exec_env_t exec_env); +} diff --git a/tests/unit/libc-builtin/libc_builtin_test.cc b/tests/unit/libc-builtin/libc_builtin_test.cc new file mode 100644 index 0000000000..6598f7a8b6 --- /dev/null +++ b/tests/unit/libc-builtin/libc_builtin_test.cc @@ -0,0 +1,1412 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "func_types.h" +#include "test_helper.h" +#include "wasm_export.h" +#include "gtest/gtest.h" +#include + +#include "../interpreter/wasm.h" + +void *func_ptr; +#define CALL_FUNC(name, ...) \ + ((name##_func_type)get_func(#name))(dummy_exec_env.get(), ##__VA_ARGS__) + +extern "C" { +extern uint32_t +get_libc_builtin_export_apis(NativeSymbol **p_libc_builtin_apis); + +extern bool +wasm_native_lookup_libc_builtin_global(const char *module_name, + const char *global_name, + WASMGlobalImport *global); +} + +class LibcBuiltinTest : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() + { + n_native_symbols = get_libc_builtin_export_apis(&native_symbols); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + public: + WAMRRuntimeRAII<512 * 1024> runtime; + DummyExecEnv dummy_exec_env; + static NativeSymbol *native_symbols; + static uint32_t n_native_symbols; + + static void *get_func(const char *name) + { + int32_t i; + + for (i = 0; i < n_native_symbols; i++) { + if (strcmp(native_symbols[i].symbol, name) == 0) { + return native_symbols[i].func_ptr; + } + } + + return NULL; + } +}; + +NativeSymbol *LibcBuiltinTest::native_symbols; +uint32_t LibcBuiltinTest::n_native_symbols; + +static const char very_long_string[] = + R"(2mwa9vxDhuuvO47XePZvc4DAMdR8dzgKrmRNAM3qVoedFhG7GYyhlC4JiuSdrw8G + 7vrPoCLGlVlGwMw7ATDL3bA5Filds8krTxS7h8ioq6CY4UmKl1zjHlmnOYRO3Wmp + ylp21RrG8LzfHFerFyKFxA1GB93OuTFcasO2n9uQljCx8h5KRolbvjdHVnado4B6 + 3zNV990V7T7LIJHwZKb0RGg0fFo4GQd6Mfdl6aD3UlpKBIxjbonyeaQBY7hPZB8R + J1JV5iw2PWB2BJEGoGhTvlc0a9FxmeqWIjpnU3yNEg2lD3NjZU627pTFcoAy5GCz + wDyF5QzcvtAgWBR95kRpDtV21CRyQ6HteorX1aHemoMYWOLIvX52stUTAnOImMD8 + tIw6xwkOZx5fs3x9m540pPnRDiihLn2XuQ1PLPwA6orWOGm3dBKthqsycTqaIl0L + 0gpycKbVYFHmakfgEyP9fyMziLT11B6EPzomHQAYgTVUdDl9u63P6sQCeaPwAYsY + gus28uK9YYjpXgOOziG8ocBddvids1iLJLdbiAqKyHaVY4IBLVWU3F74tKGF7TeI + DGAfvpzHls19VM9bKReBfCmDgbib7mCpYEFAQCmu5my0C8QrJlUoOgiljIO0x3sH + ByNf4k9OfhzYi1V4cvDnMELVrk0fyZWmIxDvig7nfzI57OltT28pughPBlLxTn8X + xyMNVYn1dD6Wpp7sqOBjxWGWmdrjleyin0iQ05UbfioHazvLKHtDfm5P2WwVejm6)"; + +TEST_F(LibcBuiltinTest, puts) +{ + char ll_string[2048]; + + /* Capture the stdout */ + testing::internal::CaptureStdout(); + EXPECT_EQ(CALL_FUNC(puts, "Hello Wrold"), strlen("Hello Wrold\n")); + EXPECT_EQ(testing::internal::GetCapturedStdout(), "Hello Wrold\n"); + + testing::internal::CaptureStdout(); + EXPECT_EQ(CALL_FUNC(puts, "c"), strlen("c\n")); + EXPECT_EQ(testing::internal::GetCapturedStdout(), "c\n"); + + testing::internal::CaptureStdout(); + EXPECT_EQ(CALL_FUNC(puts, very_long_string), strlen(very_long_string) + 1); + EXPECT_EQ(testing::internal::GetCapturedStdout(), + std::string(very_long_string) + "\n"); + + memset(ll_string, 0xAA, sizeof(ll_string)); + testing::internal::CaptureStdout(); + EXPECT_EQ(CALL_FUNC(puts, ll_string), strlen(ll_string) + 1); + EXPECT_EQ(testing::internal::GetCapturedStdout(), + std::string(ll_string) + "\n"); +} + +TEST_F(LibcBuiltinTest, printf) +{ + WAMRVaList empty_va_list(dummy_exec_env.get()); + + /* Capture the stdout */ + testing::internal::CaptureStdout(); + EXPECT_EQ(CALL_FUNC(printf, "Hello Wrold", empty_va_list.get()), + strlen("Hello Wrold")); + EXPECT_EQ(testing::internal::GetCapturedStdout(), "Hello Wrold"); + + testing::internal::CaptureStdout(); + EXPECT_EQ(CALL_FUNC(printf, "c", empty_va_list.get()), strlen("c")); + EXPECT_EQ(testing::internal::GetCapturedStdout(), "c"); + + testing::internal::CaptureStdout(); + EXPECT_EQ(CALL_FUNC(printf, very_long_string, empty_va_list.get()), + strlen(very_long_string)); + EXPECT_EQ(testing::internal::GetCapturedStdout(), very_long_string); + + /* type */ + { + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + + va_list.add(20); //%d 20 + va_list.add(65); //%i 65 + va_list.add(10); //%O 12 + va_list.add(10); //%u 10 + va_list.add(255); //%x ff + va_list.add(255); //%X FF + va_list.add(3.14); //%f 3.14 + va_list.add(3.14); //%F 3.14 + va_list.add(0.000001); //%e 1.000000e-06 + va_list.add(0.000001); //%E 1.000000E-06 + va_list.add(0.000001); //%g 1e-06 + va_list.add(0.000001); //%G 1E-06 + va_list.add("Hello World"); //%s Hello World + + testing::internal::CaptureStdout(); + /* clang-format off */ + EXPECT_EQ(CALL_FUNC(printf, "%d, %i, %o, %u, %x, %X, %f, %F, %e, %E, %g, %G, %s", va_list.get()), 97); + EXPECT_EQ(testing::internal::GetCapturedStdout(), + "20, 65, 12, 10, ff, FF, 3.140000, 3.140000, 1.000000e-06, 1.000000E-06, 1e-06, 1E-06, Hello World"); + /* clang-format on */ + } + + /* %c */ + { + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + + va_list.add('C'); //%c C + // va_list.add("Hello"); //%p + testing::internal::CaptureStdout(); + EXPECT_EQ(CALL_FUNC(printf, "%c", va_list.get()), 1); + EXPECT_EQ(testing::internal::GetCapturedStdout(), "C"); + } + + /* %p */ + { + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + + va_list.add("Hello"); + testing::internal::CaptureStdout(); + EXPECT_EQ(CALL_FUNC(printf, "%p", va_list.get()), 7); + EXPECT_EQ(testing::internal::GetCapturedStdout(), "0x200a8"); + } + + { + /* clang-format off */ + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + + va_list.add(20); //%td + va_list.add(20); //%zd + va_list.add(20); //%ld + + va_list.add(20L); //%jd + + testing::internal::CaptureStdout(); + + EXPECT_EQ(CALL_FUNC(printf, "%td, %zd, %ld, %jd", va_list.get()), 14); + EXPECT_EQ(testing::internal::GetCapturedStdout(), + "20, 20, 20, 20"); + /* clang-format on */ + } + + /* %% */ + { + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + EXPECT_TRUE(CALL_FUNC(printf, "%%", va_list.get())); + } + + /* %n */ + { + /* Construct a va_list to call printf */ + WAMRVaList empty_va_list(dummy_exec_env.get()); + + /* Capture the stdout */ + testing::internal::CaptureStdout(); + CALL_FUNC(printf, "0123%n", empty_va_list.get()); + EXPECT_EQ(testing::internal::GetCapturedStdout(), "0123"); + } + + /* flag */ + { + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + + /*%-*/ + va_list.add(20); //%-d 20 + va_list.add(20); //%d 20 + + /*%+*/ + va_list.add(20); //%+d +20 + va_list.add(-20); //%+d -20 + + /*% */ + va_list.add(20); //% d 20 + va_list.add(-20); //% d -20 + + /*%#*/ + va_list.add(20); //%#o 024 + va_list.add(255); //%#x 0xff + va_list.add(255); //%#X 0xFF + va_list.add(3.14); //%#.f 3. + va_list.add(3.14); //%#.lf 3. + va_list.add(3.14); //%#.e 3.e+00 + va_list.add(3.14); //%#.E 3.E+00 + va_list.add(3.14); //%#.g 3. + va_list.add(3.14); //%#.G 3. + va_list.add(20); //%#.a %a + va_list.add(20); //%#.A %A + + /*%0*/ + va_list.add(20); //%03d 020 + + testing::internal::CaptureStdout(); + /* clang-format off */ + EXPECT_EQ(CALL_FUNC(printf, "%-d, %d, %+d, %+d, % d, % d, %#o, %#x, %#X, %#.f, %#.lf, %#.e, %#.E, %#.g, %#.G, %#.a, %#.A, %03d", va_list.get()), 88); + EXPECT_EQ(testing::internal::GetCapturedStdout(), + "20, 20, +20, -20, 20, -20, 024, 0xff, 0XFF, 3., 3., 3.e+00, 3.E+00, 3., 3., %a, %A, 020"); + /* clang-format on */ + } + + /* precision */ + { + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + + va_list.add(20); //%d 20 + va_list.add(20); //%.1d 20 + va_list.add(20); //%.2d 20 + va_list.add(20); //%.3d 020 + va_list.add(20); //%.4d 0020 + va_list.add(20); //%.5d 00020 + va_list.add(20); //%.6d 000020 + va_list.add(20); //%.7d 0000020 + va_list.add(20); //%.8d 00000020 + va_list.add(20); //%.9d 000000020 + testing::internal::CaptureStdout(); + /* clang-format off */ + EXPECT_EQ(CALL_FUNC(printf, "%d, %.1d, %.2d, %.3d, %.4d, %.5d, %.6d, %.7d, %.8d, %.9d", va_list.get()), 66); + EXPECT_EQ(testing::internal::GetCapturedStdout(), + "20, 20, 20, 020, 0020, 00020, 000020, 0000020, 00000020, 000000020"); + /* clang-format on */ + } + + /*length*/ + { + /* clang-format off */ + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + + va_list.add(0x7F); //%hhd 127 -char + va_list.add(0xFF); //%hhu.1d 255 -unsiged char + va_list.add(0x7FFF); //%hd 32767 -sing short int + va_list.add(0xFFFF); //%hu 65535 -unsiged short + va_list.add(0x7FFFFFFF); //%ld 2147483647 - sing long + va_list.add(0xFFFFFFFF); //%lu 4294967295 -unsigned long + va_list.add(0x7FFFFFFFFFFFFFFF); //%lld 9223372036854775807 sing long long + va_list.add(0xFFFFFFFFFFFFFFFF);//%llu 18446744073709551615 unsiged long long + + testing::internal::CaptureStdout(); + + EXPECT_EQ(CALL_FUNC(printf, "%hhd, %hhu, %hd, %hu, %ld, %lu, %lld, %llu", va_list.get()), 89); + EXPECT_EQ(testing::internal::GetCapturedStdout(), + "127, 255, 32767, 65535, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615"); + /* clang-format on */ + } + + EXPECT_EQ(CALL_FUNC(printf, "Hello Wrold", 0), 0); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + EXPECT_EQ(CALL_FUNC(printf, "Hello Wrold", NULL), 0); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + EXPECT_EQ(CALL_FUNC(printf, "Hello Wrold", (char *)-1), 0); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + EXPECT_EQ(CALL_FUNC(printf, (char *)-1, (char *)-1), 0); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); +} + +TEST_F(LibcBuiltinTest, sprintf) +{ + const char *buf; + const char *str = "Hello Wrold"; + const char *str_sig = "c"; + const char *str_f = "20, 3.140000, Hello World"; + const char *str_long = "eqwewerwerqwer34were"; // test ok + // const char *str_long = "TDSFGAWE%#$TERFQ@$%$@!%$@!RS!$#@$%" + // "WAWAAEWAFSDNGFUTKNZDAERQWYNZREWGHAH"; + // //fail + + WAMRVaList empty_va_list(dummy_exec_env.get()); + + AppData buf_app{ dummy_exec_env.get(), buf }; + AppData str_app{ dummy_exec_env.get(), str }; + AppData str_sig_app{ dummy_exec_env.get(), str_sig }; + AppData str_long_app{ dummy_exec_env.get(), str_long }; + + EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), + (char *)str_app.get_native_addr(), 0), + 0); + EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), + (char *)str_app.get_native_addr(), NULL), + 0); + EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), + (char *)str_app.get_native_addr(), (char *)-1), + 0); + + EXPECT_FALSE(CALL_FUNC(sprintf, (char *)-1, + (char *)str_app.get_native_addr(), + empty_va_list.get())); + + EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), + (char *)str_app.get_native_addr(), empty_va_list.get()), + strlen(str)); + EXPECT_EQ(CALL_FUNC(memcmp, buf_app.get_native_addr(), + str_app.get_native_addr(), strlen(str)), + 0); + + EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), + (char *)str_sig_app.get_native_addr(), + empty_va_list.get()), + strlen(str_sig)); + EXPECT_EQ(CALL_FUNC(memcmp, buf_app.get_native_addr(), + str_sig_app.get_native_addr(), strlen(str_sig)), + 0); + + EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), + (char *)str_long_app.get_native_addr(), + empty_va_list.get()), + strlen(str_long)); + EXPECT_EQ(CALL_FUNC(memcmp, buf_app.get_native_addr(), + str_long_app.get_native_addr(), strlen(str_long)), + 0); + + { + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + + va_list.add(20); + va_list.add(3.14); + va_list.add("Hello World"); + + /* This is like printf("%d, %f, %s", 20, 3.14, "Hello World") */ + EXPECT_EQ(CALL_FUNC(sprintf, (char *)buf_app.get_native_addr(), + "%d, %f, %s", va_list.get()), + 25); + EXPECT_EQ(CALL_FUNC(memcmp, buf_app.get_native_addr(), str_f, 25), 0); + } +} + +TEST_F(LibcBuiltinTest, snprintf) +{ + char buf[1024]; + char buf1[10]; + + WAMRVaList empty_va_list(dummy_exec_env.get()); + + EXPECT_EQ(CALL_FUNC(snprintf, buf, strlen("Hello Wrold"), "Hello Wrold", 0), + 0); + EXPECT_EQ( + CALL_FUNC(snprintf, buf, strlen("Hello Wrold"), "Hello Wrold", NULL), + 0); + EXPECT_EQ(CALL_FUNC(snprintf, buf, strlen("Hello Wrold"), "Hello Wrold", + (char *)-1), + 0); + + EXPECT_EQ(CALL_FUNC(snprintf, buf, strlen("Hello Wrold"), "Hello Wrold", + empty_va_list.get()), + strlen("Hello Wrold")); + EXPECT_EQ(CALL_FUNC(memcmp, buf, "Hello Wrold", strlen("Hello Wrold")), 0); + + EXPECT_EQ(CALL_FUNC(snprintf, buf, strlen(very_long_string), + very_long_string, empty_va_list.get()), + strlen(very_long_string)); + { + /* Construct a va_list to call printf */ + WAMRVaList va_list(dummy_exec_env.get()); + + va_list.add(20); + va_list.add(3.14); + va_list.add("Hello World"); + + EXPECT_EQ(CALL_FUNC(snprintf, buf, 25, "%d, %f, %s", va_list.get()), + 25); + } +} + +TEST_F(LibcBuiltinTest, putchar) +{ + char ch; + + for (ch = 'a'; ch <= 'z'; ch++) + EXPECT_EQ(CALL_FUNC(putchar, ch), 1); + + for (ch = '0'; ch <= '9'; ch++) + EXPECT_EQ(CALL_FUNC(putchar, ch), 1); + + for (ch = 0; ch < 127; ch++) + EXPECT_EQ(CALL_FUNC(putchar, ch), 1); +} + +TEST_F(LibcBuiltinTest, strdup) +{ + const char *src = "Hello World!"; + + AppData src_app{ dummy_exec_env.get(), src }; + + /* exception */ + EXPECT_EQ(CALL_FUNC(strdup, NULL), 0); + + EXPECT_GE(CALL_FUNC(strdup, (char *)src_app.get_native_addr()), 0); +} + +TEST_F(LibcBuiltinTest, _strdup) +{ + const char *src = "Hello World!"; + + AppData src_app{ dummy_exec_env.get(), src }; + + /* exception */ + EXPECT_EQ(CALL_FUNC(_strdup, NULL), 0); + + EXPECT_GE(CALL_FUNC(_strdup, (char *)src_app.get_native_addr()), 0); +} + +TEST_F(LibcBuiltinTest, memcmp) +{ + const char *a = "aBcDeF"; + const char *b = "AbCdEf"; + const char *c = "aacdef"; + const char *d = "aBcDeF"; + + AppData a_app{ dummy_exec_env.get(), a }; + AppData b_app{ dummy_exec_env.get(), b }; + AppData c_app{ dummy_exec_env.get(), c }; + AppData d_app{ dummy_exec_env.get(), d }; + + /* exception */ + EXPECT_EQ(CALL_FUNC(memcmp, (void *)-1, d_app.get_native_addr(), 0), 0); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + /* size = 0 */ + EXPECT_EQ( + CALL_FUNC(memcmp, a_app.get_native_addr(), d_app.get_native_addr(), 0), + 0); + + // /* s1>s2 */ + EXPECT_GT(CALL_FUNC(memcmp, a_app.get_native_addr(), + b_app.get_native_addr(), strlen(a)), + 0); + // /* s1s2*/ + EXPECT_GT(CALL_FUNC(strcmp, (char *)b_app.get_native_addr(), + (char *)a_app.get_native_addr()), + 0); + /*s1s2*/ + EXPECT_GT(CALL_FUNC(strncmp, (char *)b_app.get_native_addr(), + (char *)a_app.get_native_addr(), strlen(a)), + 0); + /*s1s2*/ + EXPECT_GT(CALL_FUNC(strncmp, (char *)b_app.get_native_addr(), + (char *)a_app.get_native_addr(), 3), + 0); + /*s1= UINT32_MAX */ + EXPECT_EQ(CALL_FUNC(calloc, 1, 0xffffffff), 0); + + /* nmemb = 1 size=0xffffffff-1 total_size >= UINT32_MAX-1 */ + EXPECT_EQ(CALL_FUNC(calloc, 1, (0xffffffff - 1)), 0); + + /* nmemb = 1 size = 0 total_size = 0 */ + /* According to Linux man page: + If nmemb or size is 0, then calloc() returns either NULL, or a unique + pointer value that can later be successfully passed to free() */ + EXPECT_GE(CALL_FUNC(calloc, 1, 0), 0); + + /* nmemb = 10 size = 1024 total_size < UINT32_MAX */ + EXPECT_GT(CALL_FUNC(calloc, 10, 1024), 0); +} + +TEST_F(LibcBuiltinTest, realloc) +{ + unsigned int ptr = 0; + + // ptr = 0; + // EXPECT_EQ(CALL_FUNC(realloc, ptr, 1024), 0); + + // ptr = 1; + // EXPECT_GT(CALL_FUNC(realloc, ptr, 1024), 0); + + // ptr = 3; + // EXPECT_GT(CALL_FUNC(realloc, ptr, 1024), 0); + + /* If ptr is NULL, then the call is equivalent to malloc(size), for all + * values of size */ + ptr = CALL_FUNC(realloc, ptr, 1024); + EXPECT_EQ(ptr, ptr); + EXPECT_EQ(CALL_FUNC(realloc, ptr, 10), ptr); + EXPECT_EQ(CALL_FUNC(realloc, ptr, 15), ptr); + + ptr = CALL_FUNC(realloc, ptr, 2048); + EXPECT_EQ(ptr, ptr); + + /* If size is equal to zero, and ptr is not NULL, then + the call is equivalent to free(ptr) */ + CALL_FUNC(realloc, ptr, 0); +} + +TEST_F(LibcBuiltinTest, free) +{ + const char *src; + const char *s = "Hello World!"; + + AppMemory src_mem{ dummy_exec_env.get(), 15 }; + AppData s_app{ dummy_exec_env.get(), s }; + + CALL_FUNC(free, (char *)0xFFFFFFFF); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + CALL_FUNC(free, (char *)-1); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + CALL_FUNC(free, NULL); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + memset((char *)src_mem.get_native_addr(), '\0', 15); + strcpy((char *)src_mem.get_native_addr(), (char *)s_app.get_native_addr()); + EXPECT_EQ(CALL_FUNC(memcmp, (char *)src_mem.get_native_addr(), + s_app.get_native_addr(), 15), + 0); + + /* free */ + CALL_FUNC(free, (char *)src_mem.get_native_addr()); + EXPECT_NE(CALL_FUNC(memcmp, (char *)src_mem.get_native_addr(), + s_app.get_native_addr(), 15), + 0); +} + +TEST_F(LibcBuiltinTest, atoi) +{ + char *src = (char *)"123"; + char *src1 = (char *)"-123"; + + AppData src_app{ dummy_exec_env.get(), src }; + AppData src1_app{ dummy_exec_env.get(), src1 }; + + EXPECT_EQ(CALL_FUNC(atoi, (char *)src_app.get_native_addr()), 123); + EXPECT_EQ(CALL_FUNC(atoi, (char *)src1_app.get_native_addr()), -123); +} + +TEST_F(LibcBuiltinTest, exit) +{ + CALL_FUNC(exit, 3); + EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: env.exit(3)"); + dummy_exec_env.clear_exception(); +} + +TEST_F(LibcBuiltinTest, strtol) +{ + char str[20] = "20"; + char str1[20] = "-20"; + char buffer[20] = "0x31"; + char buffer1[20] = "10379cend$3"; + char *ptr; + + AppData src_app{ dummy_exec_env.get(), str }; + AppData src1_app{ dummy_exec_env.get(), str1 }; + AppData buffer_app{ dummy_exec_env.get(), buffer }; + AppData buffer1_app{ dummy_exec_env.get(), buffer1 }; + AppMemory ptr_app{ dummy_exec_env.get(), 20 }; + + CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 10); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + CALL_FUNC(strtol, (char *)src_app.get_native_addr(), &ptr, 10); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 2), 0); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 8), 0); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 10), + 0); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 16), + 0); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), NULL, 32), + 0); + + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 2), + 0); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 8), + 16); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 10), + 20); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 16), + 32); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 32), + 64); + + EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 2), + 0); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 8), + -16); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 10), + -20); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 16), + -32); + EXPECT_EQ(CALL_FUNC(strtol, (char *)src1_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 32), + -64); + + EXPECT_EQ(CALL_FUNC(strtol, (char *)buffer_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 0), + 49); + EXPECT_EQ(CALL_FUNC(strtol, (char *)buffer_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 16), + 49); + + EXPECT_EQ(CALL_FUNC(strtol, (char *)buffer_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 10), + 0); + + EXPECT_EQ(CALL_FUNC(strtol, (char *)buffer1_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 10), + 10379); + // EXPECT_STREQ((char *)ptr_app.get_native_addr(), "cend$3"); + + uint32_t str_app_addr = *(uint32_t *)ptr_app.get_native_addr(); + EXPECT_GT(str_app_addr, 0); + char *str_native_addr = (char *)dummy_exec_env.app_to_native(str_app_addr); + EXPECT_NE(str_native_addr, nullptr); + EXPECT_STREQ(str_native_addr, "cend$3"); +} + +TEST_F(LibcBuiltinTest, strtoul) +{ + char str[20] = "20"; + char buffer[20] = "0x31"; + char buffer1[20] = "10379cend$3"; + char *ptr; + + AppData src_app{ dummy_exec_env.get(), str }; + AppData buffer_app{ dummy_exec_env.get(), buffer }; + AppData buffer1_app{ dummy_exec_env.get(), buffer1 }; + AppMemory ptr_app{ dummy_exec_env.get(), 20 }; + + CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 10); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), &ptr, 10); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 2), + 0); + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 8), + 0); + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 10), + 0); + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 16), + 0); + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), NULL, 32), + 0); + + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 2), + 0); + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 8), + 16); + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 10), + 20); + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 16), + 32); + EXPECT_EQ(CALL_FUNC(strtoul, (char *)src_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 32), + 64); + + EXPECT_EQ(CALL_FUNC(strtoul, (char *)buffer_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 0), + 49); + EXPECT_EQ(CALL_FUNC(strtoul, (char *)buffer_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 16), + 49); + + EXPECT_EQ(CALL_FUNC(strtoul, (char *)buffer_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 10), + 0); + + EXPECT_EQ(CALL_FUNC(strtoul, (char *)buffer1_app.get_native_addr(), + (char **)ptr_app.get_native_addr(), 10), + 10379); + + uint32_t str_app_addr = *(uint32_t *)ptr_app.get_native_addr(); + EXPECT_GT(str_app_addr, 0); + char *str_native_addr = (char *)dummy_exec_env.app_to_native(str_app_addr); + EXPECT_NE(str_native_addr, nullptr); + EXPECT_STREQ(str_native_addr, "cend$3"); +} + +TEST_F(LibcBuiltinTest, memchr) +{ + const char src[] = "Hello World."; + char ch = 'o'; + + AppData src_app{ dummy_exec_env.get(), src }; + + /* exception */ + EXPECT_EQ(CALL_FUNC(memchr, (char *)-1, ch, strlen(src)), 0); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: out of bounds memory access"); + dummy_exec_env.clear_exception(); + + EXPECT_GE(CALL_FUNC(memchr, src_app.get_native_addr(), ch, strlen(src)), 0); +} + +TEST_F(LibcBuiltinTest, strncasecmp) +{ + const char *src1 = "Hello World."; + const char *src2 = "hel"; + const char *src3 = "HELLO WORLD."; + + AppData src1_app{ dummy_exec_env.get(), src1 }; + AppData src2_app{ dummy_exec_env.get(), src2 }; + AppData src3_app{ dummy_exec_env.get(), src3 }; + + EXPECT_GT(CALL_FUNC(strncasecmp, (char *)src1_app.get_native_addr(), + (char *)src2_app.get_native_addr(), 4), + 0); + + EXPECT_LT(CALL_FUNC(strncasecmp, (char *)src2_app.get_native_addr(), + (char *)src1_app.get_native_addr(), 4), + 0); + + EXPECT_EQ(CALL_FUNC(strncasecmp, (char *)src1_app.get_native_addr(), + (char *)src3_app.get_native_addr(), strlen(src1)), + 0); +} + +TEST_F(LibcBuiltinTest, strspn) +{ + const char *src1 = "Hello world!"; + const char *src2 = "abcd"; + const char *src3 = "l"; + const char *src4 = "Hell"; + const char *src5 = "Helo"; + + AppData src1_app{ dummy_exec_env.get(), src1 }; + AppData src2_app{ dummy_exec_env.get(), src2 }; + AppData src3_app{ dummy_exec_env.get(), src3 }; + AppData src4_app{ dummy_exec_env.get(), src4 }; + AppData src5_app{ dummy_exec_env.get(), src5 }; + + EXPECT_EQ(CALL_FUNC(strspn, (char *)src1_app.get_native_addr(), + (char *)src2_app.get_native_addr()), + 0); + + EXPECT_EQ(CALL_FUNC(strspn, (char *)src1_app.get_native_addr(), + (char *)src3_app.get_native_addr()), + 0); + + EXPECT_EQ(CALL_FUNC(strspn, (char *)src1_app.get_native_addr(), + (char *)src4_app.get_native_addr()), + 4); + + EXPECT_EQ(CALL_FUNC(strspn, (char *)src1_app.get_native_addr(), + (char *)src5_app.get_native_addr()), + 5); +} + +TEST_F(LibcBuiltinTest, strcspn) +{ + const char *src1 = "Hello world!"; + const char *src2 = ".?"; + const char *src3 = "llo"; + const char *src4 = "http://www.baidu.com/"; + const char *src5 = "?.,:\"\'-!"; + + AppData src1_app{ dummy_exec_env.get(), src1 }; + AppData src2_app{ dummy_exec_env.get(), src2 }; + AppData src3_app{ dummy_exec_env.get(), src3 }; + AppData src4_app{ dummy_exec_env.get(), src4 }; + AppData src5_app{ dummy_exec_env.get(), src5 }; + + EXPECT_EQ(CALL_FUNC(strcspn, (char *)src1_app.get_native_addr(), + (char *)src2_app.get_native_addr()), + 12); + + EXPECT_EQ(CALL_FUNC(strcspn, (char *)src1_app.get_native_addr(), + (char *)src3_app.get_native_addr()), + 2); + + EXPECT_EQ(CALL_FUNC(strcspn, (char *)src4_app.get_native_addr(), + (char *)src5_app.get_native_addr()), + 4); +} + +TEST_F(LibcBuiltinTest, strstr) +{ + const char *src1 = "Hello world!"; + const char *src2 = "abcd"; + const char *src3 = "Hello"; + const char *src4 = "H"; + const char *src5 = "llo"; + + AppData src1_app{ dummy_exec_env.get(), src1 }; + AppData src2_app{ dummy_exec_env.get(), src2 }; + AppData src3_app{ dummy_exec_env.get(), src3 }; + AppData src4_app{ dummy_exec_env.get(), src4 }; + AppData src5_app{ dummy_exec_env.get(), src5 }; + + EXPECT_EQ(CALL_FUNC(strstr, (char *)src1_app.get_native_addr(), + (char *)src2_app.get_native_addr()), + 0); + + EXPECT_EQ(CALL_FUNC(strstr, (char *)src3_app.get_native_addr(), + (char *)src1_app.get_native_addr()), + 0); + + EXPECT_GT(CALL_FUNC(strstr, (char *)src1_app.get_native_addr(), + (char *)src4_app.get_native_addr()), + 0); + + EXPECT_GT(CALL_FUNC(strstr, (char *)src1_app.get_native_addr(), + (char *)src5_app.get_native_addr()), + 0); +} + +TEST_F(LibcBuiltinTest, isupper) +{ + EXPECT_FALSE(CALL_FUNC(isupper, 'a')); + + EXPECT_FALSE(CALL_FUNC(isupper, 97)); + + EXPECT_FALSE(CALL_FUNC(isupper, '0')); + + EXPECT_FALSE(CALL_FUNC(isupper, '.')); + + EXPECT_TRUE(CALL_FUNC(isupper, 'A')); + + EXPECT_TRUE(CALL_FUNC(isupper, 65)); +} + +TEST_F(LibcBuiltinTest, isalpha) +{ + EXPECT_FALSE(CALL_FUNC(isalpha, '0')); + + EXPECT_FALSE(CALL_FUNC(isalpha, 0)); + + EXPECT_FALSE(CALL_FUNC(isalpha, '?')); + + EXPECT_TRUE(CALL_FUNC(isalpha, 'A')); + + EXPECT_TRUE(CALL_FUNC(isalpha, 'a')); +} + +TEST_F(LibcBuiltinTest, isspace) +{ + EXPECT_FALSE(CALL_FUNC(isspace, '0')); + + EXPECT_FALSE(CALL_FUNC(isspace, 0)); + + EXPECT_FALSE(CALL_FUNC(isspace, '?')); + + EXPECT_TRUE(CALL_FUNC(isspace, ' ')); + EXPECT_TRUE(CALL_FUNC(isspace, '\t')); + EXPECT_TRUE(CALL_FUNC(isspace, '\n')); + EXPECT_TRUE(CALL_FUNC(isspace, '\v')); + EXPECT_TRUE(CALL_FUNC(isspace, '\f')); + EXPECT_TRUE(CALL_FUNC(isspace, '\r')); +} + +TEST_F(LibcBuiltinTest, isgraph) +{ + /* ASCII 0x00-0x20 */ + EXPECT_FALSE(CALL_FUNC(isgraph, 0x00)); + EXPECT_FALSE(CALL_FUNC(isgraph, 0x20)); + + /* ASCII 0x7F */ + EXPECT_FALSE(CALL_FUNC(isgraph, 0x7F)); + EXPECT_FALSE(CALL_FUNC(isgraph, 0x80)); + + /* ASCII 0x21-0x7E */ + EXPECT_TRUE(CALL_FUNC(isgraph, 0x21)); + EXPECT_TRUE(CALL_FUNC(isgraph, 0x7E)); +} + +TEST_F(LibcBuiltinTest, isprint) +{ + /* ASCII 0x00-0x1F */ + EXPECT_FALSE(CALL_FUNC(isprint, 0x00)); + EXPECT_FALSE(CALL_FUNC(isprint, 0x1F)); + + /* ASCII 0x7F */ + EXPECT_FALSE(CALL_FUNC(isprint, 0x7F)); + EXPECT_FALSE(CALL_FUNC(isprint, 0x80)); + + /* ASCII 0x20-0x7E */ + EXPECT_TRUE(CALL_FUNC(isprint, 0x20)); + EXPECT_TRUE(CALL_FUNC(isprint, 0x7E)); +} + +TEST_F(LibcBuiltinTest, isdigit) +{ + /* ASCII 0x00-0x2F */ + EXPECT_FALSE(CALL_FUNC(isdigit, 0x00)); + EXPECT_FALSE(CALL_FUNC(isdigit, 0x2F)); + + /* ASCII 0x3A-0x7F */ + EXPECT_FALSE(CALL_FUNC(isdigit, 0x3A)); + EXPECT_FALSE(CALL_FUNC(isdigit, 0x7F)); + + /* ASCII 0x30-0x39 */ + EXPECT_TRUE(CALL_FUNC(isdigit, 0x30)); + EXPECT_TRUE(CALL_FUNC(isdigit, 0x39)); +} + +TEST_F(LibcBuiltinTest, isxdigit) +{ + char str[] = "-FFEE"; + char str1[] = "FFEE"; + + EXPECT_FALSE(CALL_FUNC(isxdigit, str[0])); + EXPECT_TRUE(CALL_FUNC(isxdigit, str1[0])); + + /* ASCII 0x00-0x2F */ + EXPECT_FALSE(CALL_FUNC(isxdigit, 0x00)); + EXPECT_FALSE(CALL_FUNC(isxdigit, 0x2F)); + + /* ASCII 0x3A-0x40 */ + EXPECT_FALSE(CALL_FUNC(isxdigit, 0x3A)); + EXPECT_FALSE(CALL_FUNC(isxdigit, 0x40)); + + /* ASCII 0x49-0x60 */ + EXPECT_FALSE(CALL_FUNC(isxdigit, 0x49)); + EXPECT_FALSE(CALL_FUNC(isxdigit, 0x60)); + + /* ASCII 0x67-0x7F */ + EXPECT_FALSE(CALL_FUNC(isxdigit, 0x67)); + EXPECT_FALSE(CALL_FUNC(isxdigit, 0x7F)); + + /* ASCII 0x30-0x39 */ + EXPECT_TRUE(CALL_FUNC(isxdigit, 0x30)); + EXPECT_TRUE(CALL_FUNC(isxdigit, 0x39)); + + /* ASCII 0x41-0x46 */ + EXPECT_TRUE(CALL_FUNC(isxdigit, 0x41)); + EXPECT_TRUE(CALL_FUNC(isxdigit, 0x46)); + + /* ASCII 0x61-0x66 */ + EXPECT_TRUE(CALL_FUNC(isxdigit, 0x61)); + EXPECT_TRUE(CALL_FUNC(isxdigit, 0x66)); +} + +TEST_F(LibcBuiltinTest, tolower) +{ + char src[] = "aBcDeFgH12345;!#$"; + char dest[sizeof(src)]; + int i; + + for (i = 0; i < sizeof(src); i++) { + dest[i] = CALL_FUNC(tolower, (src[i])); + } + EXPECT_STREQ(dest, "abcdefgh12345;!#$"); +} + +TEST_F(LibcBuiltinTest, toupper) +{ + char src[] = "aBcDeFgH12345;!#$"; + char dest[sizeof(src)]; + int i; + + for (i = 0; i < sizeof(src); i++) { + dest[i] = CALL_FUNC(toupper, (src[i])); + } + EXPECT_STREQ(dest, "ABCDEFGH12345;!#$"); +} + +TEST_F(LibcBuiltinTest, isalnum) +{ + char src[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678" + "9!\"#$%&'()*+,-./:;<=>?@[^_'{|}~"; + int i; + int isalnum_cnt = 0; + + for (i = 0; i < sizeof(src); i++) { + if (CALL_FUNC(isalnum, (src[i]))) + isalnum_cnt++; + } + EXPECT_EQ(isalnum_cnt, 62); +} + +TEST_F(LibcBuiltinTest, emscripten_memcpy_big) +{ + const char *src = "Hell World"; + char *dest; + + AppData src_app{ dummy_exec_env.get(), src }; + AppData dest_app{ dummy_exec_env.get(), dest }; + + /* exception */ + EXPECT_EQ(CALL_FUNC(emscripten_memcpy_big, (void *)-1, + src_app.get_native_addr(), 0), + 0); + + CALL_FUNC(emscripten_memcpy_big, dest_app.get_native_addr(), + src_app.get_native_addr(), strlen(src)); + EXPECT_EQ(CALL_FUNC(memcmp, dest_app.get_native_addr(), + src_app.get_native_addr(), strlen(src)), + 0); +} + +TEST_F(LibcBuiltinTest, abort) +{ + CALL_FUNC(abort, 33); + EXPECT_STREQ(dummy_exec_env.get_exception(), "Exception: env.abort(33)"); + dummy_exec_env.clear_exception(); +} + +TEST_F(LibcBuiltinTest, abortStackOverflow) +{ + CALL_FUNC(abortStackOverflow, 33); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: env.abortStackOverflow(33)"); + dummy_exec_env.clear_exception(); +} + +TEST_F(LibcBuiltinTest, nullFunc_X) +{ + CALL_FUNC(nullFunc_X, 33); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: env.nullFunc_X(33)"); + dummy_exec_env.clear_exception(); +} + +TEST_F(LibcBuiltinTest, __cxa_allocate_exception) +{ + EXPECT_NE(CALL_FUNC(__cxa_allocate_exception, 0x0), 0x0); + EXPECT_EQ(CALL_FUNC(__cxa_allocate_exception, 0xFFFF), 0x0); +} + +TEST_F(LibcBuiltinTest, __cxa_begin_catch) +{ + /* 无函数原型 */ +} + +TEST_F(LibcBuiltinTest, __cxa_throw) +{ + void *excepton; + void *tinfo; + + CALL_FUNC(__cxa_throw, excepton, tinfo, 1); + EXPECT_STREQ(dummy_exec_env.get_exception(), + "Exception: exception thrown by stdc++"); + dummy_exec_env.clear_exception(); +} + +struct timespec_app app; +TEST_F(LibcBuiltinTest, clock_gettime) +{ + struct timespec_app *tsapp; + tsapp = &app; + + AppMemory tsapp_app{ dummy_exec_env.get(), sizeof(struct timespec_app) }; + + /* exception */ + EXPECT_EQ(CALL_FUNC(clock_gettime, 0, (struct timespec_app *)-1), -1); + + EXPECT_EQ(CALL_FUNC(clock_gettime, 100, NULL), -1); + + EXPECT_EQ(CALL_FUNC(clock_gettime, 100, 0), -1); + + EXPECT_EQ(CALL_FUNC(clock_gettime, 10, + (struct timespec_app *)tsapp_app.get_native_addr()), + 0); +} + +TEST_F(LibcBuiltinTest, clock) +{ + EXPECT_GE(CALL_FUNC(clock), 0); +} + +WASMGlobalImport glb; +TEST_F(LibcBuiltinTest, wasm_native_lookup_libc_builtin_global) +{ + const char *module_name = "module name"; + const char *global_name = "global name"; + + const char *module_name1 = "global"; + const char *global_name1 = "NaN"; + const char *global_name2 = "Infinity"; + WASMGlobalImport *global = &glb; + + EXPECT_FALSE( + wasm_native_lookup_libc_builtin_global(NULL, global_name, global)); + EXPECT_FALSE( + wasm_native_lookup_libc_builtin_global(module_name, NULL, global)); + EXPECT_FALSE( + wasm_native_lookup_libc_builtin_global(module_name, global_name, NULL)); + EXPECT_FALSE(wasm_native_lookup_libc_builtin_global(module_name, + global_name, global)); + EXPECT_FALSE(wasm_native_lookup_libc_builtin_global(module_name, + global_name1, global)); + + EXPECT_TRUE(wasm_native_lookup_libc_builtin_global(module_name1, + global_name1, global)); + + EXPECT_TRUE(wasm_native_lookup_libc_builtin_global(module_name1, + global_name2, global)); +} diff --git a/tests/unit/linear-memory-aot/CMakeLists.txt b/tests/unit/linear-memory-aot/CMakeLists.txt new file mode 100644 index 0000000000..549b70ad6c --- /dev/null +++ b/tests/unit/linear-memory-aot/CMakeLists.txt @@ -0,0 +1,78 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-linear-memory-aot) + +add_definitions (-DRUN_ON_LINUX) + +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 0) +set (WAMR_BUILD_MEMORY_PROFILING 1) +set (WAMR_BUILD_INTERP 0) +set (WAMR_BUILD_AOT 1) + +include (../unit_common.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} + ${UNCOMMON_SHARED_SOURCE} + ${SRC_LIST} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${LIB_HOST_AGENT_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ${LIBC_BUILTIN_SOURCE} + ${IWASM_COMMON_SOURCE} + ${IWASM_INTERP_SOURCE} + ${IWASM_AOT_SOURCE} + ${IWASM_COMPL_SOURCE} + ${WASM_APP_LIB_SOURCE_ALL} +) + +# Test case: .aot file with hardware bound check. +add_executable (linear_memory_test_aot ${unit_test_sources}) +target_link_libraries (linear_memory_test_aot gtest_main) +gtest_discover_tests(linear_memory_test_aot) +target_compile_definitions(linear_memory_test_aot PRIVATE WAMR_DISABLE_HW_BOUND_CHECK=0) + +# Ensure that aot compiled is completed before linear_memory_test_aot is built +set(dummy_output "${CMAKE_CURRENT_BINARY_DIR}/dummy_output") + +add_custom_command(OUTPUT ${dummy_output} + COMMAND ./build_aot.sh + COMMAND ${CMAKE_COMMAND} -E touch ${dummy_output} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/build_aot.sh + COMMENT "Executing script to compile aot files" + VERBATIM +) + +add_custom_target( + RunBuildAot ALL + DEPENDS ${dummy_output} +) + +add_dependencies(linear_memory_test_aot RunBuildAot) + +add_custom_command(TARGET linear_memory_test_aot POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/build/*.aot + ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copy aot files to the directory: build/linear-memory-aot." +) + +# Test case: .aot file with no hardware bound check. +add_executable (linear_memory_test_aot_no_hw_bound ${unit_test_sources}) +target_link_libraries (linear_memory_test_aot_no_hw_bound gtest_main) +gtest_discover_tests(linear_memory_test_aot_no_hw_bound) +target_compile_definitions(linear_memory_test_aot_no_hw_bound PRIVATE WAMR_DISABLE_HW_BOUND_CHECK=1) diff --git a/tests/unit/linear-memory-aot/build_aot.sh b/tests/unit/linear-memory-aot/build_aot.sh new file mode 100755 index 0000000000..8f2b29edee --- /dev/null +++ b/tests/unit/linear-memory-aot/build_aot.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +# Define a list of .wasm files +file_names=("mem_grow_out_of_bounds_01" "mem_grow_out_of_bounds_02" + "mem_page_01" "mem_page_02" "mem_page_03" "mem_page_05" + "mem_page_07" "mem_page_08" "mem_page_09" "mem_page_10" + "mem_page_12" "mem_page_14" "mem_page_16" "mem_page_20" "out_of_bounds") + +WORKDIR="$PWD" +WAMRC_ROOT_DIR="${WORKDIR}/../../../wamr-compiler" +WAMRC="${WAMRC_ROOT_DIR}/build/wamrc" +WAST2WASM="/opt/wabt/bin/wat2wasm" + +# build wamrc if not exist +if [ ! -s "$WAMRC" ]; then + cd $WAMRC_ROOT_DIR + if [ -d "$WAMRC/build" ]; then + rm -r build + fi + cmake -B build && cmake --build build -j $(nproc) + cd $WORKDIR +fi + +# error if not exist +if [ ! -s "$WAST2WASM" ]; then + echo "please install wabt first" && exit -1 +fi + +# Iterate over the files array +rm -r build +mkdir build +for file_name in "${file_names[@]}"; do + # wast to wasm + $WAST2WASM "${file_name}.wast" -o "build/${file_name}.wasm" + # compile the aot files, x86-64, x86-32, no_hw_bounds, no_hw_bounds_x32 + $WAMRC -o "build/${file_name}.aot" "build/${file_name}.wasm" + $WAMRC --target=i386 -o "build/${file_name}_32.aot" "build/${file_name}.wasm" + $WAMRC --bounds-checks=1 -o "build/${file_name}_no_hw_bounds.aot" "build/${file_name}.wasm" + $WAMRC --bounds-checks=1 --target=i386 -o "build/${file_name}_no_hw_bounds_32.aot" "build/${file_name}.wasm" +done diff --git a/tests/unit/linear-memory-aot/linear_memory_aot_test.cc b/tests/unit/linear-memory-aot/linear_memory_aot_test.cc new file mode 100644 index 0000000000..dafdbb7917 --- /dev/null +++ b/tests/unit/linear-memory-aot/linear_memory_aot_test.cc @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_read_file.h" +#include "wasm_runtime_common.h" + +static std::string CWD; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +#if WASM_DISABLE_HW_BOUND_CHECK != 0 +#define TEST_SUITE_NAME linear_memory_test_suite_aot_no_hw_bound +#else +#define TEST_SUITE_NAME linear_memory_test_suite_aot +#endif + +class TEST_SUITE_NAME : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() { CWD = get_binary_path(); } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +struct ret_env { + wasm_exec_env_t exec_env; + wasm_module_t aot_module; + wasm_module_inst_t aot_module_inst; + unsigned char *aot_file_buf; + char error_buf[128]; +}; + +struct ret_env +load_aot(char *aot_file_tested, unsigned int app_heap_size) +{ + std::string aot_mem_page = aot_file_tested; + const char *aot_file = strdup((CWD + aot_mem_page).c_str()); + wasm_module_inst_t aot_module_inst = nullptr; + wasm_module_t aot_module = nullptr; + wasm_exec_env_t exec_env = nullptr; + unsigned char *aot_file_buf = nullptr; + unsigned int aot_file_size = 0; + unsigned int stack_size = 16 * 1024, heap_size = app_heap_size; + char error_buf[128] = { 0 }; + struct ret_env ret_module_env; + + memset(ret_module_env.error_buf, 0, 128); + aot_file_buf = + (unsigned char *)bh_read_file_to_buffer(aot_file, &aot_file_size); + if (!aot_file_buf) { + goto fail; + } + + aot_module = wasm_runtime_load(aot_file_buf, aot_file_size, error_buf, + sizeof(error_buf)); + if (!aot_module) { + memcpy(ret_module_env.error_buf, error_buf, 128); + goto fail; + } + + aot_module_inst = wasm_runtime_instantiate( + aot_module, stack_size, heap_size, error_buf, sizeof(error_buf)); + if (!aot_module_inst) { + memcpy(ret_module_env.error_buf, error_buf, 128); + goto fail; + } + + exec_env = wasm_runtime_create_exec_env(aot_module_inst, stack_size); + +fail: + ret_module_env.exec_env = exec_env; + ret_module_env.aot_module = aot_module; + ret_module_env.aot_module_inst = aot_module_inst; + ret_module_env.aot_file_buf = aot_file_buf; + + return ret_module_env; +} + +void +destroy_module_env(struct ret_env module_env) +{ + if (module_env.exec_env) { + wasm_runtime_destroy_exec_env(module_env.exec_env); + } + + if (module_env.aot_module_inst) { + wasm_runtime_deinstantiate(module_env.aot_module_inst); + } + + if (module_env.aot_module) { + wasm_runtime_unload(module_env.aot_module); + } + + if (module_env.aot_file_buf) { + wasm_runtime_free(module_env.aot_file_buf); + } +} + +TEST_F(TEST_SUITE_NAME, test_aot_mem_page_count) +{ + struct ret_env tmp_module_env; + const unsigned int num_normal_aot = 9; + const unsigned int num_error_aot = 2; + +#if UINTPTR_MAX == UINT64_MAX + const char *aot_file_normal[num_normal_aot] = { + "/mem_page_01.aot", "/mem_page_02.aot", "/mem_page_05.aot", + "/mem_page_07.aot", "/mem_page_08.aot", "/mem_page_09.aot", + "/mem_page_10.aot", "/mem_page_12.aot", "/mem_page_14.aot" + }; + + const char *aot_file_error[num_error_aot] = { "/mem_page_03.aot", + "/mem_page_16.aot" }; +#else + const char *aot_file_normal[num_normal_aot] = { + "/mem_page_01_32.aot", "/mem_page_02_32.aot", "/mem_page_05_32.aot", + "/mem_page_07_32.aot", "/mem_page_08_32.aot", "/mem_page_09_32.aot", + "/mem_page_10_32.aot", "/mem_page_12_32.aot", "/mem_page_14_32.aot" + }; + + const char *aot_file_error[num_error_aot] = { "/mem_page_03_32.aot", + "/mem_page_16_32.aot" }; +#endif + + // Test normal wasm file. + for (int i = 0; i < num_normal_aot; i++) { +#if UINTPTR_MAX != UINT64_MAX + // 32 bit do not load this wasm. + if ((0 == strcmp("/mem_page_14_32.aot", aot_file_normal[i]))) { + continue; + } +#endif + + tmp_module_env = load_aot((char *)aot_file_normal[i], 16 * 1024); + EXPECT_NE(nullptr, tmp_module_env.aot_module); + EXPECT_NE(nullptr, tmp_module_env.aot_file_buf); + + destroy_module_env(tmp_module_env); + } + + // Test error wasm file. + for (int i = 0; i < num_error_aot; i++) { + tmp_module_env = load_aot((char *)aot_file_error[i], 16 * 1024); + if (0 != strlen(tmp_module_env.error_buf)) { + /* 3 and 16 are for legit for loader, the init and max page count + * can be 65536, but they can't allocate any host managed heap, so + * instantiating errors */ + EXPECT_EQ(0, strncmp("AOT module instantiate failed", + (const char *)tmp_module_env.error_buf, 29)); + printf("%s\n", tmp_module_env.error_buf); + } + + destroy_module_env(tmp_module_env); + } +} + +TEST_F(TEST_SUITE_NAME, test_aot_about_app_heap) +{ + struct ret_env tmp_module_env; + + // Test case: init_page_count = 65536, app heap size = 1. +#if UINTPTR_MAX == UINT64_MAX + tmp_module_env = load_aot((char *)"/mem_page_03.aot", 1); +#else + tmp_module_env = load_aot((char *)"/mem_page_03_32.aot", 1); +#endif + EXPECT_EQ( + 0, strncmp("AOT module", (const char *)tmp_module_env.error_buf, 10)); + destroy_module_env(tmp_module_env); + + // Test case: init_page_count = 65535, app heap size = 65537. +#if UINTPTR_MAX == UINT64_MAX + tmp_module_env = load_aot((char *)"/mem_page_20.aot", 65537); +#else + tmp_module_env = load_aot((char *)"/mem_page_20_32.aot", 65537); +#endif + EXPECT_EQ( + 0, strncmp("AOT module", (const char *)tmp_module_env.error_buf, 10)); + destroy_module_env(tmp_module_env); +} + +TEST_F(TEST_SUITE_NAME, test_throw_exception_out_of_bounds) +{ + struct ret_env tmp_module_env; + WASMFunctionInstanceCommon *func = nullptr; + bool ret = false; + uint32 argv[1] = { 9999 * 64 * 1024 }; + const char *exception = nullptr; + + /* TODO: use no_hw_bounds version when disable */ +#if UINTPTR_MAX == UINT64_MAX + tmp_module_env = load_aot((char *)"/out_of_bounds.aot", 16 * 1024); +#else + tmp_module_env = load_aot((char *)"/out_of_bounds_32.aot", 16 * 1024); +#endif + func = wasm_runtime_lookup_function(tmp_module_env.aot_module_inst, "load"); + if (!func) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + ret = wasm_runtime_call_wasm(tmp_module_env.exec_env, func, 1, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + } + + exception = wasm_runtime_get_exception(tmp_module_env.aot_module_inst); + EXPECT_EQ(0, + strncmp("Exception: out of bounds memory access", exception, 38)); + +failed_out_of_bounds: + destroy_module_env(tmp_module_env); +} + +TEST_F(TEST_SUITE_NAME, test_mem_grow_out_of_bounds) +{ + struct ret_env tmp_module_env; + WASMFunctionInstanceCommon *func_mem_grow = nullptr; + WASMFunctionInstanceCommon *func_mem_size = nullptr; + bool ret = false; + uint32 argv[1] = { 65535 }; + const char *exception = nullptr; + + /* TODO: use no_hw_bounds version when disable */ + // Test case: module((memory 2)), memory.grow 65535, then memory.size. +#if UINTPTR_MAX == UINT64_MAX + tmp_module_env = load_aot((char *)"/mem_grow_out_of_bounds_01.aot", 0); +#else + tmp_module_env = load_aot((char *)"/mem_grow_out_of_bounds_01_32.aot", 0); +#endif + + func_mem_grow = wasm_runtime_lookup_function(tmp_module_env.aot_module_inst, + "mem_grow"); + if (!func_mem_grow) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + func_mem_size = wasm_runtime_lookup_function(tmp_module_env.aot_module_inst, + "mem_size"); + if (!func_mem_size) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_grow, 1, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + + EXPECT_EQ(-1, argv[0]); + + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_size, 0, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + + EXPECT_EQ(2, argv[0]); + + // Test case: wasm_runtime_instantiate(heap_size=32768), memory.grow 65534, + // memory.grow 1. + destroy_module_env(tmp_module_env); + +#if UINTPTR_MAX == UINT64_MAX + tmp_module_env = load_aot((char *)"/mem_grow_out_of_bounds_02.aot", 32768); +#else + tmp_module_env = + load_aot((char *)"/mem_grow_out_of_bounds_02_32.aot", 32768); +#endif + + func_mem_grow = wasm_runtime_lookup_function(tmp_module_env.aot_module_inst, + "mem_grow"); + if (!func_mem_grow) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + func_mem_size = wasm_runtime_lookup_function(tmp_module_env.aot_module_inst, + "mem_size"); + if (!func_mem_size) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_size, 0, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + EXPECT_EQ(2, argv[0]); + + argv[0] = 65534; + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_grow, 1, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + +#if UINTPTR_MAX == UINT64_MAX + EXPECT_EQ(2, argv[0]); +#else + EXPECT_EQ(-1, argv[0]); +#endif + + argv[0] = 1; + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_grow, 1, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + +#if UINTPTR_MAX == UINT64_MAX + EXPECT_EQ(-1, argv[0]); +#else + EXPECT_EQ(2, argv[0]); +#endif + +failed_out_of_bounds: + destroy_module_env(tmp_module_env); +} diff --git a/tests/unit/linear-memory-aot/mem_grow_out_of_bounds_01.wast b/tests/unit/linear-memory-aot/mem_grow_out_of_bounds_01.wast new file mode 100644 index 0000000000..296455d86d --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_grow_out_of_bounds_01.wast @@ -0,0 +1,16 @@ +(module + (type $0 (func (result i32))) + (type $1 (func (param i32) (result i32))) + (memory 2) + (export "mem_grow" (func $6)) + (export "mem_size" (func $7)) + + (func $6 (type $1) (param $0 i32) (result i32) + local.get $0 + memory.grow + ) + + (func $7 (type $0) (result i32) + memory.size + ) +) diff --git a/tests/unit/linear-memory-aot/mem_grow_out_of_bounds_02.wast b/tests/unit/linear-memory-aot/mem_grow_out_of_bounds_02.wast new file mode 100644 index 0000000000..7faceae496 --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_grow_out_of_bounds_02.wast @@ -0,0 +1,16 @@ +(module + (type $0 (func (result i32))) + (type $1 (func (param i32) (result i32))) + (memory 1) + (export "mem_grow" (func $6)) + (export "mem_size" (func $7)) + + (func $6 (type $1) (param $0 i32) (result i32) + local.get $0 + memory.grow + ) + + (func $7 (type $0) (result i32) + memory.size + ) +) diff --git a/tests/unit/linear-memory-aot/mem_page_01.wast b/tests/unit/linear-memory-aot/mem_page_01.wast new file mode 100644 index 0000000000..aa3aeed76f --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_01.wast @@ -0,0 +1 @@ +(module (memory 0)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_02.wast b/tests/unit/linear-memory-aot/mem_page_02.wast new file mode 100644 index 0000000000..eb1fba88ec --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_02.wast @@ -0,0 +1 @@ +(module (memory 1)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_03.wast b/tests/unit/linear-memory-aot/mem_page_03.wast new file mode 100644 index 0000000000..f3e09dcf42 --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_03.wast @@ -0,0 +1 @@ +(module (memory 65536)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_05.wast b/tests/unit/linear-memory-aot/mem_page_05.wast new file mode 100644 index 0000000000..7551af5145 --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_05.wast @@ -0,0 +1 @@ +(module (memory 0 0)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_07.wast b/tests/unit/linear-memory-aot/mem_page_07.wast new file mode 100644 index 0000000000..709e6ca050 --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_07.wast @@ -0,0 +1 @@ +(module (memory 1 1)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_08.wast b/tests/unit/linear-memory-aot/mem_page_08.wast new file mode 100644 index 0000000000..abf0818026 --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_08.wast @@ -0,0 +1 @@ +(module (memory 0 1)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_09.wast b/tests/unit/linear-memory-aot/mem_page_09.wast new file mode 100644 index 0000000000..47b38fde53 --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_09.wast @@ -0,0 +1 @@ +(module (memory 1 256)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_10.wast b/tests/unit/linear-memory-aot/mem_page_10.wast new file mode 100644 index 0000000000..523f9e6744 --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_10.wast @@ -0,0 +1 @@ +(module (memory 0 65535)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_12.wast b/tests/unit/linear-memory-aot/mem_page_12.wast new file mode 100644 index 0000000000..d82dabb59f --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_12.wast @@ -0,0 +1 @@ +(module (memory 0 65536)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_14.wast b/tests/unit/linear-memory-aot/mem_page_14.wast new file mode 100644 index 0000000000..9779bf2343 --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_14.wast @@ -0,0 +1 @@ +(module (memory 65535 65536)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_16.wast b/tests/unit/linear-memory-aot/mem_page_16.wast new file mode 100644 index 0000000000..94068a4e9a --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_16.wast @@ -0,0 +1 @@ +(module (memory 65536 65536)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/mem_page_20.wast b/tests/unit/linear-memory-aot/mem_page_20.wast new file mode 100644 index 0000000000..0d4b6ebd6e --- /dev/null +++ b/tests/unit/linear-memory-aot/mem_page_20.wast @@ -0,0 +1 @@ +(module (memory 65535)) \ No newline at end of file diff --git a/tests/unit/linear-memory-aot/out_of_bounds.wast b/tests/unit/linear-memory-aot/out_of_bounds.wast new file mode 100644 index 0000000000..89854b924d --- /dev/null +++ b/tests/unit/linear-memory-aot/out_of_bounds.wast @@ -0,0 +1,10 @@ +(module + (type $1 (func (param i32) (result i32))) + (memory $3 0) + (export "load" (func $4)) + + (func $4 (type $1) (param $0 i32) (result i32) + local.get $0 + i32.load + ) +) diff --git a/tests/unit/linear-memory-aot/readme b/tests/unit/linear-memory-aot/readme new file mode 100644 index 0000000000..a9ec33833f --- /dev/null +++ b/tests/unit/linear-memory-aot/readme @@ -0,0 +1,2 @@ +build 64 bit target: cmake .. +build 32 bit target: cmake .. -DWAMR_BUILD_TARGET=X86_32 \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/CMakeLists.txt b/tests/unit/linear-memory-wasm/CMakeLists.txt new file mode 100644 index 0000000000..03e1616d74 --- /dev/null +++ b/tests/unit/linear-memory-wasm/CMakeLists.txt @@ -0,0 +1,59 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-linear-memory-wasm) + +add_definitions (-DRUN_ON_LINUX) + +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 0) +set (WAMR_BUILD_MEMORY_PROFILING 1) +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_AOT 0) + +include (../unit_common.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} + ${UNCOMMON_SHARED_SOURCE} + ${SRC_LIST} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${LIB_HOST_AGENT_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ${LIBC_BUILTIN_SOURCE} + ${IWASM_COMMON_SOURCE} + ${IWASM_INTERP_SOURCE} + ${IWASM_AOT_SOURCE} + ${IWASM_COMPL_SOURCE} + ${WASM_APP_LIB_SOURCE_ALL} +) + +# Test case: .wasm file with hardware bound check. +add_executable (linear_memory_test_wasm ${unit_test_sources}) +target_link_libraries (linear_memory_test_wasm gtest_main) +gtest_discover_tests(linear_memory_test_wasm) +target_compile_definitions(linear_memory_test_wasm PRIVATE WAMR_DISABLE_HW_BOUND_CHECK=0) + +add_custom_command(TARGET linear_memory_test_wasm POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_LIST_DIR}/wasm_files/* + ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copy wasm files to the directory: build/linear-memory-wasm." +) + +# Test case: .wasm file with no hardware bound check. +add_executable (linear_memory_test_wasm_no_hw_bound ${unit_test_sources}) +target_link_libraries (linear_memory_test_wasm_no_hw_bound gtest_main) +gtest_discover_tests(linear_memory_test_wasm_no_hw_bound) +target_compile_definitions(linear_memory_test_wasm_no_hw_bound PRIVATE WAMR_DISABLE_HW_BOUND_CHECK=1) diff --git a/tests/unit/linear-memory-wasm/linear_memory_wasm_test.cc b/tests/unit/linear-memory-wasm/linear_memory_wasm_test.cc new file mode 100644 index 0000000000..77eb53d7ea --- /dev/null +++ b/tests/unit/linear-memory-wasm/linear_memory_wasm_test.cc @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_read_file.h" +#include "wasm_runtime_common.h" + +static std::string CWD; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +#if WASM_DISABLE_HW_BOUND_CHECK != 0 +#define TEST_SUITE_NAME linear_memory_test_suite_wasm_no_hw_bound +#else +#define TEST_SUITE_NAME linear_memory_test_suite_wasm +#endif + +class TEST_SUITE_NAME : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() { CWD = get_binary_path(); } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +struct ret_env { + wasm_exec_env_t exec_env; + wasm_module_t wasm_module; + wasm_module_inst_t wasm_module_inst; + unsigned char *wasm_file_buf; + char error_buf[128]; +}; + +struct ret_env +load_wasm(char *wasm_file_tested, unsigned int app_heap_size) +{ + std::string wasm_mem_page = wasm_file_tested; + const char *wasm_file = strdup((CWD + wasm_mem_page).c_str()); + wasm_module_inst_t wasm_module_inst = nullptr; + wasm_module_t wasm_module = nullptr; + wasm_exec_env_t exec_env = nullptr; + unsigned char *wasm_file_buf = nullptr; + unsigned int wasm_file_size = 0; + unsigned int stack_size = 16 * 1024, heap_size = app_heap_size; + char error_buf[128] = { 0 }; + struct ret_env ret_module_env; + + memset(ret_module_env.error_buf, 0, 128); + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + if (!wasm_file_buf) { + goto fail; + } + + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + if (!wasm_module) { + memcpy(ret_module_env.error_buf, error_buf, 128); + goto fail; + } + + wasm_module_inst = wasm_runtime_instantiate( + wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf)); + if (!wasm_module_inst) { + memcpy(ret_module_env.error_buf, error_buf, 128); + goto fail; + } + + exec_env = wasm_runtime_create_exec_env(wasm_module_inst, stack_size); + +fail: + ret_module_env.exec_env = exec_env; + ret_module_env.wasm_module = wasm_module; + ret_module_env.wasm_module_inst = wasm_module_inst; + ret_module_env.wasm_file_buf = wasm_file_buf; + + return ret_module_env; +} + +void +destroy_module_env(struct ret_env module_env) +{ + if (module_env.exec_env) { + wasm_runtime_destroy_exec_env(module_env.exec_env); + } + + if (module_env.wasm_module_inst) { + wasm_runtime_deinstantiate(module_env.wasm_module_inst); + } + + if (module_env.wasm_module) { + wasm_runtime_unload(module_env.wasm_module); + } + + if (module_env.wasm_file_buf) { + wasm_runtime_free(module_env.wasm_file_buf); + } +} + +TEST_F(TEST_SUITE_NAME, test_wasm_mem_page_count) +{ + struct ret_env tmp_module_env; + unsigned int num_normal_wasm = 9; + unsigned int num_error_wasm = 10; + const char *wasm_file_normal[num_normal_wasm] = { + "/wasm_mem_page_01.wasm", "/wasm_mem_page_02.wasm", + "/wasm_mem_page_05.wasm", "/wasm_mem_page_07.wasm", + "/wasm_mem_page_08.wasm", "/wasm_mem_page_09.wasm", + "/wasm_mem_page_10.wasm", "/wasm_mem_page_12.wasm", + "/wasm_mem_page_14.wasm" + }; + + const char *wasm_file_error[num_error_wasm] = { + "/wasm_mem_page_03.wasm", "/wasm_mem_page_04.wasm", + "/wasm_mem_page_06.wasm", "/wasm_mem_page_11.wasm", + "/wasm_mem_page_13.wasm", "/wasm_mem_page_15.wasm", + "/wasm_mem_page_16.wasm", "/wasm_mem_page_17.wasm", + "/wasm_mem_page_18.wasm", "/wasm_mem_page_19.wasm" + }; + + // Test normal wasm file. + for (int i = 0; i < num_normal_wasm; i++) { +#if UINTPTR_MAX != UINT64_MAX + // 32 bit do not load this wasm. + if ((0 == strcmp("/wasm_mem_page_12.wasm", wasm_file_normal[i])) + || (0 == strcmp("/wasm_mem_page_14.wasm", wasm_file_normal[i]))) { + continue; + } +#endif + tmp_module_env = load_wasm((char *)wasm_file_normal[i], 16 * 1024); + EXPECT_NE(nullptr, tmp_module_env.wasm_module); + EXPECT_NE(nullptr, tmp_module_env.wasm_file_buf); + +#if WASM_DISABLE_HW_BOUND_CHECK == 0 + EXPECT_NE(nullptr, tmp_module_env.exec_env); + EXPECT_NE(nullptr, tmp_module_env.wasm_module_inst); +#endif + destroy_module_env(tmp_module_env); + } + + // Test error wasm file. + for (int i = 0; i < num_error_wasm; i++) { + tmp_module_env = load_wasm((char *)wasm_file_error[i], 16 * 1024); + + if (0 != strlen(tmp_module_env.error_buf)) { + EXPECT_EQ(0, strncmp("WASM module", + (const char *)tmp_module_env.error_buf, 11)); + } + + destroy_module_env(tmp_module_env); + } +} + +TEST_F(TEST_SUITE_NAME, test_wasm_about_app_heap) +{ + struct ret_env tmp_module_env; + + // Test case: init_page_count = 65536, app heap size = 1. + tmp_module_env = load_wasm((char *)"/wasm_mem_page_03.wasm", 1); + EXPECT_EQ(0, strncmp("WASM module instantiate failed", + (const char *)tmp_module_env.error_buf, 30)); + destroy_module_env(tmp_module_env); + + // Test case: init_page_count = 65535, app heap size = 65537. + tmp_module_env = load_wasm((char *)"/wasm_mem_page_20.wasm", 65537); + EXPECT_EQ(0, strncmp("WASM module instantiate failed", + (const char *)tmp_module_env.error_buf, 30)); + destroy_module_env(tmp_module_env); +} + +TEST_F(TEST_SUITE_NAME, test_throw_exception_out_of_bounds) +{ + struct ret_env tmp_module_env; + WASMFunctionInstanceCommon *func = nullptr; + bool ret = false; + uint32 argv[1] = { 9999 * 64 * 1024 }; + const char *exception = nullptr; + + tmp_module_env = load_wasm((char *)"/out_of_bounds.wasm", 16 * 1024); + func = + wasm_runtime_lookup_function(tmp_module_env.wasm_module_inst, "load"); + if (!func) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + ret = wasm_runtime_call_wasm(tmp_module_env.exec_env, func, 1, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + } + + exception = wasm_runtime_get_exception(tmp_module_env.wasm_module_inst); + EXPECT_EQ(0, + strncmp("Exception: out of bounds memory access", exception, 38)); + +failed_out_of_bounds: + destroy_module_env(tmp_module_env); +} + +TEST_F(TEST_SUITE_NAME, test_mem_grow_out_of_bounds) +{ + struct ret_env tmp_module_env; + WASMFunctionInstanceCommon *func_mem_grow = nullptr; + WASMFunctionInstanceCommon *func_mem_size = nullptr; + bool ret = false; + // after refactor, the 65536 pages to one 4G page optimization is removed + // the size can be 65536 now, so use 2 + 65535 to test OOB + uint32 argv[1] = { 65535 }; + const char *exception = nullptr; + + // Test case: module((memory 2)), memory.grow 65535, then memory.size. + tmp_module_env = load_wasm((char *)"/mem_grow_out_of_bounds_01.wasm", 0); + func_mem_grow = wasm_runtime_lookup_function( + tmp_module_env.wasm_module_inst, "mem_grow"); + if (!func_mem_grow) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + func_mem_size = wasm_runtime_lookup_function( + tmp_module_env.wasm_module_inst, "mem_size"); + if (!func_mem_size) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_grow, 1, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + + EXPECT_EQ(-1, argv[0]); + + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_size, 0, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + + EXPECT_EQ(2, argv[0]); + + // Test case: wasm_runtime_instantiate(heap_size=32768), memory.grow 65535, + // memory.grow 1. + destroy_module_env(tmp_module_env); + tmp_module_env = + load_wasm((char *)"/mem_grow_out_of_bounds_02.wasm", 32768); + func_mem_grow = wasm_runtime_lookup_function( + tmp_module_env.wasm_module_inst, "mem_grow"); + if (!func_mem_grow) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + func_mem_size = wasm_runtime_lookup_function( + tmp_module_env.wasm_module_inst, "mem_size"); + if (!func_mem_size) { + printf("\nFailed to wasm_runtime_lookup_function!\n"); + goto failed_out_of_bounds; + } + + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_size, 0, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + EXPECT_EQ(2, argv[0]); + + argv[0] = 65535; + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_grow, 1, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + + EXPECT_NE(2, argv[0]); + + argv[0] = 1; + ret = + wasm_runtime_call_wasm(tmp_module_env.exec_env, func_mem_grow, 1, argv); + if (!ret) { + printf("\nFailed to wasm_runtime_call_wasm!\n"); + goto failed_out_of_bounds; + } + + EXPECT_EQ(2, argv[0]); + +failed_out_of_bounds: + destroy_module_env(tmp_module_env); +} diff --git a/tests/unit/linear-memory-wasm/mem_grow_out_of_bounds_01.wast b/tests/unit/linear-memory-wasm/mem_grow_out_of_bounds_01.wast new file mode 100644 index 0000000000..296455d86d --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_grow_out_of_bounds_01.wast @@ -0,0 +1,16 @@ +(module + (type $0 (func (result i32))) + (type $1 (func (param i32) (result i32))) + (memory 2) + (export "mem_grow" (func $6)) + (export "mem_size" (func $7)) + + (func $6 (type $1) (param $0 i32) (result i32) + local.get $0 + memory.grow + ) + + (func $7 (type $0) (result i32) + memory.size + ) +) diff --git a/tests/unit/linear-memory-wasm/mem_grow_out_of_bounds_02.wast b/tests/unit/linear-memory-wasm/mem_grow_out_of_bounds_02.wast new file mode 100644 index 0000000000..7faceae496 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_grow_out_of_bounds_02.wast @@ -0,0 +1,16 @@ +(module + (type $0 (func (result i32))) + (type $1 (func (param i32) (result i32))) + (memory 1) + (export "mem_grow" (func $6)) + (export "mem_size" (func $7)) + + (func $6 (type $1) (param $0 i32) (result i32) + local.get $0 + memory.grow + ) + + (func $7 (type $0) (result i32) + memory.size + ) +) diff --git a/tests/unit/linear-memory-wasm/mem_page_01.wast b/tests/unit/linear-memory-wasm/mem_page_01.wast new file mode 100644 index 0000000000..aa3aeed76f --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_01.wast @@ -0,0 +1 @@ +(module (memory 0)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_02.wast b/tests/unit/linear-memory-wasm/mem_page_02.wast new file mode 100644 index 0000000000..eb1fba88ec --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_02.wast @@ -0,0 +1 @@ +(module (memory 1)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_03.wast b/tests/unit/linear-memory-wasm/mem_page_03.wast new file mode 100644 index 0000000000..f3e09dcf42 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_03.wast @@ -0,0 +1 @@ +(module (memory 65536)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_04.wast b/tests/unit/linear-memory-wasm/mem_page_04.wast new file mode 100644 index 0000000000..b476caa2e7 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_04.wast @@ -0,0 +1 @@ +(module (memory 65537)) ;; Should report an error. \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_05.wast b/tests/unit/linear-memory-wasm/mem_page_05.wast new file mode 100644 index 0000000000..7551af5145 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_05.wast @@ -0,0 +1 @@ +(module (memory 0 0)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_06.wast b/tests/unit/linear-memory-wasm/mem_page_06.wast new file mode 100644 index 0000000000..eae97baa2c --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_06.wast @@ -0,0 +1 @@ +(module (memory 1 0)) ;; Should report an error. \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_07.wast b/tests/unit/linear-memory-wasm/mem_page_07.wast new file mode 100644 index 0000000000..709e6ca050 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_07.wast @@ -0,0 +1 @@ +(module (memory 1 1)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_08.wast b/tests/unit/linear-memory-wasm/mem_page_08.wast new file mode 100644 index 0000000000..abf0818026 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_08.wast @@ -0,0 +1 @@ +(module (memory 0 1)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_09.wast b/tests/unit/linear-memory-wasm/mem_page_09.wast new file mode 100644 index 0000000000..47b38fde53 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_09.wast @@ -0,0 +1 @@ +(module (memory 1 256)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_10.wast b/tests/unit/linear-memory-wasm/mem_page_10.wast new file mode 100644 index 0000000000..523f9e6744 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_10.wast @@ -0,0 +1 @@ +(module (memory 0 65535)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_11.wast b/tests/unit/linear-memory-wasm/mem_page_11.wast new file mode 100644 index 0000000000..1d9cf77cfd --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_11.wast @@ -0,0 +1 @@ +(module (memory 65535 0)) ;; Should report an error. \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_12.wast b/tests/unit/linear-memory-wasm/mem_page_12.wast new file mode 100644 index 0000000000..d82dabb59f --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_12.wast @@ -0,0 +1 @@ +(module (memory 0 65536)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_13.wast b/tests/unit/linear-memory-wasm/mem_page_13.wast new file mode 100644 index 0000000000..e3c1f1e219 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_13.wast @@ -0,0 +1 @@ +(module (memory 65536 0)) ;; Should report an error. diff --git a/tests/unit/linear-memory-wasm/mem_page_14.wast b/tests/unit/linear-memory-wasm/mem_page_14.wast new file mode 100644 index 0000000000..9779bf2343 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_14.wast @@ -0,0 +1 @@ +(module (memory 65535 65536)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_15.wast b/tests/unit/linear-memory-wasm/mem_page_15.wast new file mode 100644 index 0000000000..d2862b9bb7 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_15.wast @@ -0,0 +1 @@ +(module (memory 65536 65535)) ;; Should report an error. \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_16.wast b/tests/unit/linear-memory-wasm/mem_page_16.wast new file mode 100644 index 0000000000..94068a4e9a --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_16.wast @@ -0,0 +1 @@ +(module (memory 65536 65536)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_17.wast b/tests/unit/linear-memory-wasm/mem_page_17.wast new file mode 100644 index 0000000000..d5a19eff29 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_17.wast @@ -0,0 +1 @@ +(module (memory 65537 65537)) ;; Should report an error. \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_18.wast b/tests/unit/linear-memory-wasm/mem_page_18.wast new file mode 100644 index 0000000000..d5793de6a1 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_18.wast @@ -0,0 +1 @@ +(module (memory 65537 65535)) ;; Should report an error. \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_19.wast b/tests/unit/linear-memory-wasm/mem_page_19.wast new file mode 100644 index 0000000000..8cf0a39f67 --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_19.wast @@ -0,0 +1 @@ +(module (memory 65535 65537)) ;; Should report an error. \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/mem_page_20.wast b/tests/unit/linear-memory-wasm/mem_page_20.wast new file mode 100644 index 0000000000..0d4b6ebd6e --- /dev/null +++ b/tests/unit/linear-memory-wasm/mem_page_20.wast @@ -0,0 +1 @@ +(module (memory 65535)) \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/out_of_bounds.wast b/tests/unit/linear-memory-wasm/out_of_bounds.wast new file mode 100644 index 0000000000..89854b924d --- /dev/null +++ b/tests/unit/linear-memory-wasm/out_of_bounds.wast @@ -0,0 +1,10 @@ +(module + (type $1 (func (param i32) (result i32))) + (memory $3 0) + (export "load" (func $4)) + + (func $4 (type $1) (param $0 i32) (result i32) + local.get $0 + i32.load + ) +) diff --git a/tests/unit/linear-memory-wasm/readme b/tests/unit/linear-memory-wasm/readme new file mode 100644 index 0000000000..a9ec33833f --- /dev/null +++ b/tests/unit/linear-memory-wasm/readme @@ -0,0 +1,2 @@ +build 64 bit target: cmake .. +build 32 bit target: cmake .. -DWAMR_BUILD_TARGET=X86_32 \ No newline at end of file diff --git a/tests/unit/linear-memory-wasm/wasm_files/mem_grow_out_of_bounds_01.wasm b/tests/unit/linear-memory-wasm/wasm_files/mem_grow_out_of_bounds_01.wasm new file mode 100644 index 0000000000..544ed91e81 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/mem_grow_out_of_bounds_01.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/mem_grow_out_of_bounds_02.wasm b/tests/unit/linear-memory-wasm/wasm_files/mem_grow_out_of_bounds_02.wasm new file mode 100644 index 0000000000..ded9cc9fc4 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/mem_grow_out_of_bounds_02.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/out_of_bounds.wasm b/tests/unit/linear-memory-wasm/wasm_files/out_of_bounds.wasm new file mode 100644 index 0000000000..8ba6a862d7 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/out_of_bounds.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_app_heap_02.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_app_heap_02.wasm new file mode 100644 index 0000000000..518975da7f Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_app_heap_02.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_01.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_01.wasm new file mode 100644 index 0000000000..b55aac61b0 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_01.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_02.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_02.wasm new file mode 100644 index 0000000000..67d6849c74 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_02.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_03.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_03.wasm new file mode 100644 index 0000000000..5c82427261 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_03.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_04.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_04.wasm new file mode 100644 index 0000000000..6f2d7eb15e Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_04.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_05.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_05.wasm new file mode 100644 index 0000000000..93b6da7662 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_05.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_06.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_06.wasm new file mode 100644 index 0000000000..d09cfb187c Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_06.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_07.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_07.wasm new file mode 100644 index 0000000000..3ddd31c4f2 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_07.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_08.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_08.wasm new file mode 100644 index 0000000000..e47e0cf8d4 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_08.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_09.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_09.wasm new file mode 100644 index 0000000000..64ffe0388b Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_09.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_10.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_10.wasm new file mode 100644 index 0000000000..1bda46171f Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_10.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_11.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_11.wasm new file mode 100644 index 0000000000..8af96625b4 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_11.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_12.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_12.wasm new file mode 100644 index 0000000000..d3e6416146 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_12.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_13.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_13.wasm new file mode 100644 index 0000000000..89eab4185d Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_13.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_14.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_14.wasm new file mode 100644 index 0000000000..0650b259e1 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_14.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_15.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_15.wasm new file mode 100644 index 0000000000..e7a21b4049 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_15.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_16.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_16.wasm new file mode 100644 index 0000000000..dc19d35517 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_16.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_17.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_17.wasm new file mode 100644 index 0000000000..a7797b1165 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_17.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_18.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_18.wasm new file mode 100644 index 0000000000..f290721470 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_18.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_19.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_19.wasm new file mode 100644 index 0000000000..7c674320f1 Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_19.wasm differ diff --git a/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_20.wasm b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_20.wasm new file mode 100644 index 0000000000..518975da7f Binary files /dev/null and b/tests/unit/linear-memory-wasm/wasm_files/wasm_mem_page_20.wasm differ diff --git a/tests/unit/linux-perf/CMakeLists.txt b/tests/unit/linux-perf/CMakeLists.txt new file mode 100644 index 0000000000..572a087050 --- /dev/null +++ b/tests/unit/linux-perf/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) + +project (test-linux-perf) + +add_definitions (-DRUN_ON_LINUX) + +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_LIBC_BUILTIN 0) +set (WAMR_BUILD_JIT 0) +set (WAMR_BUILD_LAZY_JIT 0) +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_MULTI_MODULE 0) +set (WAMR_BUILD_LINUX_PERF 1) + +add_definitions(-DWASM_ENABLE_WAMR_COMPILER=1) + +# Feature to test +set (WAMR_BUILD_DUMP_CALL_STACK 1) + +include (../unit_common.cmake) + +set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") +if (NOT EXISTS "${LLVM_SRC_ROOT}/build") + message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") +endif () +set (CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include (${IWASM_DIR}/compilation/iwasm_compl.cmake) + +add_executable (linux_perf_test test_sort_func_ptrs.cc) +target_compile_options(linux_perf_test PUBLIC -fpermissive) +target_link_libraries(linux_perf_test gtest_main ) +target_link_options(linux_perf_test + PUBLIC + LINKER:--unresolved-symbols=ignore-all +) + +gtest_discover_tests(linux_perf_test) diff --git a/tests/unit/linux-perf/test_sort_func_ptrs.cc b/tests/unit/linux-perf/test_sort_func_ptrs.cc new file mode 100644 index 0000000000..68f4b850f0 --- /dev/null +++ b/tests/unit/linux-perf/test_sort_func_ptrs.cc @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "aot_runtime.h" +#include +#include +#include + +extern "C" { +// TODO: won't work, for non static function create_perf_map have goto statement jump to label ‘quit’ +// #include "aot_perf_map.c" + +// simply copy the function +struct func_info { + uint32 idx; + void *ptr; +}; + +static int +compare_func_ptrs(const void *f1, const void *f2) +{ + return (intptr_t)((struct func_info *)f1)->ptr + - (intptr_t)((struct func_info *)f2)->ptr; +} + +static struct func_info * +sort_func_ptrs(const AOTModule *module, char *error_buf, uint32 error_buf_size) +{ + uint64 content_len; + struct func_info *sorted_func_ptrs; + unsigned i; + + content_len = (uint64)sizeof(struct func_info) * module->func_count; + sorted_func_ptrs = wasm_runtime_malloc(content_len); + if (!sorted_func_ptrs) { + snprintf(error_buf, error_buf_size, + "allocate memory failed when creating perf map"); + return NULL; + } + + for (i = 0; i < module->func_count; i++) { + sorted_func_ptrs[i].idx = i; + sorted_func_ptrs[i].ptr = module->func_ptrs[i]; + } + + qsort(sorted_func_ptrs, module->func_count, sizeof(struct func_info), + compare_func_ptrs); + + return sorted_func_ptrs; +} + +void * +wasm_runtime_malloc(unsigned int size) +{ + return malloc(size); +} + +void +wasm_runtime_free(void* ptr) +{ + return free(ptr); +} + +int +b_memcpy_s(void *s1, unsigned int s1max, const void *s2, unsigned int n) +{ + return memcpy(s1, s2, n); +} +} + +TEST(TestSortFuncPtrs, qsort) +{ + void *p = sort_func_ptrs; + ASSERT_NE(p, nullptr); + + void *funcs[5] = { + (void *)0x1024, (void *)0x10, (void *)0x24, (void *)0x102, (void *)0x4, + }; + + AOTModule module = { 0 }; + module.func_count = 5; + module.func_ptrs = &funcs[0]; + + char buf[64] = { 0 }; + + struct func_info *sorted_funcs = sort_func_ptrs(&module, buf, 64); + // sorted + ASSERT_EQ((uintptr_t)(sorted_funcs[0].ptr), 0x4); + ASSERT_EQ((uintptr_t)(sorted_funcs[1].ptr), 0x10); + ASSERT_EQ((uintptr_t)(sorted_funcs[2].ptr), 0x24); + ASSERT_EQ((uintptr_t)(sorted_funcs[3].ptr), 0x102); + ASSERT_EQ((uintptr_t)(sorted_funcs[4].ptr), 0x1024); + + ASSERT_EQ(sorted_funcs[0].idx, 4); + ASSERT_EQ(sorted_funcs[1].idx, 1); + ASSERT_EQ(sorted_funcs[2].idx, 2); + ASSERT_EQ(sorted_funcs[3].idx, 3); + ASSERT_EQ(sorted_funcs[4].idx, 0); + + // don't change input + ASSERT_EQ((uintptr_t)(funcs[0]), 0x1024); + ASSERT_EQ((uintptr_t)(funcs[1]), 0x10); + ASSERT_EQ((uintptr_t)(funcs[2]), 0x24); + ASSERT_EQ((uintptr_t)(funcs[3]), 0x102); + ASSERT_EQ((uintptr_t)(funcs[4]), 0x4); + + wasm_runtime_free(sorted_funcs); +} \ No newline at end of file diff --git a/tests/unit/memory64/CMakeLists.txt b/tests/unit/memory64/CMakeLists.txt new file mode 100644 index 0000000000..f3629a7c40 --- /dev/null +++ b/tests/unit/memory64/CMakeLists.txt @@ -0,0 +1,67 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) + +project(test-memory64) + +add_definitions(-DRUN_ON_LINUX) + +set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_APP_FRAMEWORK 0) +# TODO: Currently only support classic interpreter mode +set(WAMR_BUILD_AOT 0) +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_FAST_INTERP 0) +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_FAST_JIT 0) +set(WAMR_BUILD_MEMORY64 1) +set(WAMR_BUILD_SHARED_MEMORY 1) + +# if only load this CMake other than load it as subdirectory +# include(GoogleTest) +include(../unit_common.cmake) + +set(LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") + +if (NOT EXISTS "${LLVM_SRC_ROOT}/build") + message(FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") +endif () + +set(CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include(${IWASM_DIR}/compilation/iwasm_compl.cmake) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +file(GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set(UNIT_SOURCE ${source_all}) + +aux_source_directory(. SRC_LIST) + +set(unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} + ${UNCOMMON_SHARED_SOURCE} + ${SRC_LIST} + ) + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable(memory64_test ${unit_test_sources}) + +target_link_libraries(memory64_test ${LLVM_AVAILABLE_LIBS} gtest_main) + +add_custom_command(TARGET memory64_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps/*.wasm + ${CMAKE_CURRENT_BINARY_DIR}/ + COMMENT "Copy test wasm files to the directory of google test" + ) + +gtest_discover_tests(memory64_test) diff --git a/tests/unit/memory64/memory64_atomic_test.cc b/tests/unit/memory64/memory64_atomic_test.cc new file mode 100644 index 0000000000..2f97038905 --- /dev/null +++ b/tests/unit/memory64/memory64_atomic_test.cc @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "memory64_common.h" + +// To use a test fixture and Value Parameterized Tests, +// derive a class from testing::TestWithParam. +class memory64_atomic_test_suite : public testing::TestWithParam +{ + protected: + bool load_wasm_file(const char *wasm_file) + { + const char *file; + unsigned char *wasm_file_buf; + uint32 wasm_file_size; + + file = wasm_file; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(file, &wasm_file_size); + if (!wasm_file_buf) + goto fail; + + if (!(module = wasm_runtime_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + printf("Load wasm module failed. error: %s\n", error_buf); + goto fail; + } + return true; + + fail: + if (!module) + wasm_runtime_unload(module); + + return false; + } + + bool init_exec_env() + { + if (!(module_inst = + wasm_runtime_instantiate(module, stack_size, heap_size, + error_buf, sizeof(error_buf)))) { + printf("Instantiate wasm module failed. error: %s\n", error_buf); + goto fail; + } + if (!(exec_env = + wasm_runtime_create_exec_env(module_inst, stack_size))) { + printf("Create wasm execution environment failed.\n"); + goto fail; + } + return true; + + fail: + if (exec_env) + wasm_runtime_destroy_exec_env(exec_env); + if (module_inst) + wasm_runtime_unload(module); + return false; + } + + void destory_exec_env() + { + wasm_runtime_destroy_exec_env(exec_env); + wasm_runtime_deinstantiate(module_inst); + wasm_runtime_unload(module); + } + + public: + // If your test fixture defines SetUpTestSuite() or TearDownTestSuite() + // they must be declared public rather than protected in order to use + // TEST_P. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the variables. + // Otherwise, this can be skipped. + virtual void SetUp() + { + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + ASSERT_EQ(wasm_runtime_full_init(&init_args), true); + ASSERT_TRUE(load_wasm_file("atomic_opcodes.wasm")); + ASSERT_TRUE(init_exec_env()); + + running_mode = GetParam(); + ASSERT_TRUE(wasm_runtime_set_running_mode(module_inst, running_mode)); + ASSERT_EQ(running_mode, wasm_runtime_get_running_mode(module_inst)); + + for (auto &iter : func_map) { + iter.second = + wasm_runtime_lookup_function(module_inst, iter.first.c_str()); + ASSERT_TRUE(iter.second != NULL); + } + + cleanup = true; + } + + static void SetUpTestCase() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() + { + if (cleanup) { + destory_exec_env(); + wasm_runtime_destroy(); + cleanup = false; + } + } + + static void TearDownTestCase() {} + + RuntimeInitArgs init_args; + wasm_module_t module = NULL; + wasm_module_inst_t module_inst = NULL; + wasm_exec_env_t exec_env = NULL; + RunningMode running_mode; + char error_buf[128]; + char global_heap_buf[512 * 1024]; + uint32_t stack_size = 8092, heap_size = 8092; + bool cleanup = true; + std::unordered_map func_map = { + { "i32_atomic_store", nullptr }, + { "i32_atomic_store8", nullptr }, + { "i32_atomic_store16", nullptr }, + { "i64_atomic_store", nullptr }, + { "i64_atomic_store8", nullptr }, + { "i64_atomic_store16", nullptr }, + { "i64_atomic_store32", nullptr }, + { "i32_atomic_load", nullptr }, + { "i32_atomic_load8_u", nullptr }, + { "i32_atomic_load16_u", nullptr }, + { "i64_atomic_load", nullptr }, + { "i64_atomic_load8_u", nullptr }, + { "i64_atomic_load16_u", nullptr }, + { "i64_atomic_load32_u", nullptr }, + { "i32_atomic_rmw_add", nullptr }, + { "i32_atomic_rmw8_add_u", nullptr }, + { "i32_atomic_rmw16_add_u", nullptr }, + { "i64_atomic_rmw_add", nullptr }, + { "i64_atomic_rmw8_add_u", nullptr }, + { "i64_atomic_rmw16_add_u", nullptr }, + { "i64_atomic_rmw32_add_u", nullptr }, + { "i64_atomic_rmw_cmpxchg", nullptr }, + }; + uint32_t wasm_argv[6], i32; + uint64_t i64; +}; + +TEST_P(memory64_atomic_test_suite, atomic_opcodes_i64_st) +{ + // store at 0x2000, with value 0xbeefdead + PUT_I64_TO_ADDR(wasm_argv, 0x2000); + PUT_I64_TO_ADDR(wasm_argv + 2, 0xcafedeadbeefdead); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_store"], + 4, wasm_argv)); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_load"], 2, + wasm_argv)); + // check return value: 0xcafedeadbeefdead:i64 + i64 = 0xcafedeadbeefdead; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + // store at 0x2000, with value 0xbeefbeef + PUT_I64_TO_ADDR(wasm_argv, 0x2000); + PUT_I64_TO_ADDR(wasm_argv + 2, 0xdeadbeef); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_store32"], + 4, wasm_argv)); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_load"], 2, + wasm_argv)); + // check return value: 0xcafedeaddeadbeef:i64 + i64 = 0xcafedeaddeadbeef; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + // store at 0x2000, with value 0xcafe + PUT_I64_TO_ADDR(wasm_argv, 0x2000); + PUT_I64_TO_ADDR(wasm_argv + 2, 0xcafe); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_store16"], + 4, wasm_argv)); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_load"], 2, + wasm_argv)); + // check return value: 0xcafedeaddeadcafe:i64 + i64 = 0xcafedeaddeadcafe; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + // store at 0x2000, with value 0xcafe + PUT_I64_TO_ADDR(wasm_argv, 0x2000); + PUT_I64_TO_ADDR(wasm_argv + 2, 0xaa); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_store8"], + 4, wasm_argv)); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_load"], 2, + wasm_argv)); + // check return value: 0xcafedeaddeadcaaa:i64 + i64 = 0xcafedeaddeadcaaa; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); +} + +TEST_P(memory64_atomic_test_suite, atomic_opcodes_i32_st) +{ + // store at 0x1000, with value 0xbeefbeef + PUT_I64_TO_ADDR(wasm_argv, 0x2000); + PUT_I64_TO_ADDR(wasm_argv + 2, 0xaabbccdd); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i32_atomic_store"], + 4, wasm_argv)); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i32_atomic_load"], 2, + wasm_argv)); + // check return value: 0xaabbccdd:i32 + i32 = 0xaabbccdd; + ASSERT_EQ(i32, wasm_argv[0]); + + // store at 0x1000, with value 0xcafe + PUT_I64_TO_ADDR(wasm_argv, 0x2000); + PUT_I64_TO_ADDR(wasm_argv + 2, 0xcafe); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i32_atomic_store16"], + 4, wasm_argv)); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i32_atomic_load"], 2, + wasm_argv)); + // check return value: 0xaabbcafe:i32 + i32 = 0xaabbcafe; + ASSERT_EQ(i32, wasm_argv[0]); + + PUT_I64_TO_ADDR(wasm_argv, 0x2000); + PUT_I64_TO_ADDR(wasm_argv + 2, 0xaa); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i32_atomic_store8"], + 4, wasm_argv)); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i32_atomic_load"], 2, + wasm_argv)); + // check return value: 0xaabbcaaa:i32 + i32 = 0xaabbcaaa; + ASSERT_EQ(i32, wasm_argv[0]); +} + +TEST_P(memory64_atomic_test_suite, atomic_opcodes_i64_ld) +{ + // from address 0, it's \01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F\10 + PUT_I64_TO_ADDR(wasm_argv, 0x0); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_load"], 2, + wasm_argv)); + // check return value: 0x0807060504030201:i64 + i64 = 0x0807060504030201; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + PUT_I64_TO_ADDR(wasm_argv, 0x8); + ASSERT_TRUE(wasm_runtime_call_wasm( + exec_env, func_map["i64_atomic_load32_u"], 2, wasm_argv)); + // check return value: 0x0C0B0A09:i64 + i64 = 0x0C0B0A09; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + PUT_I64_TO_ADDR(wasm_argv, 0x8); + ASSERT_TRUE(wasm_runtime_call_wasm( + exec_env, func_map["i64_atomic_load16_u"], 2, wasm_argv)); + // check return value: 0x0A09:i64 + i64 = 0x0A09; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + PUT_I64_TO_ADDR(wasm_argv, 0x0A); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_load8_u"], + 2, wasm_argv)); + // check return value: 0x0B:i64 + i64 = 0x0B; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); +} + +TEST_P(memory64_atomic_test_suite, atomic_opcodes_i32_ld) +{ + // from address 0, it's \01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F\10 + PUT_I64_TO_ADDR(wasm_argv, 0x0); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i32_atomic_load"], 2, + wasm_argv)); + // check return value: 0x04030201:i32 + i32 = 0x04030201; + ASSERT_EQ(i32, wasm_argv[0]); + + PUT_I64_TO_ADDR(wasm_argv, 0x8); + ASSERT_TRUE(wasm_runtime_call_wasm( + exec_env, func_map["i32_atomic_load16_u"], 2, wasm_argv)); + // check return value: 0x0A09:i32 + i32 = 0x0A09; + ASSERT_EQ(i32, wasm_argv[0]); + + PUT_I64_TO_ADDR(wasm_argv, 0xA); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i32_atomic_load8_u"], + 2, wasm_argv)); + // check return value: 0x0B:i32 + i32 = 0x0B; + ASSERT_EQ(i32, wasm_argv[0]); +} + +TEST_P(memory64_atomic_test_suite, atomic_opcodes_i64_rmw_add) +{ + // from address 0, it's \01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F\10 + PUT_I64_TO_ADDR(wasm_argv, 0x8); + PUT_I64_TO_ADDR(wasm_argv + 2, 0x1010101020202020); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_rmw_add"], + 4, wasm_argv)); + i64 = 0x100F0E0D0C0B0A09; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + PUT_I64_TO_ADDR(wasm_argv, 0x8); + PUT_I64_TO_ADDR(wasm_argv + 2, 0x10103030); + ASSERT_TRUE(wasm_runtime_call_wasm( + exec_env, func_map["i64_atomic_rmw32_add_u"], 4, wasm_argv)); + i64 = 0x2C2B2A29; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + PUT_I64_TO_ADDR(wasm_argv, 0x8); + PUT_I64_TO_ADDR(wasm_argv + 2, 0x1020); + ASSERT_TRUE(wasm_runtime_call_wasm( + exec_env, func_map["i64_atomic_rmw16_add_u"], 4, wasm_argv)); + i64 = 0x5A59; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + PUT_I64_TO_ADDR(wasm_argv, 0x8); + PUT_I64_TO_ADDR(wasm_argv + 2, 0x30); + ASSERT_TRUE(wasm_runtime_call_wasm( + exec_env, func_map["i64_atomic_rmw8_add_u"], 4, wasm_argv)); + i64 = 0x79; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + PUT_I64_TO_ADDR(wasm_argv, 0x8); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_load"], 2, + wasm_argv)); + i64 = 0x201F1E1D3C3B6AA9; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); +} + +TEST_P(memory64_atomic_test_suite, atomic_opcodes_i64_rmw_cmpxchg) +{ + // from address 0, it's \01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F\10 + PUT_I64_TO_ADDR(wasm_argv, 0x8); + // old + PUT_I64_TO_ADDR(wasm_argv + 2, 0x100F0E0D0C0B0A09); + // new + PUT_I64_TO_ADDR(wasm_argv + 4, 0xdeadcafebeefdead); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_rmw_cmpxchg"], + 6, wasm_argv)); + i64 = 0x100F0E0D0C0B0A09; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + PUT_I64_TO_ADDR(wasm_argv, 0x8); + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_map["i64_atomic_load"], 2, + wasm_argv)); + i64 = 0xdeadcafebeefdead; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); +} + +INSTANTIATE_TEST_CASE_P(RunningMode, memory64_atomic_test_suite, + testing::ValuesIn(running_mode_supported)); diff --git a/tests/unit/memory64/memory64_common.h b/tests/unit/memory64/memory64_common.h new file mode 100644 index 0000000000..76c43a8e7d --- /dev/null +++ b/tests/unit/memory64/memory64_common.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef UNIT_TEST_MEMORY64_COMMON_H +#define UNIT_TEST_MEMORY64_COMMON_H + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "platform_common.h" +#include "wasm_runtime_common.h" +#include "bh_read_file.h" +#include "wasm_runtime.h" +#include "bh_platform.h" +#include "wasm_export.h" +#include +// #include "aot_runtime.h" + +namespace { + +std::vector running_mode_supported = { Mode_Interp, +#if WASM_ENABLE_FAST_JIT != 0 + Mode_Fast_JIT, +#endif +#if WASM_ENABLE_JIT != 0 + Mode_LLVM_JIT, +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + Mode_Multi_Tier_JIT +#endif +}; + +static inline uint64 +GET_U64_FROM_ADDR(uint32 *addr) +{ + union { + uint64 val; + uint32 parts[2]; + } u; + u.parts[0] = addr[0]; + u.parts[1] = addr[1]; + return u.val; +} + +static inline void +PUT_U64_TO_ADDR(uint32 *addr, uint64 value) +{ + uint32 *addr_u32 = (uint32 *)(addr); + union { + float64 val; + uint32 parts[2]; + } u; + u.val = (value); + addr_u32[0] = u.parts[0]; + addr_u32[1] = u.parts[1]; +} + +} + +#endif // UNIT_TEST_MEMORY64_COMMON_H diff --git a/tests/unit/memory64/memory64_test.cc b/tests/unit/memory64/memory64_test.cc new file mode 100644 index 0000000000..67315a594c --- /dev/null +++ b/tests/unit/memory64/memory64_test.cc @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "memory64_common.h" + +// To use a test fixture and Value Parameterized Tests, +// derive a class from testing::TestWithParam. +class memory64_test_suite : public testing::TestWithParam +{ + protected: + bool load_wasm_file(const char *wasm_file) + { + const char *file; + unsigned char *wasm_file_buf; + uint32 wasm_file_size; + + file = wasm_file; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(file, &wasm_file_size); + if (!wasm_file_buf) + goto fail; + + if (!(module = wasm_runtime_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + printf("Load wasm module failed. error: %s\n", error_buf); + goto fail; + } + return true; + + fail: + if (!module) + wasm_runtime_unload(module); + + return false; + } + + bool init_exec_env() + { + if (!(module_inst = + wasm_runtime_instantiate(module, stack_size, heap_size, + error_buf, sizeof(error_buf)))) { + printf("Instantiate wasm module failed. error: %s\n", error_buf); + goto fail; + } + if (!(exec_env = + wasm_runtime_create_exec_env(module_inst, stack_size))) { + printf("Create wasm execution environment failed.\n"); + goto fail; + } + return true; + + fail: + if (exec_env) + wasm_runtime_destroy_exec_env(exec_env); + if (module_inst) + wasm_runtime_unload(module); + return false; + } + + void destory_exec_env() + { + wasm_runtime_destroy_exec_env(exec_env); + wasm_runtime_deinstantiate(module_inst); + wasm_runtime_unload(module); + } + + public: + // If your test fixture defines SetUpTestSuite() or TearDownTestSuite() + // they must be declared public rather than protected in order to use + // TEST_P. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() + { + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + ASSERT_EQ(wasm_runtime_full_init(&init_args), true); + + cleanup = true; + } + + static void SetUpTestCase() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() + { + if (cleanup) { + wasm_runtime_destroy(); + cleanup = false; + } + } + + static void TearDownTestCase() {} + + RuntimeInitArgs init_args; + wasm_module_t module = NULL; + wasm_module_inst_t module_inst = NULL; + wasm_exec_env_t exec_env = NULL; + char error_buf[128]; + char global_heap_buf[512 * 1024]; + uint32_t stack_size = 8092, heap_size = 8092; + bool cleanup = true; +}; + +TEST_F(memory64_test_suite, wasm_runtime_is_running_mode_supported) +{ + // TODO: make sure the chosen running mode option is compiled, for memory64, + // currently only support classic interp mode + ASSERT_EQ(true, wasm_runtime_is_running_mode_supported( + static_cast(Mode_Default))); + for (auto running_mode : running_mode_supported) { + ASSERT_EQ(true, wasm_runtime_is_running_mode_supported(running_mode)); + } +} + +TEST_F(memory64_test_suite, page_exceed_u32_1) +{ + bool ret; + ret = load_wasm_file("page_exceed_u32.wasm"); + ASSERT_FALSE(ret); + ASSERT_TRUE(strcmp("WASM module load failed: integer too large", error_buf) + == 0); +} + +TEST_F(memory64_test_suite, page_exceed_u32_2) +{ + bool ret; + ret = load_wasm_file("page_exceed_u32_2.wasm"); + ASSERT_FALSE(ret); + ASSERT_TRUE(strcmp("WASM module load failed: integer too large", error_buf) + == 0); +} + +TEST_F(memory64_test_suite, page_u32_max) +{ + bool ret; + ret = load_wasm_file("page_u32_max.wasm"); + ASSERT_TRUE(ret); +} + +TEST_P(memory64_test_suite, memory_8GB) +{ + RunningMode running_mode = GetParam(); + wasm_function_inst_t touch_every_page_func, i64_store_offset_4GB, + i64_load_offset_4GB; + uint32_t wasm_argv[6], i32; + uint64_t i64; + bool ret; + + ret = load_wasm_file("8GB_memory.wasm"); + ASSERT_TRUE(ret); + ret = init_exec_env(); + ASSERT_TRUE(ret); + + ret = wasm_runtime_set_running_mode(module_inst, running_mode); + ASSERT_TRUE(ret); + ASSERT_EQ(running_mode, wasm_runtime_get_running_mode(module_inst)); + + touch_every_page_func = + wasm_runtime_lookup_function(module_inst, "touch_every_page"); + ASSERT_TRUE(touch_every_page_func != NULL); + ret = wasm_runtime_call_wasm(exec_env, touch_every_page_func, 0, wasm_argv); + ASSERT_TRUE(ret); + // check return value: 0xfff8:i64,0x10000fff8:i64,0x1fff8:i32,0x1:i32 + i64 = 0xfff8; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + i64 = 0x10000fff8; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv + 2)); + i32 = 0x1fff8; + ASSERT_EQ(i32, wasm_argv[4]); + i32 = 0x1; + ASSERT_EQ(i32, wasm_argv[5]); + + // store at 0x100001000, with value 0xbeefdead + PUT_I64_TO_ADDR(wasm_argv, 0x1000); + PUT_I64_TO_ADDR(wasm_argv + 2, 0xbeefdead); + i64_store_offset_4GB = + wasm_runtime_lookup_function(module_inst, "i64_store_offset_4GB"); + ASSERT_TRUE(i64_store_offset_4GB != NULL); + ret = wasm_runtime_call_wasm(exec_env, i64_store_offset_4GB, 4, wasm_argv); + ASSERT_TRUE(ret); + + i64_load_offset_4GB = + wasm_runtime_lookup_function(module_inst, "i64_load_offset_4GB"); + ASSERT_TRUE(i64_load_offset_4GB != NULL); + ret = wasm_runtime_call_wasm(exec_env, i64_load_offset_4GB, 2, wasm_argv); + ASSERT_TRUE(ret); + // check return value: 0xbeefdead:i64 + i64 = 0xbeefdead; + ASSERT_EQ(i64, GET_U64_FROM_ADDR(wasm_argv)); + + destory_exec_env(); +} + +TEST_P(memory64_test_suite, mem64_from_clang) +{ + RunningMode running_mode = GetParam(); + wasm_function_inst_t test_func; + uint32_t wasm_argv[1], i32; + bool ret; + + ret = load_wasm_file("mem64.wasm"); + ASSERT_TRUE(ret); + ret = init_exec_env(); + ASSERT_TRUE(ret); + + ret = wasm_runtime_set_running_mode(module_inst, running_mode); + ASSERT_TRUE(ret); + ASSERT_EQ(running_mode, wasm_runtime_get_running_mode(module_inst)); + + test_func = + wasm_runtime_lookup_function(module_inst, "test"); + ASSERT_TRUE(test_func != NULL); + ret = wasm_runtime_call_wasm(exec_env, test_func, 0, wasm_argv); + ASSERT_TRUE(ret); + i32 = 0x109; + ASSERT_EQ(i32, wasm_argv[0]); + + destory_exec_env(); +} + +INSTANTIATE_TEST_CASE_P(RunningMode, memory64_test_suite, + testing::ValuesIn(running_mode_supported)); \ No newline at end of file diff --git a/tests/unit/memory64/wasm-apps/8GB_memory.wasm b/tests/unit/memory64/wasm-apps/8GB_memory.wasm new file mode 100644 index 0000000000..32028ff62b Binary files /dev/null and b/tests/unit/memory64/wasm-apps/8GB_memory.wasm differ diff --git a/tests/unit/memory64/wasm-apps/8GB_memory.wat b/tests/unit/memory64/wasm-apps/8GB_memory.wat new file mode 100644 index 0000000000..10e3551989 --- /dev/null +++ b/tests/unit/memory64/wasm-apps/8GB_memory.wat @@ -0,0 +1,53 @@ +(module + ;; Memory definition: 4 GB = 65536 + ;; 8 GB = 131072 + ;; 16 GB = 262144 + ;; 20 GB = 327680 + ;; 32 GB = 524288 + (memory (;0;) i64 131072 131072) + + ;; if touch too many pages more than physical memory can provide, + ;; the signal will kill the process + (func (export "touch_every_page") (result i64 i64 i32 i32) + (local $i i64) + i64.const 0x0000000000000ff8 + local.set $i + loop $loop + ;; a[i] = i + local.get $i + local.get $i + i64.store + local.get $i + i64.const 4096 + i64.add + local.set $i + local.get $i + ;; max boundary(exclusive) 8GB - 8 = 0x0000000200000000 - 8 + i64.const 0x0000000200000000 + i64.const 8 + i64.sub + i64.lt_u + br_if $loop + end + i64.const 0x000000000000fff8 + i64.load + i64.const 0x000000010000fff8 + i64.load + ;; lower 8 bytes of 0x000000010001fff8 -> 0x0001fff8 + i64.const 0x000000010001fff8 + i32.load + ;; higher 8 bytes of 0x000000010001fff8 -> 0x1 + i64.const 0x000000010001fffc + i32.load + return + ) + + ;; Function to test i64.atomic.store with i64 address + (func (export "i64_store_offset_4GB") (param $addr i64) (param $value i64) + (i64.store offset=0x100000000 (local.get $addr) (local.get $value)) + ) + + (func (export "i64_load_offset_4GB") (param $addr i64) (result i64) + (i64.load offset=0x100000000 (local.get $addr)) + ) +) \ No newline at end of file diff --git a/tests/unit/memory64/wasm-apps/atomic_opcodes.wasm b/tests/unit/memory64/wasm-apps/atomic_opcodes.wasm new file mode 100644 index 0000000000..fbdc587096 Binary files /dev/null and b/tests/unit/memory64/wasm-apps/atomic_opcodes.wasm differ diff --git a/tests/unit/memory64/wasm-apps/atomic_opcodes.wat b/tests/unit/memory64/wasm-apps/atomic_opcodes.wat new file mode 100644 index 0000000000..dd86fede8b --- /dev/null +++ b/tests/unit/memory64/wasm-apps/atomic_opcodes.wat @@ -0,0 +1,120 @@ +(module + ;; Memory definition: 4 GB = 65536 + ;; 8 GB = 131072 + ;; 16 GB = 262144 + ;; 20 GB = 327680 + (memory (;0;) i64 200 200 shared) + + ;; Initialize memory with some values + (data (i64.const 0) "\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F\10") + + ;; Function to test i32.atomic.store with i64 address + (func (export "i32_atomic_store") (param $addr i64) (param $value i32) + (i32.atomic.store (local.get $addr) (local.get $value)) + ) + + ;; Function to test i32.atomic.store8 with i64 address + (func (export "i32_atomic_store8") (param $addr i64) (param $value i32) + (i32.atomic.store8 (local.get $addr) (local.get $value)) + ) + + ;; Function to test i32.atomic.store16 with i64 address + (func (export "i32_atomic_store16") (param $addr i64) (param $value i32) + (i32.atomic.store16 (local.get $addr) (local.get $value)) + ) + + ;; Function to test i64.atomic.store with i64 address + (func (export "i64_atomic_store") (param $addr i64) (param $value i64) + (i64.atomic.store (local.get $addr) (local.get $value)) + ) + + ;; Function to test i64.atomic.store8 with i64 address + (func (export "i64_atomic_store8") (param $addr i64) (param $value i64) + (i64.atomic.store8 (local.get $addr) (local.get $value)) + ) + + ;; Function to test i64.atomic.store16 with i64 address + (func (export "i64_atomic_store16") (param $addr i64) (param $value i64) + (i64.atomic.store16 (local.get $addr) (local.get $value)) + ) + + ;; Function to test i64.atomic.store32 with i64 address + (func (export "i64_atomic_store32") (param $addr i64) (param $value i64) + (i64.atomic.store32 (local.get $addr) (local.get $value)) + ) + + ;; Function to test i32.atomic.load with i64 address + (func (export "i32_atomic_load") (param $addr i64) (result i32) + (i32.atomic.load (local.get $addr)) + ) + + ;; Function to test i32.atomic.load8_u with i64 address + (func (export "i32_atomic_load8_u") (param $addr i64) (result i32) + (i32.atomic.load8_u (local.get $addr)) + ) + + ;; Function to test i32.atomic.load16_u with i64 address + (func (export "i32_atomic_load16_u") (param $addr i64) (result i32) + (i32.atomic.load16_u (local.get $addr)) + ) + + ;; Function to test i64.atomic.load with i64 address + (func (export "i64_atomic_load") (param $addr i64) (result i64) + (i64.atomic.load (local.get $addr)) + ) + + ;; Function to test i64.atomic.load8_u with i64 address + (func (export "i64_atomic_load8_u") (param $addr i64) (result i64) + (i64.atomic.load8_u (local.get $addr)) + ) + + ;; Function to test i64.atomic.load16_u with i64 address + (func (export "i64_atomic_load16_u") (param $addr i64) (result i64) + (i64.atomic.load16_u (local.get $addr)) + ) + + ;; Function to test i64.atomic.load32_u with i64 address + (func (export "i64_atomic_load32_u") (param $addr i64) (result i64) + (i64.atomic.load32_u (local.get $addr)) + ) + + ;; Function to test i32.atomic.rmw.add with i64 address + (func (export "i32_atomic_rmw_add") (param $addr i64) (param $value i32) (result i32) + (i32.atomic.rmw.add (local.get $addr) (local.get $value)) + ) + + ;; Function to test i32.atomic.rmw8.add_u with i64 address + (func (export "i32_atomic_rmw8_add_u") (param $addr i64) (param $value i32) (result i32) + (i32.atomic.rmw8.add_u (local.get $addr) (local.get $value)) + ) + + ;; Function to test i32.atomic.rmw16.add_u with i64 address + (func (export "i32_atomic_rmw16_add_u") (param $addr i64) (param $value i32) (result i32) + (i32.atomic.rmw16.add_u (local.get $addr) (local.get $value)) + ) + + ;; Function to test i64.atomic.rmw.add with i64 address + (func (export "i64_atomic_rmw_add") (param $addr i64) (param $value i64) (result i64) + (i64.atomic.rmw.add (local.get $addr) (local.get $value)) + ) + + ;; Function to test i64.atomic.rmw8.add_u with i64 address + (func (export "i64_atomic_rmw8_add_u") (param $addr i64) (param $value i64) (result i64) + (i64.atomic.rmw8.add_u (local.get $addr) (local.get $value)) + ) + + ;; Function to test i64.atomic.rmw16.add_u with i64 address + (func (export "i64_atomic_rmw16_add_u") (param $addr i64) (param $value i64) (result i64) + (i64.atomic.rmw16.add_u (local.get $addr) (local.get $value)) + ) + + ;; Function to test i64.atomic.rmw32.add_u with i64 address + (func (export "i64_atomic_rmw32_add_u") (param $addr i64) (param $value i64) (result i64) + (i64.atomic.rmw32.add_u (local.get $addr) (local.get $value)) + ) + + (func (export "i64_atomic_rmw_cmpxchg") (param $addr i64) (param $old i64) (param $new i64) (result i64) + (i64.atomic.rmw.cmpxchg (local.get $addr) (local.get $old) (local.get $new)) + ) + +) \ No newline at end of file diff --git a/tests/unit/memory64/wasm-apps/mem64.c b/tests/unit/memory64/wasm-apps/mem64.c new file mode 100644 index 0000000000..447a75b693 --- /dev/null +++ b/tests/unit/memory64/wasm-apps/mem64.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +int +add_a_and_b_to_c(int *array, int *b, int *c) +{ + int i; + // Perform computation: multiply each element by 2 + for (i = 0; i < 5; i++) { + array[i] = array[i] * 2; + } + // Compute the product of corresponding elements of a and b + for (i = 0; i < 5; i++) { + c[i] = array[i] * b[i]; + } + return i; +} + +int +test() +{ + // Initialize an array with some values + int array[5] = { 1, 2, 3, 4, 5 }; + int b[5] = { 6, 7, 8, 9, 10 }; + int c[5], i, j, res = 0; + + j = add_a_and_b_to_c(array, b, c); + + for (i = 0; i < 5; i++) { + res += c[i]; + } + + return res + j; +} + +int +main(int argc, char *argv[]) +{ + // Initialize an array with some values + int array[5] = { 1, 2, 3, 4, 5 }; + int b[5] = { 6, 7, 8, 9, 10 }; + int c[5], i; + + // Perform computation: multiply each element by 2 + for (i = 0; i < 5; i++) { + array[i] = array[i] * 2; + } + // Compute the product of corresponding elements of a and b + for (i = 0; i < 5; i++) { + c[i] = array[i] * b[i]; + } + + return c[4]; +} diff --git a/tests/unit/memory64/wasm-apps/mem64.wasm b/tests/unit/memory64/wasm-apps/mem64.wasm new file mode 100755 index 0000000000..b4b0a58629 Binary files /dev/null and b/tests/unit/memory64/wasm-apps/mem64.wasm differ diff --git a/tests/unit/memory64/wasm-apps/page_exceed_u32.wasm b/tests/unit/memory64/wasm-apps/page_exceed_u32.wasm new file mode 100644 index 0000000000..3aa1786d06 Binary files /dev/null and b/tests/unit/memory64/wasm-apps/page_exceed_u32.wasm differ diff --git a/tests/unit/memory64/wasm-apps/page_exceed_u32.wat b/tests/unit/memory64/wasm-apps/page_exceed_u32.wat new file mode 100644 index 0000000000..8da477ff57 --- /dev/null +++ b/tests/unit/memory64/wasm-apps/page_exceed_u32.wat @@ -0,0 +1,4 @@ +(module + ;; u32 max pages is 4,294,967,295 + (memory i64 1 4294967296) +) \ No newline at end of file diff --git a/tests/unit/memory64/wasm-apps/page_exceed_u32_2.wasm b/tests/unit/memory64/wasm-apps/page_exceed_u32_2.wasm new file mode 100644 index 0000000000..cf2f876e48 Binary files /dev/null and b/tests/unit/memory64/wasm-apps/page_exceed_u32_2.wasm differ diff --git a/tests/unit/memory64/wasm-apps/page_exceed_u32_2.wat b/tests/unit/memory64/wasm-apps/page_exceed_u32_2.wat new file mode 100644 index 0000000000..4db1b838d6 --- /dev/null +++ b/tests/unit/memory64/wasm-apps/page_exceed_u32_2.wat @@ -0,0 +1,4 @@ +(module + ;; u32 max pages is 4,294,967,295 + (memory i64 4294967296) +) \ No newline at end of file diff --git a/tests/unit/memory64/wasm-apps/page_u32_max.wasm b/tests/unit/memory64/wasm-apps/page_u32_max.wasm new file mode 100644 index 0000000000..caa8de4543 Binary files /dev/null and b/tests/unit/memory64/wasm-apps/page_u32_max.wasm differ diff --git a/tests/unit/memory64/wasm-apps/page_u32_max.wat b/tests/unit/memory64/wasm-apps/page_u32_max.wat new file mode 100644 index 0000000000..ae2ef11c41 --- /dev/null +++ b/tests/unit/memory64/wasm-apps/page_u32_max.wat @@ -0,0 +1,4 @@ +(module + ;; u32 max pages is 4,294,967,295 + (memory i64 1 4294967295) +) \ No newline at end of file diff --git a/tests/unit/running-modes/CMakeLists.txt b/tests/unit/running-modes/CMakeLists.txt new file mode 100644 index 0000000000..5fc6a80bce --- /dev/null +++ b/tests/unit/running-modes/CMakeLists.txt @@ -0,0 +1,56 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) + +project(test-running-modes) + +# Compile wasm modules +add_subdirectory(wasm-apps) + +add_definitions(-DRUN_ON_LINUX) + +set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_APP_FRAMEWORK 0) +set(WAMR_BUILD_JIT 1) +set(WAMR_BUILD_FAST_JIT 1) + +# if only load this CMake other than load it as subdirectory +include(../unit_common.cmake) + +set(LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") + +if (NOT EXISTS "${LLVM_SRC_ROOT}/build") + message(FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") +endif () + +set(CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include(${IWASM_DIR}/compilation/iwasm_compl.cmake) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +file(GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set(UNIT_SOURCE ${source_all}) + +aux_source_directory(. SRC_LIST) + +set(unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} + ${UNCOMMON_SHARED_SOURCE} + ${SRC_LIST} + ) + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable(wasm_running_modes_test ${unit_test_sources}) + +target_link_libraries(wasm_running_modes_test ${LLVM_AVAILABLE_LIBS} gtest_main) + +gtest_discover_tests(wasm_running_modes_test) diff --git a/tests/unit/running-modes/wasm-apps/CMakeLists.txt b/tests/unit/running-modes/wasm-apps/CMakeLists.txt new file mode 100644 index 0000000000..b2f1e9c0c5 --- /dev/null +++ b/tests/unit/running-modes/wasm-apps/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) +project(wasm-apps) + +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) + +set(CMAKE_SYSTEM_PROCESSOR wasm32) +set(CMAKE_SYSROOT ${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot) + +if (NOT DEFINED WASI_SDK_DIR) + set(WASI_SDK_DIR "/opt/wasi-sdk") +endif () + +set(CMAKE_C_FLAGS "-nostdlib -pthread -Qunused-arguments") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -z stack-size=8192 -nostdlib") +set(CMAKE_C_COMPILER_TARGET "wasm32") +set(CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") + +set(DEFINED_SYMBOLS + "${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt") + +set(CMAKE_EXE_LINKER_FLAGS + "-Wl,--no-entry \ + -Wl,--initial-memory=65536 \ + -Wl,--export-all \ + -Wl,--allow-undefined" + ) + +add_executable(mytest.wasm mytest.c) +target_link_libraries(mytest.wasm) + +add_executable(hello.wasm hello.c) +target_link_libraries(hello.wasm) + +add_custom_command(TARGET hello.wasm POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_BINARY_DIR}/hello.wasm + ${CMAKE_CURRENT_BINARY_DIR}/../ + COMMENT "Copy hello.wasm to the same directory of google test" + ) + +add_custom_command(TARGET mytest.wasm POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_BINARY_DIR}/mytest.wasm + ${CMAKE_CURRENT_BINARY_DIR}/../ + COMMENT "Copy mytest.wasm to the same directory of google test" + ) diff --git a/tests/unit/running-modes/wasm-apps/hello.c b/tests/unit/running-modes/wasm-apps/hello.c new file mode 100644 index 0000000000..3aa7c2a698 --- /dev/null +++ b/tests/unit/running-modes/wasm-apps/hello.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +double +foo(double d) +{ + return d / 3.0; +} + +double +maybe_min(double d, double e) +{ + return d < e ? d : e; +} + +double +factor(double a, double b, double c) +{ + return (a * c) + (b * c); +} + +int +echo(int a) +{ + double b = foo(14.5); + double c = maybe_min(12.2, 15.4); + double d = factor(a, b, c); + return 2 * a; +} \ No newline at end of file diff --git a/tests/unit/running-modes/wasm-apps/mytest.c b/tests/unit/running-modes/wasm-apps/mytest.c new file mode 100644 index 0000000000..c5d1916dee --- /dev/null +++ b/tests/unit/running-modes/wasm-apps/mytest.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +int +recursive(int a) +{ + if (a > 0) { + return recursive(a - 1) + 1; + } + else + return 0; +} + +int +testFunction(int *input, int length) +{ + int sum = 0; + for (int i = 0; i < length; ++i) { + sum += input[i]; + } + return sum; +} + +int +main(int argc, char **argv) +{ + + int arr[5] = { 1, 2, 3, 4, 5 }; + testFunction(arr, recursive(5)); + + char *buf; + + printf("Hello world!\n"); + + buf = malloc(1024); + if (!buf) { + printf("malloc buf failed\n"); + return -1; + } + + printf("buf ptr: %p\n", buf); + + snprintf(buf, 1024, "%s", "1234\n"); + printf("buf: %s", buf); + + free(buf); + return 0; +} diff --git a/tests/unit/running-modes/wasm_running_modes_test.cc b/tests/unit/running-modes/wasm_running_modes_test.cc new file mode 100644 index 0000000000..9d6a9379cd --- /dev/null +++ b/tests/unit/running-modes/wasm_running_modes_test.cc @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "platform_common.h" +#include "wasm_runtime_common.h" +#include "bh_read_file.h" +#include "wasm_runtime.h" +#include "bh_platform.h" +#include "wasm_export.h" +#include "aot_runtime.h" + +namespace { + +std::string CWD; +std::string TEST_WASM1 = "/hello.wasm"; +std::string TEST_WASM2 = "/mytest.wasm"; +char *WASM_FILE_1; +char *WASM_FILE_2; +std::vector running_mode_supportted = { Mode_Interp, +#if WASM_ENABLE_FAST_JIT != 0 + Mode_Fast_JIT, +#endif +#if WASM_ENABLE_JIT != 0 + Mode_LLVM_JIT, +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + Mode_Multi_Tier_JIT +#endif +}; + +// To use a test fixture and Value Parameterized Tests, +// derive a class from testing::TestWithParam. +class wasm_running_modes_test_suite : public testing::TestWithParam +{ + private: + std::string get_binary_path() + { + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); + } + + bool load_wasm_file(const char *wasm_file) + { + const char *file; + unsigned char *wasm_file_buf; + uint32 wasm_file_size; + + file = wasm_file; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(file, &wasm_file_size); + if (!wasm_file_buf) + goto fail; + + if (!(module = wasm_runtime_load(wasm_file_buf, wasm_file_size, + error_buf, sizeof(error_buf)))) { + printf("Load wasm module failed. error: %s\n", error_buf); + goto fail; + } + return true; + + fail: + if (!module) + wasm_runtime_unload(module); + + return false; + } + + bool init_exec_env() + { + if (!(module_inst = + wasm_runtime_instantiate(module, stack_size, heap_size, + error_buf, sizeof(error_buf)))) { + printf("Instantiate wasm module failed. error: %s\n", error_buf); + goto fail; + } + if (!(exec_env = + wasm_runtime_create_exec_env(module_inst, stack_size))) { + printf("Create wasm execution environment failed.\n"); + goto fail; + } + return true; + + fail: + if (exec_env) + wasm_runtime_destroy_exec_env(exec_env); + if (module_inst) + wasm_runtime_unload(module); + return false; + } + + void destory_exec_env() + { + wasm_runtime_destroy_exec_env(exec_env); + wasm_runtime_deinstantiate(module_inst); + wasm_runtime_unload(module); + } + + protected: + void run_wasm_basic( + char *filename, bool in_default_running_mode, + RunningMode running_mode = static_cast(Mode_Default)) + { + bool ret; + uint32_t wasm_argv[2]; + ret = load_wasm_file(filename); + ASSERT_TRUE(ret); + ret = init_exec_env(); + ASSERT_TRUE(ret); + + if (!in_default_running_mode) { + ret = wasm_runtime_set_running_mode(module_inst, running_mode); + ASSERT_TRUE(ret); + ASSERT_EQ(running_mode, wasm_runtime_get_running_mode(module_inst)); + } + + wasm_function_inst_t echo2xback_func = + wasm_runtime_lookup_function(module_inst, "echo"); + ASSERT_TRUE(echo2xback_func != NULL); + + wasm_argv[0] = 5; + ret = wasm_runtime_call_wasm(exec_env, echo2xback_func, 1, wasm_argv); + ASSERT_TRUE(ret); + ASSERT_EQ(10, wasm_argv[0]); + + destory_exec_env(); + } + + void run_wasm_complex(char *filename1, char *filename2, + RunningMode default_running_mode, + RunningMode running_mode) + { + bool ret; + uint32_t wasm_argv[2]; + + /* run wasm file 1 in default running mode */ + wasm_runtime_set_default_running_mode(default_running_mode); + ret = load_wasm_file(filename1); + ASSERT_TRUE(ret); + ret = init_exec_env(); + ASSERT_TRUE(ret); + + uint8_t *buffer, *buffer2; + wasm_function_inst_t echo2xback_func, main; + + ASSERT_EQ(default_running_mode, + wasm_runtime_get_running_mode(module_inst)); + echo2xback_func = wasm_runtime_lookup_function(module_inst, "echo"); + ASSERT_TRUE(echo2xback_func != NULL); + wasm_argv[0] = 5; + ret = wasm_runtime_call_wasm(exec_env, echo2xback_func, 1, wasm_argv); + ASSERT_TRUE(ret); + ASSERT_EQ(10, wasm_argv[0]); + + destory_exec_env(); + + /* run wasm file 2 in running_mode */ + ret = load_wasm_file(filename2); + ASSERT_TRUE(ret); + ret = init_exec_env(); + ASSERT_TRUE(ret); + + ret = wasm_runtime_set_running_mode(module_inst, running_mode); + ASSERT_TRUE(ret); + ASSERT_EQ(running_mode, wasm_runtime_get_running_mode(module_inst)); + main = wasm_runtime_lookup_function(module_inst, "__main_argc_argv"); + ASSERT_TRUE(main != NULL); + ret = wasm_runtime_call_wasm(exec_env, main, 2, wasm_argv); + ASSERT_TRUE(ret); + + destory_exec_env(); + } + + public: + // If your test fixture defines SetUpTestSuite() or TearDownTestSuite() + // they must be declared public rather than protected in order to use + // TEST_P. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() + { + CWD = get_binary_path(); + WASM_FILE_1 = strdup((CWD + TEST_WASM1).c_str()); + WASM_FILE_2 = strdup((CWD + TEST_WASM2).c_str()); + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + ASSERT_EQ(wasm_runtime_full_init(&init_args), true); + + cleanup = true; + } + + static void SetUpTestCase() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() + { + if (cleanup) { + wasm_runtime_destroy(); + cleanup = false; + } + free(WASM_FILE_1); + free(WASM_FILE_2); + } + + static void TearDownTestCase() {} + + std::string CWD; + RuntimeInitArgs init_args; + wasm_module_t module = NULL; + wasm_module_inst_t module_inst = NULL; + wasm_exec_env_t exec_env = NULL; + char error_buf[128]; + char global_heap_buf[512 * 1024]; + uint32_t stack_size = 8092, heap_size = 8092; + bool cleanup = true; +}; + +TEST_F(wasm_running_modes_test_suite, wasm_runtime_is_running_mode_supported) +{ + // normal situation + ASSERT_EQ(true, wasm_runtime_is_running_mode_supported( + static_cast(Mode_Default))); + for (auto running_mode : running_mode_supportted) { + ASSERT_EQ(true, wasm_runtime_is_running_mode_supported(running_mode)); + } + + // abnormal situation + ASSERT_EQ(false, wasm_runtime_is_running_mode_supported( + static_cast(-1))); + ASSERT_EQ(false, wasm_runtime_is_running_mode_supported( + static_cast(5))); + ASSERT_EQ(false, wasm_runtime_is_running_mode_supported( + static_cast(0xFF))); +} + +TEST_F(wasm_running_modes_test_suite, wasm_runtime_set_default_running_mode) +{ + // normal situation: only set up + ASSERT_EQ(true, wasm_runtime_set_default_running_mode( + static_cast(Mode_Default))); + for (auto running_mode : running_mode_supportted) { + ASSERT_EQ(true, wasm_runtime_set_default_running_mode(running_mode)); + } + + // abnormal situation + ASSERT_EQ(false, wasm_runtime_set_default_running_mode( + static_cast(-1))); + ASSERT_EQ(false, wasm_runtime_set_default_running_mode( + static_cast(5))); + ASSERT_EQ(false, wasm_runtime_set_default_running_mode( + static_cast(0xFF))); +} + +TEST_P(wasm_running_modes_test_suite, + wasm_runtime_set_default_running_mode_basic) +{ + RunningMode running_mode = GetParam(); + ASSERT_EQ(true, wasm_runtime_set_default_running_mode(running_mode)); + run_wasm_basic(WASM_FILE_1, true); +} + +TEST_P(wasm_running_modes_test_suite, + wasm_runtime_set_and_get_running_mode_basic) +{ + RunningMode running_mode = GetParam(); + run_wasm_basic(WASM_FILE_1, false, running_mode); +} + +TEST_P(wasm_running_modes_test_suite, + wasm_runtime_set_and_get_running_mode_complex) +{ + RunningMode default_running_mode = GetParam(); + for (auto running_mode : running_mode_supportted) { + run_wasm_complex(WASM_FILE_1, WASM_FILE_2, default_running_mode, + running_mode); + } +} + +INSTANTIATE_TEST_CASE_P(RunningMode, wasm_running_modes_test_suite, + testing::ValuesIn(running_mode_supportted)); + +} \ No newline at end of file diff --git a/tests/unit/runtime-common/CMakeLists.txt b/tests/unit/runtime-common/CMakeLists.txt new file mode 100644 index 0000000000..f737569151 --- /dev/null +++ b/tests/unit/runtime-common/CMakeLists.txt @@ -0,0 +1,73 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project(test-runtime-common) + +add_definitions(-DRUN_ON_LINUX) + +set(WAMR_BUILD_LIBC_WASI 0) +set(WAMR_BUILD_APP_FRAMEWORK 0) + +include(../unit_common.cmake) + +set(LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") + +if(NOT EXISTS "${LLVM_SRC_ROOT}/build") + message(FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build") +endif() + +set(CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}") +find_package(LLVM REQUIRED CONFIG) +include_directories(${LLVM_INCLUDE_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +file(GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set(UNIT_SOURCE ${source_all}) + +aux_source_directory(. SRC_LIST) + +set(unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} + ${UNCOMMON_SHARED_SOURCE} + ${SRC_LIST} +) + +add_executable(runtime_common_test ${unit_test_sources}) + +target_link_libraries(runtime_common_test ${LLVM_AVAILABLE_LIBS} gtest_main) + +# Ensure that aot compiled is completed before linear_memory_test_aot is built +set(dummy_output "${CMAKE_CURRENT_BINARY_DIR}/dummy_output") + +add_custom_command(OUTPUT ${dummy_output} + COMMAND ./build_aot.sh + COMMAND ${CMAKE_COMMAND} -E touch ${dummy_output} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/build_aot.sh + COMMENT "Executing script to compile aot files" + VERBATIM +) + +add_custom_target( + BuildAot ALL + DEPENDS ${dummy_output} +) + +add_dependencies(runtime_common_test BuildAot) + +add_custom_command(TARGET runtime_common_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_LIST_DIR}/wasm-apps/main.wasm ${CMAKE_CURRENT_LIST_DIR}/wasm-apps/main.aot + ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copy main.wasm and main.aot to the directory: build/runtime-common." +) + +gtest_discover_tests(runtime_common_test) diff --git a/tests/unit/runtime-common/build_aot.sh b/tests/unit/runtime-common/build_aot.sh new file mode 100755 index 0000000000..441d441b55 --- /dev/null +++ b/tests/unit/runtime-common/build_aot.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +# Define a list of .wasm files +file_names=("main") + +WORKDIR="$PWD" +WAMRC_ROOT_DIR="${WORKDIR}/../../../wamr-compiler" +WAMRC="${WAMRC_ROOT_DIR}/build/wamrc" +WAST2WASM="/opt/wabt/bin/wat2wasm" + +# build wamrc if not exist +if [ ! -s "$WAMRC" ]; then + cd $WAMRC_ROOT_DIR + if [ -d "$WAMRC/build" ]; then + rm -r build + fi + cmake -B build && cmake --build build -j $(nproc) + cd $WORKDIR +fi + +# Iterate over the files array +for file_name in "${file_names[@]}"; do + # compile wasm to aot + $WAMRC -o "wasm-apps/${file_name}.aot" "wasm-apps/${file_name}.wasm" +done + diff --git a/tests/unit/runtime-common/wasm-apps/main.aot b/tests/unit/runtime-common/wasm-apps/main.aot new file mode 100644 index 0000000000..79319145a9 Binary files /dev/null and b/tests/unit/runtime-common/wasm-apps/main.aot differ diff --git a/tests/unit/runtime-common/wasm-apps/main.wasm b/tests/unit/runtime-common/wasm-apps/main.wasm new file mode 100644 index 0000000000..28af80e405 Binary files /dev/null and b/tests/unit/runtime-common/wasm-apps/main.wasm differ diff --git a/tests/unit/runtime-common/wasm_exec_env_test.cc b/tests/unit/runtime-common/wasm_exec_env_test.cc new file mode 100644 index 0000000000..06c162b623 --- /dev/null +++ b/tests/unit/runtime-common/wasm_exec_env_test.cc @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "wasm_exec_env.h" + +class wasm_exec_env_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} +}; + +TEST_F(wasm_exec_env_test_suite, wasm_exec_env_create) +{ + EXPECT_EQ(nullptr, wasm_exec_env_create(nullptr, 0)); +} + +TEST_F(wasm_exec_env_test_suite, wasm_exec_env_create_internal) +{ + EXPECT_EQ(nullptr, wasm_exec_env_create_internal(nullptr, UINT32_MAX)); +} + +TEST_F(wasm_exec_env_test_suite, wasm_exec_env_pop_jmpbuf) +{ + WASMExecEnv exec_env; + + exec_env.jmpbuf_stack_top = nullptr; + EXPECT_EQ(nullptr, wasm_exec_env_pop_jmpbuf(&exec_env)); +} diff --git a/tests/unit/runtime-common/wasm_runtime_common_test.cc b/tests/unit/runtime-common/wasm_runtime_common_test.cc new file mode 100644 index 0000000000..978b540227 --- /dev/null +++ b/tests/unit/runtime-common/wasm_runtime_common_test.cc @@ -0,0 +1,682 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "platform_common.h" +#include "wasm_runtime_common.h" +#include "bh_read_file.h" +#include "wasm_runtime.h" +#include "bh_platform.h" +#include "wasm_export.h" +#include "aot_runtime.h" + +using namespace std; + +extern "C" { +uint32 +wasm_runtime_module_realloc(WASMModuleInstanceCommon *module_inst, uint32 ptr, + uint32 size, void **p_native_addr); +bool +wasm_runtime_create_exec_env_and_call_wasm( + WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *function, + uint32 argc, uint32 argv[]); +} + +static bh_list loading_module_list_head; +static bh_list *const loading_module_list = &loading_module_list_head; +static korp_mutex loading_module_list_lock; + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static std::string MAIN_AOT = "/main.aot"; +static char *WASM_FILE_1; +static char *AOT_FILE_1; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +class wasm_runtime_common_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE_1 = strdup((CWD + MAIN_WASM).c_str()); + AOT_FILE_1 = strdup((CWD + MAIN_AOT).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + static void TearDownTestCase() + { + free(WASM_FILE_1); + free(AOT_FILE_1); + } + + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_destroy) +{ + wasm_runtime_init(); + wasm_runtime_destroy(); +} + +static bool +reader_test(package_type_t module_type, const char *module_name, + uint8 **p_buffer, uint32 *p_size) +{ + return true; +} + +static void +destroyer_test(uint8 *buffer, uint32 size) +{} + +TEST_F(wasm_runtime_common_test_suite, + set_module_reader_get_module_reader_get_module_destroyer) +{ + wasm_runtime_set_module_reader(reader_test, destroyer_test); + EXPECT_EQ((module_reader)reader_test, wasm_runtime_get_module_reader()); + EXPECT_EQ((module_destroyer)destroyer_test, + wasm_runtime_get_module_destroyer()); +} + +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_register_module) +{ + const char *wasm_file = WASM_FILE_1; + wasm_module_t wasm_module = nullptr; + unsigned char *wasm_file_buf = nullptr; + unsigned int wasm_file_size = 0; + char error_buf[128] = { 0 }; + char module_name[] = "module_test"; + char module_name_1[] = "module_test_1"; + + // Normal situation. + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + EXPECT_NE(false, + wasm_runtime_register_module("module_test", wasm_module, + error_buf, sizeof(error_buf))); + + // Abnormal situation. + EXPECT_EQ(false, + wasm_runtime_register_module(nullptr, nullptr, nullptr, 0)); + EXPECT_EQ(false, wasm_runtime_register_module( + "module_test", nullptr, error_buf, sizeof(error_buf))); + EXPECT_EQ(false, wasm_runtime_register_module("module_test", wasm_module, + nullptr, sizeof(error_buf))); + EXPECT_EQ(false, wasm_runtime_register_module("module_test", wasm_module, + error_buf, 0)); + EXPECT_EQ(false, wasm_runtime_register_module( + nullptr, wasm_module, error_buf, sizeof(error_buf))); + EXPECT_EQ(false, wasm_runtime_register_module(nullptr, nullptr, error_buf, + sizeof(error_buf))); + + EXPECT_EQ(true, wasm_runtime_register_module(module_name, wasm_module, + error_buf, sizeof(error_buf))); + EXPECT_EQ(false, wasm_runtime_register_module_internal(nullptr, wasm_module, + NULL, 0, error_buf, + sizeof(error_buf))); + EXPECT_EQ(false, wasm_runtime_register_module_internal( + module_name_1, wasm_module, NULL, 0, error_buf, + sizeof(error_buf))); +} + +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_unregister_module) +{ + wasm_runtime_unregister_module(nullptr); +} + +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_find_module_registered) +{ + EXPECT_EQ(nullptr, wasm_runtime_find_module_registered("module_test")); +} + +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_is_module_registered) +{ + EXPECT_EQ(nullptr, wasm_runtime_find_module_registered("")); +} + +/* TODO: add thread safety test. */ +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_add_loading_module) +{ + EXPECT_EQ(true, wasm_runtime_add_loading_module(nullptr, nullptr, 0)); +} + +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_destroy_loading_module_list) +{ + os_mutex_init(&loading_module_list_lock); + wasm_runtime_destroy_loading_module_list(); + os_mutex_destroy(&loading_module_list_lock); +} + +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_is_built_in_module) +{ + EXPECT_EQ(true, wasm_runtime_is_built_in_module("env")); + EXPECT_EQ(true, wasm_runtime_is_built_in_module("wasi_unstable")); + EXPECT_EQ(true, wasm_runtime_is_built_in_module("wasi_snapshot_preview1")); + EXPECT_EQ(true, wasm_runtime_is_built_in_module("")); + EXPECT_EQ(false, wasm_runtime_is_built_in_module("test")); +} + +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_read_v128) +{ + unsigned char buf[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + unsigned char ret1[8] = { 0 }; + unsigned char ret2[8] = { 0 }; + + wasm_runtime_read_v128((const uint8 *)buf, (uint64 *)ret1, (uint64 *)ret2); + EXPECT_EQ(0, strncmp("01234567", (const char *)ret1, 8)); + EXPECT_EQ(0, strncmp("89ABCDEF", (const char *)ret2, 8)); +} + +TEST_F(wasm_runtime_common_test_suite, + wasm_runtime_show_app_heap_corrupted_prompt) +{ + wasm_runtime_show_app_heap_corrupted_prompt(); +} + +TEST_F(wasm_runtime_common_test_suite, wasm_runtime_is_xip_file) +{ + // WASM file. + const char *wasm_file = WASM_FILE_1; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + EXPECT_EQ(false, wasm_runtime_is_xip_file(wasm_file_buf, wasm_file_size)); + + // AoT file. + const char *aot_file = AOT_FILE_1; + unsigned int aot_file_size = 0; + unsigned char *aot_file_buf = nullptr; + + aot_file_buf = + (unsigned char *)bh_read_file_to_buffer(aot_file, &aot_file_size); + EXPECT_NE(aot_file_buf, nullptr); + EXPECT_EQ(false, wasm_runtime_is_xip_file(aot_file_buf, aot_file_size)); +} + +TEST_F(wasm_runtime_common_test_suite, get_package_type) +{ + const char *wasm_file = WASM_FILE_1; + unsigned int wasm_file_size = 0; + unsigned char *wasm_file_buf = nullptr; + + // WASM file. + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + EXPECT_EQ(Wasm_Module_Bytecode, + get_package_type(wasm_file_buf, wasm_file_size)); + + // WASM file. Abnormally. + wasm_file_buf[3] = -1; + EXPECT_EQ(Package_Type_Unknown, + get_package_type(wasm_file_buf, wasm_file_size)); + wasm_file_buf[2] = -1; + EXPECT_EQ(Package_Type_Unknown, + get_package_type(wasm_file_buf, wasm_file_size)); + wasm_file_buf[1] = -1; + EXPECT_EQ(Package_Type_Unknown, + get_package_type(wasm_file_buf, wasm_file_size)); + wasm_file_buf[0] = -1; + EXPECT_EQ(Package_Type_Unknown, + get_package_type(wasm_file_buf, wasm_file_size)); + + EXPECT_EQ(Package_Type_Unknown, get_package_type(wasm_file_buf, 0)); + EXPECT_EQ(Package_Type_Unknown, get_package_type(nullptr, 0)); + + // AoT file. + const char *wasm_file_aot = AOT_FILE_1; + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file_aot, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + EXPECT_EQ(Wasm_Module_AoT, get_package_type(wasm_file_buf, wasm_file_size)); + + // AoT file. Abnormally. + wasm_file_buf[3] = -1; + EXPECT_EQ(Package_Type_Unknown, + get_package_type(wasm_file_buf, wasm_file_size)); + wasm_file_buf[2] = -1; + EXPECT_EQ(Package_Type_Unknown, + get_package_type(wasm_file_buf, wasm_file_size)); + wasm_file_buf[1] = -1; + EXPECT_EQ(Package_Type_Unknown, + get_package_type(wasm_file_buf, wasm_file_size)); + wasm_file_buf[0] = -1; + EXPECT_EQ(Package_Type_Unknown, + get_package_type(wasm_file_buf, wasm_file_size)); + + EXPECT_EQ(Package_Type_Unknown, get_package_type(wasm_file_buf, 0)); + EXPECT_EQ(Package_Type_Unknown, get_package_type(nullptr, 0)); +} + +TEST_F(wasm_runtime_common_test_suite, functions_on_wasm_module) +{ + const char *wasm_file = WASM_FILE_1; + wasm_module_inst_t wasm_module_inst = nullptr; + wasm_module_t wasm_module = nullptr; + wasm_exec_env_t exec_env = nullptr; + wasm_exec_env_t exec_env_1 = nullptr; + unsigned char *wasm_file_buf = nullptr; + WASMFunctionInstanceCommon *func = nullptr; + const char *user_data = "test"; + unsigned int wasm_file_size = 0; + unsigned int stack_size = 16 * 1024, heap_size = 16 * 1024; + char error_buf[128] = { 0 }; + unsigned int argv[2] = { 0 }; + WASMType *func_type = nullptr; + wasm_val_t arguments[1]; + char str_test[] = "This is a test."; + char str_exception[] = "Exception: "; + char str_tmp[60] = { 0 }; + void *ptr_tmp = nullptr; + unsigned int offset_tmp = 0; + unsigned int tmp = 0; + unsigned char *p_native_start_addr = nullptr; + unsigned char *p_native_end_addr = nullptr; + NativeSymbol *native_symbols; + uint32 n_native_symbols; + const char *exception_test = nullptr; + + arguments[0].kind = WASM_I32; + arguments[0].of.i32 = 0; + + // Create exec_env. + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + wasm_module_inst = wasm_runtime_instantiate( + wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf)); + EXPECT_NE(wasm_module_inst, nullptr); + exec_env = wasm_runtime_create_exec_env(wasm_module_inst, stack_size); + EXPECT_NE(exec_env, nullptr); + + // Operations on exec_env. + EXPECT_EQ(true, wasm_runtime_register_module_internal("test", wasm_module, + nullptr, 0, error_buf, + sizeof(error_buf))); + EXPECT_NE(nullptr, wasm_runtime_find_module_registered("test")); + EXPECT_EQ(wasm_module_inst, wasm_runtime_get_module_inst(exec_env)); + EXPECT_EQ(exec_env->attachment, + wasm_runtime_get_function_attachment(exec_env)); + EXPECT_EQ(wasm_module, wasm_exec_env_get_module(exec_env)); + + wasm_runtime_set_user_data(exec_env, (void *)user_data); + EXPECT_EQ((void *)user_data, wasm_runtime_get_user_data(exec_env)); + + func = wasm_runtime_lookup_function(wasm_module_inst, "on_timer_event"); + func_type = + wasm_runtime_get_function_type(func, wasm_module_inst->module_type); + EXPECT_NE(func_type, nullptr); + EXPECT_EQ(false, wasm_runtime_call_wasm(exec_env, func, 0, argv)); + exception_test = wasm_runtime_get_exception(wasm_module_inst); + EXPECT_NE(nullptr, exception_test); + + EXPECT_EQ(false, wasm_runtime_call_wasm_a(exec_env, func, 0, nullptr, 1, + arguments)); + exception_test = wasm_runtime_get_exception(wasm_module_inst); + EXPECT_NE(nullptr, exception_test); + + WASMFunctionInstance func_test_1; + WASMFunction wasm_func_test; + WASMType wasm_type_test; + wasm_func_test.func_type = &wasm_type_test; + func_test_1.u.func = &wasm_func_test; + func_test_1.u.func->func_type->param_count = 1; + func_test_1.u.func->func_type->param_cell_num = 2; + func_test_1.u.func->func_type->types[0] = VALUE_TYPE_I64; + func_test_1.u.func->max_stack_cell_num = 10; + EXPECT_EQ(false, wasm_runtime_call_wasm_v( + exec_env, (WASMFunctionInstanceCommon *)(&func_test_1), + 0, nullptr, 1, arguments)); + func_test_1.u.func->func_type->types[0] = VALUE_TYPE_F32; + EXPECT_EQ(false, wasm_runtime_call_wasm_v( + exec_env, (WASMFunctionInstanceCommon *)(&func_test_1), + 0, nullptr, 1, arguments)); + func_test_1.u.func->func_type->types[0] = VALUE_TYPE_F64; + EXPECT_EQ(false, wasm_runtime_call_wasm_v( + exec_env, (WASMFunctionInstanceCommon *)(&func_test_1), + 0, nullptr, 1, arguments)); + +#if 0 + WASMFunctionInstance func_test; + WASMFunctionImport func_import_test; + WASMType *func_type_1 = nullptr; + func_import_test.func_type = func_type; + func_test.u.func_import = &func_import_test; + func_test.is_import_func = true; + func_type_1 = wasm_runtime_get_function_type(&func_test, + wasm_module_inst->module_type); + EXPECT_NE(func_type_1, nullptr); +#endif + + EXPECT_EQ(true, wasm_runtime_create_exec_env_singleton(wasm_module_inst)); + EXPECT_NE(nullptr, wasm_runtime_get_exec_env_singleton(wasm_module_inst)); + + wasm_runtime_set_exception(wasm_module_inst, str_test); + sprintf(str_tmp, "%s%s", str_exception, str_test); + EXPECT_EQ(0, strcmp(str_tmp, wasm_runtime_get_exception(wasm_module_inst))); + wasm_runtime_clear_exception(wasm_module_inst); + EXPECT_EQ(nullptr, wasm_runtime_get_exception(wasm_module_inst)); + + wasm_runtime_set_custom_data(wasm_module_inst, (void *)user_data); + EXPECT_EQ((void *)user_data, + wasm_runtime_get_custom_data(wasm_module_inst)); + + offset_tmp = wasm_runtime_module_malloc(wasm_module_inst, 10, &ptr_tmp); + EXPECT_NE(0, offset_tmp); + EXPECT_EQ(true, + wasm_runtime_validate_app_addr(wasm_module_inst, offset_tmp, 10)); + EXPECT_EQ(ptr_tmp, + wasm_runtime_addr_app_to_native(wasm_module_inst, offset_tmp)); + EXPECT_EQ(true, + wasm_runtime_validate_native_addr(wasm_module_inst, ptr_tmp, 10)); + EXPECT_EQ(offset_tmp, + wasm_runtime_addr_native_to_app(wasm_module_inst, ptr_tmp)); + EXPECT_EQ(true, wasm_runtime_get_native_addr_range( + wasm_module_inst, (unsigned char *)ptr_tmp, + &p_native_start_addr, &p_native_end_addr)); + EXPECT_NE(0, wasm_runtime_module_realloc(wasm_module_inst, offset_tmp, 100, + &ptr_tmp)); + /* can't test like that since shrink size optimization will be applied */ + /* EXPECT_EQ(false, + wasm_enlarge_memory((WASMModuleInstance *)wasm_module_inst, 1)); + */ + EXPECT_EQ(offset_tmp, + wasm_runtime_addr_native_to_app(wasm_module_inst, ptr_tmp)); + EXPECT_EQ(true, wasm_runtime_get_native_addr_range( + wasm_module_inst, (unsigned char *)ptr_tmp, + &p_native_start_addr, &p_native_end_addr)); + + offset_tmp = wasm_runtime_module_dup_data(wasm_module_inst, str_test, + sizeof(str_test)); + EXPECT_EQ(0, strcmp(str_test, (char *)wasm_runtime_addr_app_to_native( + wasm_module_inst, offset_tmp))); + EXPECT_EQ(true, + wasm_runtime_validate_app_str_addr(wasm_module_inst, offset_tmp)); + + ((WASMModuleInstance *)wasm_module_inst)->exec_env_singleton = nullptr; + EXPECT_NE(nullptr, wasm_runtime_get_exec_env_singleton(wasm_module_inst)); + + EXPECT_EQ(false, wasm_runtime_call_wasm(nullptr, func, 0, argv)); + wasm_runtime_set_exception(wasm_module_inst, str_test); + EXPECT_EQ(false, wasm_runtime_call_wasm(exec_env, func, 0, argv)); + wasm_runtime_clear_exception(wasm_module_inst); + + EXPECT_EQ(false, wasm_runtime_call_wasm_a(exec_env, func, 0, nullptr, 2, + arguments)); + WASMFunctionInstance *func_test_call_wasm_a_ptr = + (WASMFunctionInstance *)func; + func_test_call_wasm_a_ptr->u.func->func_type->ret_cell_num = 10; + EXPECT_EQ(true, wasm_runtime_call_wasm_a(exec_env, func, 0, nullptr, 1, + arguments)); + + // Destroy. + wasm_runtime_module_free(wasm_module_inst, offset_tmp); + wasm_runtime_destroy_exec_env(exec_env); + wasm_runtime_deinstantiate(wasm_module_inst); + wasm_runtime_unload(wasm_module); + if (wasm_file_buf) { + wasm_runtime_free(wasm_file_buf); + } +} + +TEST_F(wasm_runtime_common_test_suite, functions_on_aot_module) +{ + const char *wasm_file = AOT_FILE_1; + wasm_module_inst_t wasm_module_inst = nullptr; + wasm_module_t wasm_module = nullptr; + wasm_exec_env_t exec_env = nullptr; + wasm_exec_env_t exec_env_1 = nullptr; + unsigned char *wasm_file_buf = nullptr; + WASMFunctionInstanceCommon *func = nullptr; + const char *user_data = "test"; + unsigned int wasm_file_size = 0; + unsigned int stack_size = 16 * 1024, heap_size = 16 * 1024; + char error_buf[128] = { 0 }; + unsigned int argv[2] = { 0 }; + WASMType *func_type = nullptr; + wasm_val_t arguments[1]; + char str_test[] = "This is a test."; + char str_exception[] = "Exception: "; + char str_tmp[60] = { 0 }; + void *ptr_tmp = nullptr; + unsigned int offset_tmp = 0; + unsigned int tmp = 0; + unsigned char *p_native_start_addr = nullptr; + unsigned char *p_native_end_addr = nullptr; + NativeSymbol *native_symbols; + uint32 n_native_symbols; + const char *exception_test = nullptr; + + arguments[0].kind = WASM_I32; + arguments[0].of.i32 = 0; + + // Create exec_env. + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + wasm_module_inst = wasm_runtime_instantiate( + wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf)); + EXPECT_NE(wasm_module_inst, nullptr); + exec_env = wasm_runtime_create_exec_env(wasm_module_inst, stack_size); + EXPECT_NE(exec_env, nullptr); + + // Operations on exec_env. + EXPECT_EQ(true, wasm_runtime_register_module_internal("test", wasm_module, + nullptr, 0, error_buf, + sizeof(error_buf))); + EXPECT_NE(nullptr, wasm_runtime_find_module_registered("test")); + EXPECT_EQ(wasm_module_inst, wasm_runtime_get_module_inst(exec_env)); + EXPECT_EQ(exec_env->attachment, + wasm_runtime_get_function_attachment(exec_env)); + EXPECT_EQ(wasm_module, wasm_exec_env_get_module(exec_env)); + + wasm_runtime_set_user_data(exec_env, (void *)user_data); + EXPECT_EQ((void *)user_data, wasm_runtime_get_user_data(exec_env)); + + func = wasm_runtime_lookup_function(wasm_module_inst, "on_timer_event"); + func_type = + wasm_runtime_get_function_type(func, wasm_module_inst->module_type); + EXPECT_NE(func_type, nullptr); + + EXPECT_EQ(false, wasm_runtime_call_wasm(exec_env, func, 0, argv)); + exception_test = wasm_runtime_get_exception(wasm_module_inst); + EXPECT_NE(nullptr, exception_test); + + EXPECT_EQ(false, wasm_runtime_call_wasm_a(exec_env, func, 0, nullptr, 1, + arguments)); + exception_test = wasm_runtime_get_exception(wasm_module_inst); + EXPECT_NE(nullptr, exception_test); + EXPECT_EQ(false, wasm_runtime_call_wasm_v(exec_env, func, 0, nullptr, 1, + arguments)); + exception_test = wasm_runtime_get_exception(wasm_module_inst); + EXPECT_NE(nullptr, exception_test); + + AOTFunctionInstance func_test; + AOTImportFunc func_import_test; + func_test.u.func_import = &func_import_test; + func_import_test.func_type = (AOTFuncType *)func_type; + func_test.is_import_func = true; + EXPECT_NE(nullptr, wasm_runtime_get_function_type( + &func_test, wasm_module_inst->module_type)); + + EXPECT_EQ(true, wasm_runtime_create_exec_env_singleton(wasm_module_inst)); + EXPECT_NE(nullptr, wasm_runtime_get_exec_env_singleton(wasm_module_inst)); + + wasm_runtime_set_exception(wasm_module_inst, str_test); + sprintf(str_tmp, "%s%s", str_exception, str_test); + EXPECT_EQ(0, strcmp(str_tmp, wasm_runtime_get_exception(wasm_module_inst))); + wasm_runtime_clear_exception(wasm_module_inst); + EXPECT_EQ(nullptr, wasm_runtime_get_exception(wasm_module_inst)); + + wasm_runtime_set_custom_data(wasm_module_inst, (void *)user_data); + EXPECT_EQ((void *)user_data, + wasm_runtime_get_custom_data(wasm_module_inst)); + + offset_tmp = wasm_runtime_module_malloc(wasm_module_inst, 10, &ptr_tmp); + EXPECT_NE(0, offset_tmp); + EXPECT_EQ(true, + wasm_runtime_validate_app_addr(wasm_module_inst, offset_tmp, 10)); + EXPECT_EQ(ptr_tmp, + wasm_runtime_addr_app_to_native(wasm_module_inst, offset_tmp)); + EXPECT_EQ(true, + wasm_runtime_validate_native_addr(wasm_module_inst, ptr_tmp, 10)); + EXPECT_EQ(offset_tmp, + wasm_runtime_addr_native_to_app(wasm_module_inst, ptr_tmp)); + EXPECT_EQ(true, wasm_runtime_get_native_addr_range( + wasm_module_inst, (unsigned char *)ptr_tmp, + &p_native_start_addr, &p_native_end_addr)); + EXPECT_NE(0, wasm_runtime_module_realloc(wasm_module_inst, offset_tmp, 100, + &ptr_tmp)); + + /* can't test like that since shrink size optimization will be applied */ + /* EXPECT_EQ(false, + wasm_enlarge_memory((WASMModuleInstance *)wasm_module_inst, 1)); + */ + + offset_tmp = wasm_runtime_module_dup_data(wasm_module_inst, str_test, + sizeof(str_test)); + EXPECT_EQ(0, strcmp(str_test, (char *)wasm_runtime_addr_app_to_native( + wasm_module_inst, offset_tmp))); + EXPECT_EQ(true, + wasm_runtime_validate_app_str_addr(wasm_module_inst, offset_tmp)); + + ((WASMModuleInstance *)wasm_module_inst)->exec_env_singleton = nullptr; + EXPECT_NE(nullptr, wasm_runtime_get_exec_env_singleton(wasm_module_inst)); + + // Destroy. + wasm_runtime_module_free(wasm_module_inst, offset_tmp); + wasm_runtime_destroy_exec_env(exec_env); + wasm_runtime_deinstantiate(wasm_module_inst); + wasm_runtime_unload(wasm_module); + if (wasm_file_buf) { + wasm_runtime_free(wasm_file_buf); + } +} + +TEST_F(wasm_runtime_common_test_suite, functions_on_module_type_unknown) +{ + const char *wasm_file = AOT_FILE_1; + wasm_module_inst_t wasm_module_inst = nullptr; + wasm_module_t wasm_module = nullptr; + wasm_exec_env_t exec_env = nullptr; + wasm_exec_env_t exec_env_1 = nullptr; + unsigned char *wasm_file_buf = nullptr; + WASMFunctionInstanceCommon *func = nullptr; + const char *user_data = "test"; + unsigned int wasm_file_size = 0; + unsigned int stack_size = 16 * 1024, heap_size = 16 * 1024; + char error_buf[128] = { 0 }; + unsigned int argv[2] = { 0 }; + WASMType *func_type = nullptr; + wasm_val_t arguments[1]; + char str_test[] = "This is a test."; + char str_exception[] = "Exception: "; + char str_tmp[60] = { 0 }; + void *ptr_tmp = nullptr; + unsigned int offset_tmp = 0; + unsigned int tmp = 0; + unsigned char *p_native_start_addr = nullptr; + unsigned char *p_native_end_addr = nullptr; + const char *exception_test = nullptr; + + arguments[0].kind = WASM_I32; + arguments[0].of.i32 = 0; + + // Create exec_env. + wasm_runtime_unregister_module(wasm_module); + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size); + EXPECT_NE(wasm_file_buf, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_NE(wasm_module, nullptr); + wasm_module_inst = wasm_runtime_instantiate( + wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf)); + EXPECT_NE(wasm_module_inst, nullptr); + exec_env = wasm_runtime_create_exec_env(wasm_module_inst, stack_size); + EXPECT_NE(exec_env, nullptr); + + // wasm_module_inst->module_type = Package_Type_Unknown. + wasm_module_inst->module_type = Package_Type_Unknown; + EXPECT_DEATH(wasm_exec_env_get_module(exec_env), ""); + EXPECT_DEATH( + wasm_runtime_validate_app_str_addr(wasm_module_inst, offset_tmp), ""); + + // wasm_module->module_type = Package_Type_Unknown. + wasm_module->module_type = Package_Type_Unknown; + EXPECT_EQ(nullptr, + wasm_runtime_instantiate(wasm_module, stack_size, heap_size, + error_buf, sizeof(error_buf))); + + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + /* Reload unmodified buffer should be valid now */ + EXPECT_NE(wasm_module, nullptr); + wasm_file_buf[3] = -1; + wasm_file_buf[2] = -1; + wasm_file_buf[1] = -1; + wasm_file_buf[0] = -1; + wasm_module = + wasm_runtime_load(wasm_file_buf, 0, error_buf, sizeof(error_buf)); + EXPECT_EQ(wasm_module, nullptr); + wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, + sizeof(error_buf)); + EXPECT_EQ(wasm_module, nullptr); + + // Destroy. + wasm_runtime_module_free(wasm_module_inst, offset_tmp); + wasm_runtime_destroy_exec_env(exec_env); + wasm_runtime_deinstantiate(wasm_module_inst); + wasm_runtime_unload(wasm_module); + if (wasm_file_buf) { + wasm_runtime_free(wasm_file_buf); + } +} diff --git a/tests/unit/runtime-common/wasm_runtime_init_test.cc b/tests/unit/runtime-common/wasm_runtime_init_test.cc new file mode 100644 index 0000000000..30e44cea31 --- /dev/null +++ b/tests/unit/runtime-common/wasm_runtime_init_test.cc @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "platform_common.h" +#include "wasm_runtime_common.h" +#include "bh_read_file.h" +#include "wasm_runtime.h" +#include "bh_platform.h" +#include "wasm_export.h" + +using namespace std; + +extern "C" { +uint32 +wasm_runtime_module_realloc(WASMModuleInstanceCommon *module_inst, uint32 ptr, + uint32 size, void **p_native_addr); +bool +wasm_runtime_create_exec_env_and_call_wasm( + WASMModuleInstanceCommon *module_inst, WASMFunctionInstanceCommon *function, + uint32 argc, uint32 argv[]); +} + +static char global_heap_buf[100 * 1024 * 1024] = { 0 }; + +static std::string CWD; +static std::string MAIN_WASM = "/main.wasm"; +static std::string MAIN_AOT = "/main.aot"; +static char *WASM_FILE_1; +static char *AOT_FILE_1; + +static int +foo(int a, int b); + +static int +foo_native(wasm_exec_env_t exec_env, int a, int b) +{ + return a + b; +} + +static NativeSymbol native_symbols[] = { { + "foo", // the name of WASM function name + (void *)foo_native, // the native function pointer + "(ii)i" // the function prototype signature +} }; + +static std::string +get_binary_path() +{ + char cwd[1024]; + memset(cwd, 0, 1024); + + if (readlink("/proc/self/exe", cwd, 1024) <= 0) { + } + + char *path_end = strrchr(cwd, '/'); + if (path_end != NULL) { + *path_end = '\0'; + } + + return std::string(cwd); +} + +class wasm_runtime_init_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + static void SetUpTestCase() + { + CWD = get_binary_path(); + WASM_FILE_1 = strdup((CWD + MAIN_WASM).c_str()); + AOT_FILE_1 = strdup((CWD + MAIN_AOT).c_str()); + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + static void TearDownTestCase() + { + free(WASM_FILE_1); + free(AOT_FILE_1); + } +}; + +TEST_F(wasm_runtime_init_test_suite, init_and_register_natives) +{ + EXPECT_EQ(true, wasm_runtime_init()); + int n_native_symbols = sizeof(native_symbols) / sizeof(NativeSymbol); + EXPECT_EQ(true, wasm_runtime_register_natives("env", native_symbols, + n_native_symbols)); + EXPECT_EQ(true, wasm_runtime_register_natives_raw("env", native_symbols, + n_native_symbols)); + wasm_runtime_destroy(); +} + +TEST_F(wasm_runtime_init_test_suite, init_thread_env_destroy_thread_env) +{ + EXPECT_EQ(true, wasm_runtime_init_thread_env()); + wasm_runtime_destroy_thread_env(); +} + +TEST_F(wasm_runtime_init_test_suite, wasm_runtime_full_init) +{ + RuntimeInitArgs init_args; + unsigned char *wasm_file_buf; + uint32 wasm_file_size; + wasm_module_t module = nullptr; + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + EXPECT_EQ(true, wasm_runtime_full_init(&init_args)); + wasm_runtime_destroy(); + init_args.n_native_symbols = 1; + EXPECT_EQ(true, wasm_runtime_full_init(&init_args)); + wasm_runtime_destroy(); + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = (void *)malloc; + init_args.mem_alloc_option.allocator.realloc_func = (void *)realloc; + init_args.mem_alloc_option.allocator.free_func = (void *)free; + EXPECT_EQ(true, wasm_runtime_full_init(&init_args)); + wasm_runtime_destroy(); + + 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; + EXPECT_EQ(true, wasm_runtime_full_init(&init_args)); + /* Use valid module, and runtime need to be proper inited */ + wasm_file_buf = + (unsigned char *)bh_read_file_to_buffer(WASM_FILE_1, &wasm_file_size); + EXPECT_NE(nullptr, wasm_file_buf); + module = wasm_runtime_load(wasm_file_buf, wasm_file_size, nullptr, 0); + EXPECT_NE(nullptr, module); + EXPECT_EQ(true, wasm_runtime_register_module_internal( + "module", module, wasm_file_buf, wasm_file_size, nullptr, 0)); + wasm_runtime_destroy(); + + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = NULL; + init_args.mem_alloc_option.pool.heap_size = 0; + EXPECT_EQ(false, wasm_runtime_full_init(&init_args)); +} diff --git a/tests/unit/shared-utils/CMakeLists.txt b/tests/unit/shared-utils/CMakeLists.txt new file mode 100644 index 0000000000..c5a43dd0e0 --- /dev/null +++ b/tests/unit/shared-utils/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-shared-utils) + +add_definitions (-DRUN_ON_LINUX) + +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 0) + +include (../unit_common.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${WAMR_RUNTIME_LIB_SOURCE} +) + +add_executable (shared_utils_test ${unit_test_sources}) + +target_link_libraries (shared_utils_test gtest_main) + +gtest_discover_tests(shared_utils_test) diff --git a/tests/unit/shared-utils/bh_assert_test.cc b/tests/unit/shared-utils/bh_assert_test.cc new file mode 100644 index 0000000000..faa7a807b9 --- /dev/null +++ b/tests/unit/shared-utils/bh_assert_test.cc @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_assert.h" + +class bh_assert_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} +}; + +TEST_F(bh_assert_test_suite, bh_assert_internal) +{ + bh_assert_internal(6, "file_name_test", 6, "expr_string_test"); + + // Test abnormal cases. + EXPECT_DEATH(bh_assert_internal(0, "file_name_test", 1, "expr_string_test"), + ""); + EXPECT_DEATH(bh_assert_internal(0, nullptr, 2, "expr_string_test"), ""); + EXPECT_DEATH(bh_assert_internal(0, "file_name_test", 3, nullptr), ""); +} diff --git a/tests/unit/shared-utils/bh_common_test.cc b/tests/unit/shared-utils/bh_common_test.cc new file mode 100644 index 0000000000..1d1cb528d7 --- /dev/null +++ b/tests/unit/shared-utils/bh_common_test.cc @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_common.h" + +class bh_common_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + public: + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +#define STR_TEST "test" + +TEST_F(bh_common_test_suite, wa_strdup) +{ + EXPECT_EQ(nullptr, wa_strdup(nullptr)); + EXPECT_NE(nullptr, wa_strdup(STR_TEST)); +} + +TEST_F(bh_common_test_suite, b_strcpy_s) +{ + char dest[10] = { 0 }; + + EXPECT_EQ(0, b_strcpy_s(dest, sizeof(dest), STR_TEST)); + + // Test abnormal cases. + EXPECT_EQ(-1, b_strcpy_s(nullptr, 0, nullptr)); + EXPECT_EQ(-1, b_strcpy_s(dest, sizeof(dest), nullptr)); + EXPECT_EQ(-1, b_strcpy_s(dest, 0, STR_TEST)); +} + +TEST_F(bh_common_test_suite, b_strcat_s) +{ + char dest[10] = { 0 }; + + EXPECT_EQ(0, b_strcat_s(dest, sizeof(dest), STR_TEST)); + + // Test abnormal cases. + EXPECT_EQ(-1, b_strcat_s(nullptr, 0, nullptr)); + EXPECT_EQ(-1, b_strcat_s(dest, sizeof(dest), nullptr)); + EXPECT_EQ(-1, b_strcat_s(dest, 0, STR_TEST)); +} + +TEST_F(bh_common_test_suite, bh_strdup) +{ + EXPECT_NE(nullptr, bh_strdup(STR_TEST)); + EXPECT_EQ(nullptr, bh_strdup(nullptr)); +} + +TEST_F(bh_common_test_suite, b_memmove_s) +{ + char dest[10] = { 0 }; + + EXPECT_EQ(0, b_memmove_s(dest, sizeof(dest), STR_TEST, sizeof(STR_TEST))); + + // Test abnormal cases. + EXPECT_EQ(0, b_memmove_s(dest, sizeof(dest), STR_TEST, 0)); + EXPECT_EQ(0, b_memmove_s(nullptr, sizeof(dest), STR_TEST, 0)); + + EXPECT_EQ(0, b_memmove_s(dest, sizeof(dest), nullptr, 0)); + EXPECT_EQ(-1, b_memmove_s(dest, sizeof(dest), STR_TEST, sizeof(dest) + 1)); +} + +TEST_F(bh_common_test_suite, b_memcpy_s) +{ + char dest[10] = { 0 }; + + EXPECT_EQ(0, b_memcpy_s(dest, sizeof(dest), STR_TEST, sizeof(STR_TEST))); + + // Test abnormal cases. + EXPECT_EQ(0, b_memcpy_s(dest, sizeof(dest), STR_TEST, 0)); + EXPECT_EQ(-1, + b_memcpy_s(nullptr, sizeof(dest), STR_TEST, sizeof(STR_TEST))); + EXPECT_EQ(-1, b_memcpy_s(dest, sizeof(dest), nullptr, sizeof(STR_TEST))); + EXPECT_EQ(-1, b_memcpy_s(dest, sizeof(dest), STR_TEST, sizeof(dest) + 1)); +} diff --git a/tests/unit/shared-utils/bh_hashmap_test.cc b/tests/unit/shared-utils/bh_hashmap_test.cc new file mode 100644 index 0000000000..4b651ef177 --- /dev/null +++ b/tests/unit/shared-utils/bh_hashmap_test.cc @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#include "test_helper.h" +#include "gtest/gtest.h" +#include "bh_hashmap.h" +#include "wasm.h" +#include "wasm_export.h" + +#include + +typedef struct HashMapElem { + void *key; + void *value; + struct HashMapElem *next; +} HashMapElem; + +struct HashMap { + /* size of element array */ + uint32 size; + /* lock for elements */ + korp_mutex *lock; + /* hash function of key */ + HashFunc hash_func; + /* key equal function */ + KeyEqualFunc key_equal_func; + KeyDestroyFunc key_destroy_func; + ValueDestroyFunc value_destroy_func; + HashMapElem *elements[1]; +}; + +int DESTROY_NUM = 0; +char TRAVERSE_KEY[] = "key_1"; +char TRAVERSE_VAL[] = "val_1"; +int TRAVERSE_COMP_RES = 0; + +class bh_hashmap_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + public: + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(bh_hashmap_test_suite, bh_hash_map_create) +{ + // Normally. + EXPECT_NE((HashMap *)nullptr, + bh_hash_map_create(32, true, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, nullptr, + wasm_runtime_free)); + + // Illegal parameters. + EXPECT_EQ((HashMap *)nullptr, + bh_hash_map_create(65537, true, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, nullptr, + wasm_runtime_free)); + EXPECT_EQ((HashMap *)nullptr, + bh_hash_map_create(65536, true, nullptr, nullptr, nullptr, + wasm_runtime_free)); + EXPECT_EQ((HashMap *)nullptr, + bh_hash_map_create(65536, true, (HashFunc)wasm_string_hash, + nullptr, nullptr, wasm_runtime_free)); +} + +TEST_F(bh_hashmap_test_suite, bh_hash_map_insert) +{ + HashMap *test_hash_map = bh_hash_map_create( + 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal, + nullptr, wasm_runtime_free); + int num = 0; + void **p_old_key = nullptr; + void **p_old_value = nullptr; + + // Normally. + EXPECT_EQ(true, bh_hash_map_insert(test_hash_map, (void *)"key_1", + (void *)"val_1")); + num++; + // Illegal parameters. + EXPECT_EQ(false, bh_hash_map_insert(nullptr, nullptr, (void *)"val_2")); + + // Execute fail: more than 32. + for (; num <= 32; num++) { + bh_hash_map_insert(test_hash_map, (void *)&num, (void *)"val"); + } + EXPECT_EQ(false, + bh_hash_map_insert(test_hash_map, (void *)&num, (void *)"val")); + + // Remove one, insert one. + bh_hash_map_remove(test_hash_map, (void *)"key_1", p_old_key, p_old_value); + EXPECT_EQ(true, bh_hash_map_insert(test_hash_map, (void *)"key_1", + (void *)"val_1")); +} + +TEST_F(bh_hashmap_test_suite, bh_hash_map_find) +{ + HashMap *test_hash_map = bh_hash_map_create( + 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal, + nullptr, wasm_runtime_free); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + + // Normally. use_lock is false. + EXPECT_NE((void *)nullptr, + bh_hash_map_find(test_hash_map, (void *)"key_1")); + + // Execute fail. + EXPECT_EQ((void *)nullptr, + bh_hash_map_find(test_hash_map, (void *)"KEY_1")); + + // Illegal parameters. + EXPECT_EQ((void *)nullptr, bh_hash_map_find(nullptr, nullptr)); + EXPECT_EQ((void *)nullptr, bh_hash_map_find(test_hash_map, nullptr)); + + // Normally. use_lock is true. + test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, nullptr, + wasm_runtime_free); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + EXPECT_EQ((void *)nullptr, + bh_hash_map_find(test_hash_map, (void *)"KEY_1")); +} + +TEST_F(bh_hashmap_test_suite, bh_hash_map_update) +{ + char old_value[10] = { 0 }; + void **p_old_value = (void **)(&old_value); + HashMap *test_hash_map = bh_hash_map_create( + 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal, + nullptr, wasm_runtime_free); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + + // test_hash_map->lock == nullptr. Normally. + EXPECT_EQ(true, bh_hash_map_update(test_hash_map, (void *)"key_1", + (void *)"val_2", p_old_value)); + // test_hash_map->lock == nullptr. Illegal parameters. + EXPECT_EQ(false, bh_hash_map_update(nullptr, nullptr, (void *)"val_2", + p_old_value)); + EXPECT_EQ(false, bh_hash_map_update(test_hash_map, nullptr, (void *)"val_2", + p_old_value)); + EXPECT_EQ(false, + bh_hash_map_update(nullptr, nullptr, (void *)"val_2", nullptr)); + + // test_hash_map->lock == nullptr. Update non-existent elements. + EXPECT_EQ(false, bh_hash_map_update(test_hash_map, (void *)"key", + (void *)"val", p_old_value)); + + test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, nullptr, + wasm_runtime_free); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + + // test_hash_map->lock == no nullptr. Normally. + EXPECT_EQ(true, bh_hash_map_update(test_hash_map, (void *)"key_1", + (void *)"val_2", p_old_value)); + // test_hash_map->lock == no nullptr. Illegal parameters. + EXPECT_EQ(false, bh_hash_map_update(nullptr, nullptr, (void *)"val_2", + p_old_value)); + EXPECT_EQ(false, bh_hash_map_update(test_hash_map, nullptr, (void *)"val_2", + p_old_value)); +} + +void +trav_callback_fun(void *key, void *value, void *user_data) +{ + if (!strncmp(TRAVERSE_VAL, (const char *)value, 5)) { + TRAVERSE_COMP_RES = 1; + } + else { + TRAVERSE_COMP_RES = 0; + } +} + +TEST_F(bh_hashmap_test_suite, bh_hash_map_traverse) +{ + void **p_old_value = nullptr; + HashMap *test_hash_map = bh_hash_map_create( + 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal, + nullptr, wasm_runtime_free); + + // Normally: TRAVERSE_COMP_RES = 1. + bh_hash_map_insert(test_hash_map, (void *)TRAVERSE_KEY, + (void *)TRAVERSE_VAL); + EXPECT_EQ(true, + bh_hash_map_traverse(test_hash_map, trav_callback_fun, nullptr)); + EXPECT_EQ(1, TRAVERSE_COMP_RES); + + // Normally: TRAVERSE_COMP_RES = 0. + bh_hash_map_update(test_hash_map, (void *)TRAVERSE_KEY, (void *)"val", + p_old_value); + EXPECT_EQ(true, + bh_hash_map_traverse(test_hash_map, trav_callback_fun, nullptr)); + EXPECT_EQ(0, TRAVERSE_COMP_RES); + // Illegal parameters. + EXPECT_EQ(false, bh_hash_map_traverse(nullptr, trav_callback_fun, nullptr)); + EXPECT_EQ(false, bh_hash_map_traverse(test_hash_map, nullptr, nullptr)); +} + +TEST_F(bh_hashmap_test_suite, bh_hash_map_remove) +{ + void **p_old_key = nullptr; + void **p_old_value = nullptr; + + HashMap *test_hash_map = bh_hash_map_create( + 32, false, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal, + nullptr, wasm_runtime_free); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2"); + + // test_hash_map->lock == nullptr. Normally. + EXPECT_EQ(true, bh_hash_map_remove(test_hash_map, (void *)"key_1", + p_old_key, p_old_value)); + // test_hash_map->lock == nullptr. Remove non-existent elements. + EXPECT_EQ(false, bh_hash_map_remove(test_hash_map, (void *)"key_1", + p_old_key, p_old_value)); + // test_hash_map->lock == nullptr. Illegal parameters. + EXPECT_EQ(false, bh_hash_map_remove(nullptr, (void *)"key_2", p_old_key, + p_old_value)); + EXPECT_EQ(false, bh_hash_map_remove(test_hash_map, nullptr, p_old_key, + p_old_value)); + + test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, nullptr, + wasm_runtime_free); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2"); + + // test_hash_map->lock == no nullptr. Normally. + EXPECT_EQ(true, bh_hash_map_remove(test_hash_map, (void *)"key_1", + p_old_key, p_old_value)); + // test_hash_map->lock == no nullptr. Illegal parameters. + EXPECT_EQ(false, bh_hash_map_remove(nullptr, (void *)"key_2", p_old_key, + p_old_value)); +} + +TEST_F(bh_hashmap_test_suite, bh_hash_map_get_struct_size) +{ + HashMap *test_hash_map = nullptr; + uint32 size = 0; + + // No lock. + test_hash_map = bh_hash_map_create(32, false, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, nullptr, + wasm_runtime_free); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + size = (size_t)(&((HashMap *)0)->elements) + + (uint32)sizeof(HashMapElem *) * test_hash_map->size; + EXPECT_EQ(size, bh_hash_map_get_struct_size(test_hash_map)); + + // Has lock. + test_hash_map = bh_hash_map_create(32, true, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, nullptr, + wasm_runtime_free); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + size = (size_t)(&((HashMap *)0)->elements) + + (uint32)sizeof(HashMapElem *) * test_hash_map->size; + size += (uint32)sizeof(korp_mutex); + EXPECT_EQ(size, bh_hash_map_get_struct_size(test_hash_map)); +} + +TEST_F(bh_hashmap_test_suite, bh_hash_map_get_elem_struct_size) +{ + EXPECT_EQ((uint32)sizeof(HashMapElem), bh_hash_map_get_elem_struct_size()); +} + +void +destroy_func_test(void *key) +{ + DESTROY_NUM++; +} + +TEST_F(bh_hashmap_test_suite, bh_hash_map_destroy) +{ + HashMap *test_hash_map = bh_hash_map_create( + 32, true, (HashFunc)wasm_string_hash, (KeyEqualFunc)wasm_string_equal, + destroy_func_test, wasm_runtime_free); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2"); + + // test_hash_map->lock == no nullptr. Normally. + EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map)); + // key_destroy_func must be called 2 times. + EXPECT_EQ(2, DESTROY_NUM); + + test_hash_map = bh_hash_map_create(32, false, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, + destroy_func_test, wasm_runtime_free); + + // test_hash_map->lock == no nullptr. Illegal parameters. + EXPECT_EQ(false, bh_hash_map_destroy(nullptr)); + // test_hash_map->lock == nullptr. + EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map)); + + // key_destroy_func and value_destroy_func is nullptr. + test_hash_map = + bh_hash_map_create(32, false, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, nullptr, nullptr); + bh_hash_map_insert(test_hash_map, (void *)"key_1", (void *)"val_1"); + bh_hash_map_insert(test_hash_map, (void *)"key_2", (void *)"val_2"); + EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map)); +} + +// This fun allows inserting the same keys. +bool +string_equal_test(const char *s1, const char *s2) +{ + return false; +} + +int COUNT_ELEM = 0; + +void +fun_count_elem(void *key, void *value, void *user_data) +{ + COUNT_ELEM++; +} + +TEST_F(bh_hashmap_test_suite, bh_hashmap_thread_safety) +{ + HashMap *test_hash_map = bh_hash_map_create( + 32, true, (HashFunc)wasm_string_hash, (KeyEqualFunc)string_equal_test, + destroy_func_test, wasm_runtime_free); + int32_t i = 0; + std::vector> threads; + + // Creat 8 threads. In every thread, run the codes in brackets of + // std::async. + for (i = 0; i < 8; i++) { + threads.push_back(std::async([&] { + for (int j = 0; j < 25; j++) { + bh_hash_map_insert(test_hash_map, (void *)"key_1", + (void *)"val_1"); + } + })); + } + + // Wait all 8 threads finished. + for (auto &t : threads) { + t.wait(); + } + + // Count hash map elements. + bh_hash_map_traverse(test_hash_map, fun_count_elem, nullptr); + + EXPECT_EQ(200, COUNT_ELEM); + EXPECT_EQ(true, bh_hash_map_destroy(test_hash_map)); +} \ No newline at end of file diff --git a/tests/unit/shared-utils/bh_list_test.cc b/tests/unit/shared-utils/bh_list_test.cc new file mode 100644 index 0000000000..981c52f253 --- /dev/null +++ b/tests/unit/shared-utils/bh_list_test.cc @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" + +#include "test_helper.h" +#include "gtest/gtest.h" + +class bh_list_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + public: + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(bh_list_test_suite, bh_list_init) +{ + bh_list list_test; + + // Normally. + EXPECT_EQ(BH_LIST_SUCCESS, bh_list_init(&list_test)); + + // Illegal parameters. + EXPECT_EQ(BH_LIST_ERROR, bh_list_init(nullptr)); +} + +TEST_F(bh_list_test_suite, bh_list_insert) +{ + bh_list list_test; + bh_list_link elem_insert; + + // Normally. + bh_list_init(&list_test); + EXPECT_EQ(BH_LIST_SUCCESS, bh_list_insert(&list_test, &elem_insert)); + + // Illegal parameters. + EXPECT_EQ(BH_LIST_ERROR, bh_list_insert(nullptr, nullptr)); + EXPECT_EQ(BH_LIST_ERROR, bh_list_insert(&list_test, nullptr)); +} + +TEST_F(bh_list_test_suite, bh_list_remove) +{ + bh_list list_test; + bh_list_link elem_insert_1; + bh_list_link elem_insert_2; + bh_list_link elem_insert_3; + bh_list_link elem_insert_4; + + // Normally. + bh_list_init(&list_test); + bh_list_insert(&list_test, &elem_insert_1); + bh_list_insert(&list_test, &elem_insert_2); + bh_list_insert(&list_test, &elem_insert_3); + bh_list_insert(&list_test, &elem_insert_4); + EXPECT_EQ(BH_LIST_SUCCESS, bh_list_remove(&list_test, &elem_insert_1)); + + // The elem specified by prameter is not in the list. + EXPECT_EQ(BH_LIST_ERROR, bh_list_remove(&list_test, &elem_insert_1)); + + // Illegal parameters. + EXPECT_EQ(BH_LIST_ERROR, bh_list_remove(&list_test, nullptr)); + EXPECT_EQ(BH_LIST_ERROR, bh_list_remove(nullptr, nullptr)); + EXPECT_EQ(BH_LIST_ERROR, bh_list_remove(nullptr, &elem_insert_1)); +} + +TEST_F(bh_list_test_suite, bh_list_length) +{ + bh_list list_test; + bh_list_link elem_insert_1; + bh_list_link elem_insert_2; + + bh_list_init(&list_test); + + // The length is 0. + EXPECT_EQ(0, bh_list_length(&list_test)); + + // The length is 2. + bh_list_insert(&list_test, &elem_insert_1); + bh_list_insert(&list_test, &elem_insert_2); + EXPECT_EQ(2, bh_list_length(&list_test)); + + // Illegal parameters. + EXPECT_EQ(0, bh_list_length(nullptr)); +} + +TEST_F(bh_list_test_suite, bh_list_first_elem) +{ + bh_list list_test; + bh_list_link elem_insert_1; + bh_list_link elem_insert_2; + + bh_list_init(&list_test); + + // There is no element in the list. + EXPECT_EQ(nullptr, bh_list_first_elem(&list_test)); + + // There are 2 elements in the list. + bh_list_insert(&list_test, &elem_insert_1); + bh_list_insert(&list_test, &elem_insert_2); + EXPECT_EQ(&elem_insert_2, bh_list_first_elem(&list_test)); + + // Illegal parameters. + EXPECT_EQ(nullptr, bh_list_first_elem(nullptr)); +} + +TEST_F(bh_list_test_suite, bh_list_elem_next) +{ + bh_list list_test; + bh_list_link elem_insert_1; + bh_list_link elem_insert_2; + + bh_list_init(&list_test); + bh_list_insert(&list_test, &elem_insert_1); + bh_list_insert(&list_test, &elem_insert_2); + + // Normally. + EXPECT_EQ(&elem_insert_1, bh_list_elem_next(&elem_insert_2)); + + // Illegal parameters. + EXPECT_EQ(nullptr, bh_list_elem_next(nullptr)); +} diff --git a/tests/unit/shared-utils/bh_log_test.cc b/tests/unit/shared-utils/bh_log_test.cc new file mode 100644 index 0000000000..250fb79268 --- /dev/null +++ b/tests/unit/shared-utils/bh_log_test.cc @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_log.h" +#include "stdio.h" + +class bh_log_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} +}; + +#define TEST_STR "This is a test." + +TEST_F(bh_log_test_suite, bh_log_set_verbose_level) +{ + bh_log_set_verbose_level(BH_LOG_LEVEL_DEBUG); +} + +TEST_F(bh_log_test_suite, bh_print_time) +{ + std::string captured; + + bh_log_set_verbose_level(BH_LOG_LEVEL_WARNING); + bh_print_time(TEST_STR); + + bh_log_set_verbose_level(BH_LOG_LEVEL_DEBUG); + testing::internal::CaptureStdout(); + bh_print_time(TEST_STR); + captured = testing::internal::GetCapturedStdout(); + EXPECT_EQ(0, strncmp(TEST_STR, captured.c_str(), strlen(TEST_STR))); + + testing::internal::CaptureStdout(); + bh_print_time(TEST_STR); + captured = testing::internal::GetCapturedStdout(); + EXPECT_EQ(0, strncmp(TEST_STR, captured.c_str(), strlen(TEST_STR))); +} + +TEST_F(bh_log_test_suite, bh_log) +{ + std::string captured; + + bh_log_set_verbose_level(BH_LOG_LEVEL_DEBUG); + testing::internal::CaptureStdout(); + bh_log(BH_LOG_LEVEL_FATAL, __FILE__, __LINE__, TEST_STR); + captured = testing::internal::GetCapturedStdout(); + EXPECT_PRED_FORMAT2(::testing::IsSubstring, TEST_STR, captured); + + testing::internal::CaptureStdout(); + bh_log(BH_LOG_LEVEL_ERROR, __FILE__, __LINE__, TEST_STR); + captured = testing::internal::GetCapturedStdout(); + EXPECT_PRED_FORMAT2(::testing::IsSubstring, TEST_STR, captured); + + testing::internal::CaptureStdout(); + bh_log(BH_LOG_LEVEL_WARNING, __FILE__, __LINE__, TEST_STR); + captured = testing::internal::GetCapturedStdout(); + EXPECT_PRED_FORMAT2(::testing::IsSubstring, TEST_STR, captured); + + testing::internal::CaptureStdout(); + bh_log(BH_LOG_LEVEL_DEBUG, __FILE__, __LINE__, TEST_STR); + captured = testing::internal::GetCapturedStdout(); + EXPECT_PRED_FORMAT2(::testing::IsSubstring, TEST_STR, captured); + + // log_verbose_level == BH_LOG_LEVEL_DEBUG, so BH_LOG_LEVEL_VERBOSE is not + // printed. + testing::internal::CaptureStdout(); + bh_log(BH_LOG_LEVEL_VERBOSE, __FILE__, __LINE__, TEST_STR); + captured = testing::internal::GetCapturedStdout(); + EXPECT_EQ(nullptr, strstr(captured.c_str(), TEST_STR)); + + // After set log_verbose_level = BH_LOG_LEVEL_VERBOSE, BH_LOG_LEVEL_VERBOSE + // can be printed. + bh_log_set_verbose_level(BH_LOG_LEVEL_VERBOSE); + testing::internal::CaptureStdout(); + bh_log(BH_LOG_LEVEL_VERBOSE, __FILE__, __LINE__, TEST_STR); + captured = testing::internal::GetCapturedStdout(); + EXPECT_PRED_FORMAT2(::testing::IsSubstring, TEST_STR, captured); +} diff --git a/tests/unit/shared-utils/bh_queue_test.cc b/tests/unit/shared-utils/bh_queue_test.cc new file mode 100644 index 0000000000..c540d8f36c --- /dev/null +++ b/tests/unit/shared-utils/bh_queue_test.cc @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" + +#include "bh_platform.h" + +class bh_queue_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + public: + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +typedef struct bh_queue_node { + struct bh_queue_node *next; + struct bh_queue_node *prev; + unsigned short tag; + unsigned int len; + void *body; + bh_msg_cleaner msg_cleaner; +} bh_queue_node; + +struct bh_queue { + bh_queue_mutex queue_lock; + bh_queue_cond queue_wait_cond; + unsigned int cnt; + unsigned int max; + unsigned int drops; + bh_queue_node *head; + bh_queue_node *tail; + + bool exit_loop_run; +}; + +typedef enum LINK_MSG_TYPE { + COAP_TCP_RAW = 0, + COAP_UDP_RAW = 1, + REQUEST_PACKET, + RESPONSE_PACKET, + INSTALL_WASM_APP, + CBOR_GENERIC = 30, + + LINK_MSG_TYPE_MAX = 50 +} LINK_MSG_TYPE; + +typedef enum QUEUE_MSG_TYPE { + COAP_PARSED = LINK_MSG_TYPE_MAX + 1, + RESTFUL_REQUEST, + RESTFUL_RESPONSE, + TIMER_EVENT = 5, + SENSOR_EVENT = 6, + GPIO_INTERRUPT_EVENT = 7, + BLE_EVENT = 8, + JDWP_REQUEST = 9, + WD_TIMEOUT = 10, + BASE_EVENT_MAX = 100 + +} QUEUE_MSG_TYPE; + +enum { + WASM_Msg_Start = BASE_EVENT_MAX, + TIMER_EVENT_WASM, + SENSOR_EVENT_WASM, + CONNECTION_EVENT_WASM, + WIDGET_EVENT_WASM, + WASM_Msg_End = WASM_Msg_Start + 100 +}; + +// If RES_CMP == 1, the function bh_queue_enter_loop_run run error. +int RES_CMP = 0; + +TEST_F(bh_queue_test_suite, bh_queue_create) +{ + EXPECT_NE(nullptr, bh_queue_create()); +} + +TEST_F(bh_queue_test_suite, bh_queue_destroy) +{ + bh_message_t msg_ptr; + bh_queue *queue_ptr = bh_queue_create(); + + // Normally. + msg_ptr = bh_new_msg(RESTFUL_REQUEST, nullptr, 0, nullptr); + bh_post_msg2(queue_ptr, msg_ptr); + bh_queue_destroy(queue_ptr); + EXPECT_EQ(nullptr, queue_ptr->head); + + // Illegal parameters. + bh_queue_destroy(nullptr); +} + +TEST_F(bh_queue_test_suite, bh_message_payload) +{ + bh_message_t msg_ptr; + + msg_ptr = bh_new_msg(RESTFUL_REQUEST, (void *)"test_msg_body", + sizeof("test_msg_body"), nullptr); + EXPECT_EQ("test_msg_body", bh_message_payload(msg_ptr)); +} + +TEST_F(bh_queue_test_suite, bh_message_payload_len) +{ + bh_message_t msg_ptr; + + msg_ptr = bh_new_msg(RESTFUL_REQUEST, (void *)"test_msg_body", + sizeof("test_msg_body"), nullptr); + EXPECT_EQ(sizeof("test_msg_body"), bh_message_payload_len(msg_ptr)); +} + +TEST_F(bh_queue_test_suite, bh_message_type) +{ + bh_message_t msg_ptr; + + msg_ptr = bh_new_msg(RESTFUL_REQUEST, (void *)"test_msg_body", + sizeof("test_msg_body"), nullptr); + EXPECT_EQ(RESTFUL_REQUEST, bh_message_type(msg_ptr)); +} + +TEST_F(bh_queue_test_suite, bh_new_msg) +{ + EXPECT_NE(nullptr, bh_new_msg(RESTFUL_REQUEST, (void *)"test_msg_body", + sizeof("test_msg_body"), nullptr)); +} + +void +msg_cleaner_test(void *) +{ + return; +} + +TEST_F(bh_queue_test_suite, bh_free_msg) +{ + bh_message_t msg_ptr; + + msg_ptr = bh_new_msg(RESTFUL_REQUEST, (void *)"test_msg_body", + sizeof("test_msg_body"), (void *)msg_cleaner_test); + bh_free_msg(msg_ptr); + + msg_ptr = bh_new_msg(RESTFUL_REQUEST, (void *)"test_msg_body", + sizeof("test_msg_body"), nullptr); + bh_free_msg(msg_ptr); + + msg_ptr = bh_new_msg(RESTFUL_REQUEST, (void *)(uintptr_t)100, 0, nullptr); + bh_free_msg(msg_ptr); +} + +TEST_F(bh_queue_test_suite, bh_post_msg) +{ + int i = 0; + bh_queue *queue_ptr = bh_queue_create(); + bh_message_t msg_ptr; + + EXPECT_EQ(true, bh_post_msg(queue_ptr, TIMER_EVENT_WASM, nullptr, 0)); + EXPECT_EQ(1, queue_ptr->cnt); + + // queue_ptr->cnt >= queue_ptr->max. + msg_ptr = bh_new_msg(RESTFUL_REQUEST, (void *)"test_msg_body", + sizeof("test_msg_body"), nullptr); + for (i = 1; i <= 50; i++) { + bh_post_msg2(queue_ptr, msg_ptr); + } + EXPECT_EQ(false, bh_post_msg(queue_ptr, TIMER_EVENT_WASM, nullptr, 0)); +} + +TEST_F(bh_queue_test_suite, bh_post_msg2) +{ + bh_message_t msg_ptr; + bh_queue *queue_ptr = bh_queue_create(); + + msg_ptr = bh_new_msg(RESTFUL_REQUEST, nullptr, 0, nullptr); + EXPECT_EQ(true, bh_post_msg2(queue_ptr, msg_ptr)); + EXPECT_EQ(1, queue_ptr->cnt); +} + +TEST_F(bh_queue_test_suite, bh_get_msg) +{ + bh_message_t msg_ptr; + bh_queue *queue_ptr = bh_queue_create(); + + msg_ptr = bh_new_msg(RESTFUL_REQUEST, (void *)"test_msg_body", + sizeof("test_msg_body"), nullptr); + + // queue->cnt == 0, timeout_us == 0. + EXPECT_EQ(nullptr, bh_get_msg(queue_ptr, 0)); + // queue->cnt == 0, timeout_us != 0. + bh_get_msg(queue_ptr, 1); + + bh_post_msg2(queue_ptr, msg_ptr); + EXPECT_EQ(1, queue_ptr->cnt); + bh_get_msg(queue_ptr, -1); + EXPECT_EQ(0, queue_ptr->cnt); +} + +TEST_F(bh_queue_test_suite, bh_queue_get_message_count) +{ + int i = 0, j = 0; + bh_message_t msg_ptr; + bh_queue *queue_ptr = bh_queue_create(); + + // Normally. + msg_ptr = bh_new_msg(RESTFUL_REQUEST, (void *)"test_msg_body", + sizeof("test_msg_body"), nullptr); + for (i = 1; i <= 20; i++) { + bh_post_msg2(queue_ptr, msg_ptr); + } + i = i - 1; + // The count of msg is less than queue_ptr->max. + EXPECT_EQ(i, bh_queue_get_message_count(queue_ptr)); + + // The count of msg is more than queue_ptr->max. + for (j = 1; j <= 60; j++) { + bh_post_msg2(queue_ptr, msg_ptr); + } + j = j - 1; + EXPECT_EQ(queue_ptr->max, bh_queue_get_message_count(queue_ptr)); + EXPECT_EQ(j + i - queue_ptr->max, queue_ptr->drops); + + // Illegal parameters. + EXPECT_EQ(0, bh_queue_get_message_count(nullptr)); +} + +void +bh_queue_enter_loop_run_test_fun(void *message, void *arg) +{ + static int count = 0; + RES_CMP = + strncmp("test_queue_loop", (char *)((bh_message_t)message)->body, 15); + + count++; + if (2 == count) { + bh_queue_exit_loop_run((bh_queue *)arg); + } +} + +TEST_F(bh_queue_test_suite, bh_queue_enter_loop_run) +{ + bh_queue *queue_ptr = bh_queue_create(); + bh_message_t msg_ptr1 = + bh_new_msg(RESTFUL_REQUEST, (void *)"test_queue_loop", + sizeof("test_queue_loop"), nullptr); + bh_message_t msg_ptr2 = + bh_new_msg(RESTFUL_REQUEST, (void *)"test_queue_loop", + sizeof("test_queue_loop"), nullptr); + + bh_post_msg2(queue_ptr, msg_ptr1); + bh_post_msg2(queue_ptr, msg_ptr2); + bh_queue_enter_loop_run(queue_ptr, bh_queue_enter_loop_run_test_fun, + queue_ptr); + EXPECT_EQ(0, RES_CMP); + + // Illegal parameters. + bh_queue_enter_loop_run(nullptr, bh_queue_enter_loop_run_test_fun, + queue_ptr); +} + +TEST_F(bh_queue_test_suite, bh_queue_exit_loop_run) +{ + // Illegal parameters. + bh_queue_exit_loop_run(nullptr); +} \ No newline at end of file diff --git a/tests/unit/shared-utils/bh_vector_test.cc b/tests/unit/shared-utils/bh_vector_test.cc new file mode 100644 index 0000000000..3da9fba5d7 --- /dev/null +++ b/tests/unit/shared-utils/bh_vector_test.cc @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "test_helper.h" +#include "gtest/gtest.h" +#include "bh_platform.h" + +#include + +class bh_vector_test_suite : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + public: + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +static inline void * +malloc_internal(uint64 size); + +TEST_F(bh_vector_test_suite, bh_vector_init) +{ + Vector *vector_ptr = nullptr; + + // Normally. use_lock is true. + vector_ptr = (Vector *)wasm_runtime_malloc(sizeof(Vector)); + memset(vector_ptr, 0, sizeof(Vector)); + EXPECT_EQ(true, bh_vector_init(vector_ptr, 6, sizeof(Vector *), true)); + // use_lock is false. + EXPECT_EQ(true, bh_vector_init(vector_ptr, 6, sizeof(Vector *), false)); + // init_length == 0. + EXPECT_EQ(true, bh_vector_init(vector_ptr, 0, sizeof(Vector *), false)); + // size_elem > UINT32_MAX. + EXPECT_EQ(true, bh_vector_init(vector_ptr, 6, UINT32_MAX + 1, false)); + // init_length > UINT32_MAX. + EXPECT_EQ(true, bh_vector_init(vector_ptr, UINT32_MAX + 1, sizeof(Vector *), + false)); + + // Illegal parameters. + EXPECT_EQ(false, bh_vector_init(nullptr, 6, sizeof(Vector *), true)); +} + +TEST_F(bh_vector_test_suite, bh_vector_set) +{ + Vector *vector_ptr = nullptr; + char elem_buf[] = "test_vector"; + + vector_ptr = (Vector *)wasm_runtime_malloc(sizeof(Vector)); + memset(vector_ptr, 0, sizeof(Vector)); + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), true); + bh_vector_append(vector_ptr, "test"); + + // Normally. use_lock is true. + EXPECT_EQ(true, bh_vector_set(vector_ptr, 0, elem_buf)); + + // Illegal parameters: nullptr. + EXPECT_EQ(false, bh_vector_set(nullptr, 0, nullptr)); + EXPECT_EQ(false, bh_vector_set(vector_ptr, 0, nullptr)); + // Illegal parameters: index >= vector->num_elems. + EXPECT_EQ(false, bh_vector_set(vector_ptr, 1, elem_buf)); + + // Normally. use_lock is false. + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), false); + bh_vector_append(vector_ptr, "test"); + EXPECT_EQ(true, bh_vector_set(vector_ptr, 0, elem_buf)); +} + +TEST_F(bh_vector_test_suite, bh_vector_get) +{ + Vector *vector_ptr = nullptr; + char elem_buf[] = "test_vector"; + char get_elem[12] = { 0 }; + + vector_ptr = (Vector *)wasm_runtime_malloc(sizeof(Vector)); + memset(vector_ptr, 0, sizeof(Vector)); + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), true); + bh_vector_append(vector_ptr, elem_buf); + + // Normally. use_lock is true. + EXPECT_EQ(true, bh_vector_get(vector_ptr, 0, get_elem)); + EXPECT_EQ(0, strncmp(elem_buf, get_elem, 11)); + + // Illegal parameters: nullptr. + EXPECT_EQ(false, bh_vector_get(nullptr, 0, nullptr)); + EXPECT_EQ(false, bh_vector_get(vector_ptr, 0, nullptr)); + // Illegal parameters: index >= vector->num_elems. + EXPECT_EQ(false, bh_vector_get(vector_ptr, 1, get_elem)); + + // Normally. use_lock is false. + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), false); + bh_vector_append(vector_ptr, elem_buf); + EXPECT_EQ(true, bh_vector_get(vector_ptr, 0, get_elem)); + EXPECT_EQ(0, strncmp(elem_buf, get_elem, 11)); +} + +TEST_F(bh_vector_test_suite, bh_vector_insert) +{ + Vector *vector_ptr = nullptr; + char elem_buf[] = "test_vector"; + char get_elem[12] = { 0 }; + + vector_ptr = (Vector *)wasm_runtime_malloc(sizeof(Vector)); + memset(vector_ptr, 0, sizeof(Vector)); + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), true); + bh_vector_append(vector_ptr, "test"); + bh_vector_append(vector_ptr, "test"); + bh_vector_append(vector_ptr, "test"); + bh_vector_append(vector_ptr, "test"); + + // Normally. + EXPECT_EQ(true, bh_vector_insert(vector_ptr, 0, elem_buf)); + bh_vector_get(vector_ptr, 1, get_elem); + EXPECT_EQ(0, strncmp(elem_buf, get_elem, 11)); + + EXPECT_EQ(true, bh_vector_insert(vector_ptr, 2, elem_buf)); + EXPECT_EQ(true, bh_vector_insert(vector_ptr, 5, elem_buf)); + + // Illegal parameters: nullptr. + EXPECT_EQ(false, bh_vector_insert(nullptr, 0, nullptr)); + EXPECT_EQ(false, bh_vector_insert(vector_ptr, 0, nullptr)); + EXPECT_EQ(0, strncmp(elem_buf, get_elem, 0)); + // Illegal parameters: index >= vector->num_elems. + EXPECT_EQ(false, bh_vector_insert(vector_ptr, 10, elem_buf)); + + // "if (!extend_vector(vector, vector->num_elems + 1))" == true. + vector_ptr->num_elems = UINT32_MAX + 1; + EXPECT_EQ(false, bh_vector_insert(vector_ptr, 2, elem_buf)); + + // use_lock is false. + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), false); + bh_vector_append(vector_ptr, "test"); + EXPECT_EQ(true, bh_vector_insert(vector_ptr, 0, elem_buf)); +} + +TEST_F(bh_vector_test_suite, bh_vector_append) +{ + Vector *vector_ptr = nullptr; + char elem_buf[] = "test_vector"; + char get_elem[12] = { 0 }; + + vector_ptr = (Vector *)wasm_runtime_malloc(sizeof(Vector)); + memset(vector_ptr, 0, sizeof(Vector)); + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), true); + + // Normally. + EXPECT_EQ(true, bh_vector_append(vector_ptr, elem_buf)); + bh_vector_get(vector_ptr, 0, get_elem); + EXPECT_EQ(0, strncmp(elem_buf, get_elem, 11)); + + // Illegal parameters: nullptr. + EXPECT_EQ(false, bh_vector_append(nullptr, nullptr)); + EXPECT_EQ(false, bh_vector_append(vector_ptr, nullptr)); +} + +TEST_F(bh_vector_test_suite, bh_vector_remove) +{ + Vector *vector_ptr = nullptr; + char elem_buf[] = "test_vector"; + char old_elem[12] = { 0 }; + + vector_ptr = (Vector *)wasm_runtime_malloc(sizeof(Vector)); + memset(vector_ptr, 0, sizeof(Vector)); + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), true); + bh_vector_append(vector_ptr, elem_buf); + bh_vector_append(vector_ptr, elem_buf); + bh_vector_append(vector_ptr, elem_buf); + bh_vector_append(vector_ptr, elem_buf); + + // Normally. + // Remove the first one. + EXPECT_EQ(true, bh_vector_remove(vector_ptr, 0, old_elem)); + // Remove the middle one. + EXPECT_EQ(true, bh_vector_remove(vector_ptr, 2, old_elem)); + // Remove the last one. + EXPECT_EQ(true, bh_vector_remove(vector_ptr, 1, old_elem)); + + EXPECT_EQ(true, bh_vector_remove(vector_ptr, 0, nullptr)); + + // Illegal parameters: nullptr. + EXPECT_EQ(false, bh_vector_remove(nullptr, 0, nullptr)); + EXPECT_EQ(false, bh_vector_remove(vector_ptr, 0, nullptr)); + // Illegal parameters: index >= vector->num_elems. + EXPECT_EQ(false, bh_vector_remove(vector_ptr, 1, old_elem)); + + // use_lock is false. + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), false); + bh_vector_append(vector_ptr, elem_buf); + EXPECT_EQ(true, bh_vector_remove(vector_ptr, 0, old_elem)); +} + +TEST_F(bh_vector_test_suite, bh_vector_size) +{ + Vector *vector_ptr = nullptr; + char elem_buf[] = "test_vector"; + + vector_ptr = (Vector *)wasm_runtime_malloc(sizeof(Vector)); + memset(vector_ptr, 0, sizeof(Vector)); + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), true); + bh_vector_append(vector_ptr, elem_buf); + + EXPECT_EQ(1, bh_vector_size(vector_ptr)); + EXPECT_EQ(0, bh_vector_size(nullptr)); +} + +TEST_F(bh_vector_test_suite, bh_vector_destroy) +{ + Vector *vector_ptr = nullptr; + char elem_buf[] = "test_vector"; + + vector_ptr = (Vector *)wasm_runtime_malloc(sizeof(Vector)); + memset(vector_ptr, 0, sizeof(Vector)); + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), true); + bh_vector_append(vector_ptr, elem_buf); + + // Normally. + EXPECT_EQ(true, bh_vector_destroy(vector_ptr)); + // Illegal parameters: nullptr. + EXPECT_EQ(false, bh_vector_destroy(nullptr)); + + // use_lock is false. + bh_vector_init(vector_ptr, 6, sizeof(elem_buf), false); + bh_vector_append(vector_ptr, elem_buf); + EXPECT_EQ(true, bh_vector_destroy(vector_ptr)); +} + +TEST_F(bh_vector_test_suite, bh_vector_thread_safety) +{ + Vector *vector_ptr = nullptr; + char elem; + int32_t i = 0; + std::vector> threads; + + vector_ptr = (Vector *)wasm_runtime_malloc(sizeof(Vector)); + memset(vector_ptr, 0, sizeof(Vector)); + bh_vector_init(vector_ptr, 6, sizeof(elem), true); + + for (i = 0; i < 8; i++) { + threads.push_back(std::async([&] { + for (int j = 0; j < 25; j++) { + bh_vector_append(vector_ptr, (void *)&elem); + } + })); + } + + for (auto &t : threads) { + t.wait(); + } + + EXPECT_EQ(bh_vector_size(vector_ptr), 200); + + // Normally. + EXPECT_EQ(true, bh_vector_destroy(vector_ptr)); +} diff --git a/tests/unit/shared-utils/shared_utils_test.cc b/tests/unit/shared-utils/shared_utils_test.cc new file mode 100644 index 0000000000..82bedf32fa --- /dev/null +++ b/tests/unit/shared-utils/shared_utils_test.cc @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#include "test_helper.h" +#include "gtest/gtest.h" + +/* Test APIs under wamr/core/shared/utils */ + +class SharedUtilsTest : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + virtual void SetUp() {} + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + virtual void TearDown() {} + + public: + WAMRRuntimeRAII<512 * 1024> runtime; +}; + +TEST_F(SharedUtilsTest, bh_list) {} diff --git a/tests/unit/tid-allocator/CMakeLists.txt b/tests/unit/tid-allocator/CMakeLists.txt new file mode 100644 index 0000000000..be62340a3c --- /dev/null +++ b/tests/unit/tid-allocator/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +project (tid_allocator_tests) + +if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS) + set (WAMR_BUILD_LIB_WASI_THREADS 1) +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_PLATFORM) + string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +endif () + +include (../unit_common.cmake) + +add_library (tid_allocator_vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +add_library (wamr_gtest_main main.cpp) +target_link_libraries (wamr_gtest_main PUBLIC gtest tid_allocator_vmlib) + +function (create_wamr_unit_test test_name) + set (sources ${ARGN}) + add_executable (${test_name} ${sources}) + target_link_libraries ( + ${test_name} + wamr_gtest_main + tid_allocator_vmlib + ${LLVM_AVAILABLE_LIBS} + ) + gtest_discover_tests (${test_name}) + endfunction () + +include (${IWASM_DIR}/libraries/lib-wasi-threads/unit-test/lib_wasi_threads_unit_tests.cmake) + diff --git a/tests/unit/main.cpp b/tests/unit/tid-allocator/main.cpp similarity index 99% rename from tests/unit/main.cpp rename to tests/unit/tid-allocator/main.cpp index 63695d9ee7..081676a1b9 100644 --- a/tests/unit/main.cpp +++ b/tests/unit/tid-allocator/main.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ + #include #include "wasm_runtime_common.h" diff --git a/tests/unit/unit_common.cmake b/tests/unit/unit_common.cmake new file mode 100644 index 0000000000..90ea2eb7cd --- /dev/null +++ b/tests/unit/unit_common.cmake @@ -0,0 +1,105 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +if (NOT DEFINED WAMR_BUILD_PLATFORM) + set (WAMR_BUILD_PLATFORM "linux") +endif () + +set (UNIT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${UNIT_ROOT_DIR}) + +enable_language (ASM) + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + else () + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Debug) +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + # Enable Interpreter by default + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Enable AOT by default. + set (WAMR_BUILD_AOT 1) +endif () + +if (NOT DEFINED WAMR_BUILD_JIT) + # Disable JIT by default. + set (WAMR_BUILD_JIT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + # Enable libc builtin support by default + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_WASI) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 1) +endif () + +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + set (WAMR_BUILD_MULTI_MODULE 1) +endif() + +if (NOT DEFINED WAMR_BUILD_APP_FRAMEWORK) + set (WAMR_BUILD_APP_FRAMEWORK 1) +endif () + +if (COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") +endif () + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ + -Wall -Wno-unused-parameter -Wno-pedantic") + +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) + +# include the build config template file +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +include_directories (${SHARED_DIR}/include + ${IWASM_DIR}/include) + +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +if (NOT (GOOGLETEST_INCLUDED EQUAL 1)) +# Prevent overriding the parent project's compiler/linker +# settings on Windows +set (gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Fetch Google test +include (FetchContent) +FetchContent_Declare ( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) +FetchContent_MakeAvailable (googletest) + +endif() + +# Add helper classes +include_directories(${CMAKE_CURRENT_LIST_DIR}/common) + +message ("unit_common.cmake included") + diff --git a/tests/unit/wasm-c-api/CMakeLists.txt b/tests/unit/wasm-c-api/CMakeLists.txt new file mode 100644 index 0000000000..3b8884e111 --- /dev/null +++ b/tests/unit/wasm-c-api/CMakeLists.txt @@ -0,0 +1,62 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.9) +project (wasm_c_api_test) + +################ runtime settings ################ +set(CMAKE_BUILD_TYPE Debug) +set(WAMR_BUILD_PLATFORM "linux") + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch +set(WAMR_BUILD_TARGET "X86_64") +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_AOT 0) +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_LIBC_WASI 0) +set(WAMR_BUILD_FAST_INTERP 0) + +# compiling and linking flags +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -mindirect-branch-register") + +# build out vmlib +# hard code path here +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) +################################################ + +################ unit test related ################ +# Add googletest directly to our build. This defines +# the gtest and gtest_main targets. + +if (NOT (GOOGLETEST_INCLUDED EQUAL 1)) +# Prevent overriding the parent project's compiler/linker +# settings on Windows +set (gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Fetch Google test +include (FetchContent) +FetchContent_Declare ( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) +FetchContent_MakeAvailable (googletest) +endif() + +enable_testing() + +add_executable(wasm_c_api_test + basic.cc +) + +target_link_libraries(wasm_c_api_test vmlib gtest_main) + +gtest_discover_tests(wasm_c_api_test) diff --git a/tests/unit/wasm-c-api/basic.cc b/tests/unit/wasm-c-api/basic.cc new file mode 100644 index 0000000000..34d837dd92 --- /dev/null +++ b/tests/unit/wasm-c-api/basic.cc @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +#include "bh_platform.h" +#include "wasm_c_api.h" +#include "wasm_c_api_internal.h" + +#ifndef own +#define own +#endif + +class CApiTests : public ::testing::Test +{ + protected: + void SetUp() + { + bh_log_set_verbose_level(5); + engine = nullptr; + engine = wasm_engine_new(); + ASSERT_NE(nullptr, engine); + } + + void TearDown() { wasm_engine_delete(engine); } + + wasm_engine_t *engine; +}; + +TEST_F(CApiTests, empty) {} + +TEST_F(CApiTests, wasm_engine_t) +{ + wasm_engine_t *engine1 = wasm_engine_new(); + wasm_engine_t *engine2 = wasm_engine_new(); + EXPECT_EQ(engine1, engine2); + /* TearDown() will delete it */ +} + +TEST_F(CApiTests, wasm_store_t) +{ + wasm_engine_t *engine = wasm_engine_new(); + wasm_store_t *store1 = wasm_store_new(engine); + EXPECT_NE(nullptr, store1); + EXPECT_NE(nullptr, store1->modules->data); + + wasm_store_t *store2 = wasm_store_new(engine); + EXPECT_NE(store1, store2); + EXPECT_NE(store1->modules->data, store2->modules->data); + + wasm_store_delete(store1); + wasm_store_delete(store2); + + store1 = wasm_store_new(engine); + EXPECT_NE(nullptr, store1); + wasm_store_delete(store1); +} + +TEST_F(CApiTests, wasm_byte_vec_t) +{ + wasm_byte_vec_t byte_vec = { 0 }; + wasm_byte_vec_new_uninitialized(&byte_vec, 10); + EXPECT_NE(nullptr, byte_vec.data); + EXPECT_EQ(10, byte_vec.size); + + byte_vec.data[0] = (wasm_byte_t)'a'; + byte_vec.data[1] = (wasm_byte_t)'b'; + byte_vec.data[2] = (wasm_byte_t)'c'; + EXPECT_STREQ("abc", (char *)byte_vec.data); + + byte_vec.data[5] = (wasm_byte_t)'d'; + byte_vec.data[6] = (wasm_byte_t)'e'; + byte_vec.data[7] = (wasm_byte_t)'f'; + EXPECT_STREQ("def", (char *)(byte_vec.data + 5)); + + wasm_byte_vec_delete(&byte_vec); + EXPECT_EQ(nullptr, byte_vec.data); + EXPECT_EQ(0, byte_vec.size); +} + +TEST_F(CApiTests, wasm_valtype_vec_t) +{ + wasm_valtype_vec_t tuple1 = { 0 }; + wasm_valtype_vec_new_uninitialized(&tuple1, 128); + EXPECT_NE(nullptr, tuple1.data); + EXPECT_EQ(128, tuple1.size); + + wasm_valtype_t *val_type_1 = wasm_valtype_new_i32(); + tuple1.data[0] = val_type_1; + EXPECT_EQ(WASM_I32, wasm_valtype_kind(*(tuple1.data + 0))); + wasm_valtype_vec_delete(&tuple1); + wasm_valtype_delete(val_type_1); + + wasm_valtype_t *val_types[5] = { + wasm_valtype_new_i32(), wasm_valtype_new_i64(), wasm_valtype_new_f32(), + wasm_valtype_new_f64(), wasm_valtype_new_funcref() + }; + + wasm_valtype_vec_t tuple2 = { 0 }; + wasm_valtype_vec_new(&tuple2, 5, val_types); + EXPECT_NE(nullptr, tuple2.data); + EXPECT_EQ(WASM_F32, wasm_valtype_kind(*(tuple2.data + 2))); + EXPECT_EQ(WASM_FUNCREF, wasm_valtype_kind(*(tuple2.data + 4))); + + wasm_valtype_vec_t tuple3 = { 0 }; + wasm_valtype_vec_copy(&tuple3, &tuple2); + + wasm_valtype_vec_delete(&tuple2); + + EXPECT_EQ(WASM_I64, wasm_valtype_kind(*(tuple3.data + 1))); + EXPECT_EQ(WASM_F64, wasm_valtype_kind(*(tuple3.data + 3))); + wasm_valtype_vec_delete(&tuple3); +} + +TEST_F(CApiTests, wasm_functype_t) +{ + wasm_functype_t *callback_type = wasm_functype_new_1_1( + wasm_valtype_new(WASM_EXTERNREF), wasm_valtype_new(WASM_FUNCREF)); + EXPECT_EQ(WASM_EXTERNREF, + wasm_valtype_kind(*(wasm_functype_params(callback_type)->data))); + wasm_functype_delete(callback_type); + + callback_type = wasm_functype_new_0_0(); + wasm_functype_delete(callback_type); + + callback_type = wasm_functype_new_0_1(wasm_valtype_new(WASM_EXTERNREF)); + const wasm_valtype_vec_t *results = wasm_functype_results(callback_type); + EXPECT_EQ(WASM_EXTERNREF, wasm_valtype_kind(*(results->data))); + wasm_functype_delete(callback_type); + + callback_type = wasm_functype_new_1_0(wasm_valtype_new(WASM_EXTERNREF)); + EXPECT_EQ(WASM_EXTERNREF, + wasm_valtype_kind(*(wasm_functype_params(callback_type)->data))); + wasm_functype_delete(callback_type); + + wasm_functype_t *func_type1 = wasm_functype_new_2_2( + wasm_valtype_new(WASM_I32), wasm_valtype_new(WASM_I64), + wasm_valtype_new(WASM_I32), wasm_valtype_new(WASM_I64)); + wasm_functype_t *func_type2 = wasm_functype_copy(func_type1); + wasm_functype_delete(func_type1); + + EXPECT_EQ(WASM_I64, wasm_valtype_kind( + *(wasm_functype_results(func_type2)->data + 1))); + wasm_functype_delete(func_type2); +} + +TEST_F(CApiTests, wasm_globaltype_t) +{ + wasm_globaltype_t *const_f32_type = + wasm_globaltype_new(wasm_valtype_new(WASM_F32), WASM_CONST); + EXPECT_EQ(WASM_F32, + wasm_valtype_kind(wasm_globaltype_content(const_f32_type))); + + wasm_globaltype_t *cloned = wasm_globaltype_copy(const_f32_type); + wasm_globaltype_delete(const_f32_type); + + EXPECT_EQ(WASM_F32, wasm_valtype_kind(wasm_globaltype_content(cloned))); + + wasm_globaltype_delete(cloned); +} + +static wasm_trap_t * +test_func(const wasm_val_vec_t *args, own wasm_val_vec_t *results) +{ + return NULL; +} + +TEST_F(CApiTests, wasm_func_t) +{ + wasm_valtype_t *types[4] = { wasm_valtype_new_i32(), wasm_valtype_new_i64(), + wasm_valtype_new_i64(), + wasm_valtype_new_i32() }; + wasm_valtype_vec_t tuple1 = { 0 }, tuple2 = { 0 }; + wasm_valtype_vec_new(&tuple1, 4, types); + wasm_valtype_vec_copy(&tuple2, &tuple1); + wasm_functype_t *callback_type = wasm_functype_new(&tuple1, &tuple2); + + wasm_store_t *store = wasm_store_new(engine); + wasm_func_t *callback_func = wasm_func_new(store, callback_type, test_func); + wasm_functype_delete(callback_type); + + callback_type = callback_func->type; + EXPECT_EQ(WASM_I32, wasm_valtype_kind( + *(wasm_functype_params(callback_type)->data + 0))); + EXPECT_EQ(WASM_I32, wasm_valtype_kind( + *(wasm_functype_results(callback_type)->data + 3))); + wasm_func_delete(callback_func); + wasm_store_delete(store); +} diff --git a/tests/unit/wasm-c-api/run.sh b/tests/unit/wasm-c-api/run.sh new file mode 100755 index 0000000000..1b0d88e367 --- /dev/null +++ b/tests/unit/wasm-c-api/run.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# ./c_api_unit_test --gtest_list_tests + +function run_one() +{ + local case=$1 + valgrind --tool=memcheck --leak-check=yes -v \ + ./c_api_unit_test --gtest_filter=CApiTests.${case} +} + +function run() +{ + valgrind --tool=memcheck --leak-check=yes -v \ + ./c_api_unit_test +} + +[[ $# -gt 0 ]] && $@ || run diff --git a/tests/unit/wasm-vm/.gitignore b/tests/unit/wasm-vm/.gitignore new file mode 100644 index 0000000000..aa3883989b --- /dev/null +++ b/tests/unit/wasm-vm/.gitignore @@ -0,0 +1,2 @@ +wasm-apps/app[123]/*.wat +wasm-apps/app[123]/*.wasm \ No newline at end of file diff --git a/tests/unit/wasm-vm/CMakeLists.txt b/tests/unit/wasm-vm/CMakeLists.txt new file mode 100644 index 0000000000..d13d65aac5 --- /dev/null +++ b/tests/unit/wasm-vm/CMakeLists.txt @@ -0,0 +1,53 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.9) + +project (test-wasm-vm) + +add_definitions (-DRUN_ON_LINUX) + +add_definitions (-Dattr_container_malloc=malloc) +add_definitions (-Dattr_container_free=free) + +set (WAMR_BUILD_APP_FRAMEWORK 1) +set (CMAKE_BUILD_TYPE Release) + +include (../unit_common.cmake) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc) + +set (UNIT_SOURCE ${source_all}) + +set (unit_test_sources + ${UNIT_SOURCE} + ${PLATFORM_SHARED_SOURCE} + ${UTILS_SHARED_SOURCE} + ${MEM_ALLOC_SHARED_SOURCE} + ${LIB_HOST_AGENT_SOURCE} + ${NATIVE_INTERFACE_SOURCE} + ${LIBC_BUILTIN_SOURCE} + ${LIBC_WASI_SOURCE} + ${IWASM_COMMON_SOURCE} + ${IWASM_INTERP_SOURCE} + ${IWASM_AOT_SOURCE} + ${IWASM_COMPL_SOURCE} + ${WASM_APP_LIB_SOURCE_ALL} + ${UNCOMMON_SHARED_SOURCE} + ) + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable(wasm_vm_test ${unit_test_sources}) + +target_link_libraries(wasm_vm_test ${LLVM_AVAILABLE_LIBS} gtest_main) + +add_custom_command(TARGET wasm_vm_test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps/app4/*.wasm + ${PROJECT_BINARY_DIR}/ + COMMENT "Copy wasm files to the output directory" +) + +gtest_discover_tests(wasm_vm_test) diff --git a/tests/unit/wasm-vm/wasm-apps/app1.wast b/tests/unit/wasm-vm/wasm-apps/app1.wast new file mode 100644 index 0000000000..aea3a87928 --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app1.wast @@ -0,0 +1,106 @@ +(module + (type $0 (func (param i32) (result i32))) + (type $1 (func (param i32 i32) (result i32))) + (type $2 (func (param i32))) + (type $3 (func (param i32 i32 i32) (result i32))) + (type $4 (func)) + (type $5 (func (result i32))) + (import "env" "malloc" (func $13 (param i32) (result i32))) + (import "env" "calloc" (func $14 (param i32 i32) (result i32))) + (import "env" "free" (func $15 (param i32))) + (import "env" "memcpy" (func $16 (param i32 i32 i32) (result i32))) + (import "env" "strdup" (func $17 (param i32) (result i32))) + (memory $6 1) + (global $7 i32 (i32.const 1024)) + (global $8 i32 (i32.const 1024)) + (global $9 i32 (i32.const 1024)) + (global $10 i32 (i32.const 5120)) + (global $11 i32 (i32.const 0)) + (global $12 i32 (i32.const 1)) + (export "memory" (memory $6)) + (export "__wasm_call_ctors" (func $18)) + (export "on_init" (func $18)) + (export "my_sqrt" (func $19)) + (export "null_pointer" (func $20)) + (export "my_malloc" (func $21)) + (export "my_calloc" (func $22)) + (export "my_free" (func $23)) + (export "my_memcpy" (func $24)) + (export "my_strdup" (func $25)) + (export "__dso_handle" (global $7)) + (export "__data_end" (global $8)) + (export "__global_base" (global $9)) + (export "__heap_base" (global $10)) + (export "__memory_base" (global $11)) + (export "__table_base" (global $12)) + + (func $18 (type $4) + nop + ) + + (func $19 (type $1) + (param $0 i32) + (param $1 i32) + (result i32) + local.get $1 + local.get $1 + i32.mul + local.get $0 + local.get $0 + i32.mul + i32.add + ) + + (func $20 (type $5) + (result i32) + i32.const 0 + ) + + (func $21 (type $0) + (param $0 i32) + (result i32) + local.get $0 + call $13 + ) + + (func $22 (type $1) + (param $0 i32) + (param $1 i32) + (result i32) + local.get $0 + local.get $1 + call $14 + ) + + (func $23 (type $2) + (param $0 i32) + local.get $0 + call $15 + ) + + (func $24 (type $3) + (param $0 i32) + (param $1 i32) + (param $2 i32) + (result i32) + local.get $0 + local.get $1 + local.get $2 + call $16 + ) + + (func $25 (type $0) + (param $0 i32) + (result i32) + local.get $0 + call $17 + ) + + ;;(custom_section "producers" + ;; (after code) + ;; "\01\0cprocessed-by\01\05clangV11.0.0 (ht" + ;; "tps://github.com/llvm/llvm-proje" + ;; "ct 176249bd6732a8044d457092ed932" + ;; "768724a6f06)") + + ) \ No newline at end of file diff --git a/tests/unit/wasm-vm/wasm-apps/app1/main.c b/tests/unit/wasm-vm/wasm-apps/app1/main.c new file mode 100644 index 0000000000..0090d105fd --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app1/main.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include + +void +on_init() +{} + +int +my_sqrt(int x, int y) +{ + return x * x + y * y; +} + +void * +null_pointer() +{ + void *ptr = NULL; + return ptr; +} + +void * +my_malloc(int size) +{ + return malloc(size); +} + +void * +my_calloc(int nmemb, int size) +{ + return calloc(nmemb, size); +} + +void +my_free(void *ptr) +{ + return free(ptr); +} + +void * +my_memcpy(void *dst, void *src, int size) +{ + return memcpy(dst, src, size); +} + +char * +my_strdup(const char *s) +{ + return strdup(s); +} diff --git a/tests/unit/wasm-vm/wasm-apps/app1_wasm.h b/tests/unit/wasm-vm/wasm-apps/app1_wasm.h new file mode 100644 index 0000000000..2b20b39f9a --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app1_wasm.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +unsigned char app1_wasm[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x1E, 0x06, 0x60, + 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01, + 0x7F, 0x00, 0x60, 0x03, 0x7F, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x00, 0x00, + 0x60, 0x00, 0x01, 0x7F, 0x02, 0x40, 0x05, 0x03, 0x65, 0x6E, 0x76, 0x06, + 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, + 0x06, 0x63, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x01, 0x03, 0x65, 0x6E, + 0x76, 0x04, 0x66, 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x65, 0x6E, 0x76, + 0x06, 0x6D, 0x65, 0x6D, 0x63, 0x70, 0x79, 0x00, 0x03, 0x03, 0x65, 0x6E, + 0x76, 0x06, 0x73, 0x74, 0x72, 0x64, 0x75, 0x70, 0x00, 0x00, 0x03, 0x09, + 0x08, 0x04, 0x01, 0x05, 0x00, 0x01, 0x02, 0x03, 0x00, 0x05, 0x03, 0x01, + 0x00, 0x01, 0x06, 0x23, 0x06, 0x7F, 0x00, 0x41, 0x80, 0x08, 0x0B, 0x7F, + 0x00, 0x41, 0x80, 0x08, 0x0B, 0x7F, 0x00, 0x41, 0x80, 0x08, 0x0B, 0x7F, + 0x00, 0x41, 0x80, 0x28, 0x0B, 0x7F, 0x00, 0x41, 0x00, 0x0B, 0x7F, 0x00, + 0x41, 0x01, 0x0B, 0x07, 0xD4, 0x01, 0x10, 0x06, 0x6D, 0x65, 0x6D, 0x6F, + 0x72, 0x79, 0x02, 0x00, 0x11, 0x5F, 0x5F, 0x77, 0x61, 0x73, 0x6D, 0x5F, + 0x63, 0x61, 0x6C, 0x6C, 0x5F, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x00, 0x05, + 0x07, 0x6F, 0x6E, 0x5F, 0x69, 0x6E, 0x69, 0x74, 0x00, 0x05, 0x07, 0x6D, + 0x79, 0x5F, 0x73, 0x71, 0x72, 0x74, 0x00, 0x06, 0x0C, 0x6E, 0x75, 0x6C, + 0x6C, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x07, 0x09, + 0x6D, 0x79, 0x5F, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x08, 0x09, + 0x6D, 0x79, 0x5F, 0x63, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x09, 0x07, + 0x6D, 0x79, 0x5F, 0x66, 0x72, 0x65, 0x65, 0x00, 0x0A, 0x09, 0x6D, 0x79, + 0x5F, 0x6D, 0x65, 0x6D, 0x63, 0x70, 0x79, 0x00, 0x0B, 0x09, 0x6D, 0x79, + 0x5F, 0x73, 0x74, 0x72, 0x64, 0x75, 0x70, 0x00, 0x0C, 0x0C, 0x5F, 0x5F, + 0x64, 0x73, 0x6F, 0x5F, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x03, 0x00, + 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, 0x61, 0x5F, 0x65, 0x6E, 0x64, 0x03, + 0x01, 0x0D, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x62, + 0x61, 0x73, 0x65, 0x03, 0x02, 0x0B, 0x5F, 0x5F, 0x68, 0x65, 0x61, 0x70, + 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x03, 0x0D, 0x5F, 0x5F, 0x6D, 0x65, + 0x6D, 0x6F, 0x72, 0x79, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x04, 0x0C, + 0x5F, 0x5F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x5F, 0x62, 0x61, 0x73, 0x65, + 0x03, 0x05, 0x0A, 0x41, 0x08, 0x03, 0x00, 0x01, 0x0B, 0x0D, 0x00, 0x20, + 0x01, 0x20, 0x01, 0x6C, 0x20, 0x00, 0x20, 0x00, 0x6C, 0x6A, 0x0B, 0x04, + 0x00, 0x41, 0x00, 0x0B, 0x06, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0B, 0x08, + 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x01, 0x0B, 0x06, 0x00, 0x20, 0x00, + 0x10, 0x02, 0x0B, 0x0A, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, + 0x03, 0x0B, 0x06, 0x00, 0x20, 0x00, 0x10, 0x04, 0x0B, 0x00, 0x76, 0x09, + 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x72, 0x73, 0x01, 0x0C, 0x70, + 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x2D, 0x62, 0x79, 0x01, + 0x05, 0x63, 0x6C, 0x61, 0x6E, 0x67, 0x56, 0x31, 0x31, 0x2E, 0x30, 0x2E, + 0x30, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x6C, 0x6C, + 0x76, 0x6D, 0x2F, 0x6C, 0x6C, 0x76, 0x6D, 0x2D, 0x70, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x20, 0x31, 0x37, 0x36, 0x32, 0x34, 0x39, 0x62, 0x64, + 0x36, 0x37, 0x33, 0x32, 0x61, 0x38, 0x30, 0x34, 0x34, 0x64, 0x34, 0x35, + 0x37, 0x30, 0x39, 0x32, 0x65, 0x64, 0x39, 0x33, 0x32, 0x37, 0x36, 0x38, + 0x37, 0x32, 0x34, 0x61, 0x36, 0x66, 0x30, 0x36, 0x29 +}; diff --git a/tests/unit/wasm-vm/wasm-apps/app2.wast b/tests/unit/wasm-vm/wasm-apps/app2.wast new file mode 100644 index 0000000000..c5ea06eaac --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app2.wast @@ -0,0 +1,311 @@ +(module + (type $0 (func (param i32 i32 i32) (result i32))) + (type $1 (func (param i32 i32) (result i32))) + (type $2 (func (param i32) (result i32))) + (type $3 (func (param i32))) + (type $4 (func (param i32 i32 i32 i32) (result i32))) + (type $5 (func)) + (type $6 (func (result i32))) + (import "env" "malloc" (func $15 (param i32) (result i32))) + (import "env" "calloc" (func $16 (param i32 i32) (result i32))) + (import "env" "free" (func $17 (param i32))) + (import "env" "memcpy" (func $18 (param i32 i32 i32) (result i32))) + (import "env" "strdup" (func $19 (param i32) (result i32))) + (import "env" "memcmp" (func $20 (param i32 i32 i32) (result i32))) + (import "env" "printf" (func $21 (param i32 i32) (result i32))) + (import "env" "sprintf" (func $22 (param i32 i32 i32) (result i32))) + (import "env" "snprintf" (func $23 (param i32 i32 i32 i32) (result i32))) + (import "env" "puts" (func $24 (param i32) (result i32))) + (import "env" "putchar" (func $25 (param i32) (result i32))) + (import "env" "memmove" (func $26 (param i32 i32 i32) (result i32))) + (import "env" "memset" (func $27 (param i32 i32 i32) (result i32))) + (import "env" "strchr" (func $28 (param i32 i32) (result i32))) + (import "env" "strcmp" (func $29 (param i32 i32) (result i32))) + (import "env" "strcpy" (func $30 (param i32 i32) (result i32))) + (import "env" "strlen" (func $31 (param i32) (result i32))) + (import "env" "strncmp" (func $32 (param i32 i32 i32) (result i32))) + (import "env" "strncpy" (func $33 (param i32 i32 i32) (result i32))) + (memory $7 1) + (global $8 (mut i32) (i32.const 5120)) + (global $9 i32 (i32.const 1024)) + (global $10 i32 (i32.const 1024)) + (global $11 i32 (i32.const 1024)) + (global $12 i32 (i32.const 5120)) + (global $13 i32 (i32.const 0)) + (global $14 i32 (i32.const 1)) + (export "memory" (memory $7)) + (export "__wasm_call_ctors" (func $34)) + (export "on_init" (func $34)) + (export "my_sqrt" (func $35)) + (export "null_pointer" (func $36)) + (export "my_malloc" (func $37)) + (export "my_calloc" (func $38)) + (export "my_free" (func $39)) + (export "my_memcpy" (func $40)) + (export "my_strdup" (func $41)) + (export "my_memcmp" (func $42)) + (export "my_printf" (func $43)) + (export "my_sprintf" (func $44)) + (export "my_snprintf" (func $45)) + (export "my_puts" (func $46)) + (export "my_putchar" (func $47)) + (export "my_memmove" (func $48)) + (export "my_memset" (func $49)) + (export "my_strchr" (func $50)) + (export "my_strcmp" (func $51)) + (export "my_strcpy" (func $52)) + (export "my_strlen" (func $53)) + (export "my_strncmp" (func $54)) + (export "my_strncpy" (func $55)) + (export "__dso_handle" (global $9)) + (export "__data_end" (global $10)) + (export "__global_base" (global $11)) + (export "__heap_base" (global $12)) + (export "__memory_base" (global $13)) + (export "__table_base" (global $14)) + + (func $34 (type $5) + nop + ) + + (func $35 (type $1) + (param $0 i32) + (param $1 i32) + (result i32) + local.get $1 + local.get $1 + i32.mul + local.get $0 + local.get $0 + i32.mul + i32.add + ) + + (func $36 (type $6) + (result i32) + i32.const 0 + ) + + (func $37 (type $2) + (param $0 i32) + (result i32) + local.get $0 + call $15 + ) + + (func $38 (type $1) + (param $0 i32) + (param $1 i32) + (result i32) + local.get $0 + local.get $1 + call $16 + ) + + (func $39 (type $3) + (param $0 i32) + local.get $0 + call $17 + ) + + (func $40 (type $0) + (param $0 i32) + (param $1 i32) + (param $2 i32) + (result i32) + local.get $0 + local.get $1 + local.get $2 + call $18 + ) + + (func $41 (type $2) + (param $0 i32) + (result i32) + local.get $0 + call $19 + ) + + (func $42 (type $0) + (param $0 i32) + (param $1 i32) + (param $2 i32) + (result i32) + local.get $0 + local.get $1 + local.get $2 + call $20 + ) + + (func $43 (type $1) + (param $0 i32) + (param $1 i32) + (result i32) + (local $2 i32) + global.get $8 + i32.const 16 + i32.sub + local.tee $2 + global.set $8 + local.get $2 + local.get $1 + i32.store + local.get $0 + local.get $2 + call $21 + local.get $2 + i32.const 16 + i32.add + global.set $8 + ) + + (func $44 (type $0) + (param $0 i32) + (param $1 i32) + (param $2 i32) + (result i32) + (local $3 i32) + global.get $8 + i32.const 16 + i32.sub + local.tee $3 + global.set $8 + local.get $3 + local.get $2 + i32.store + local.get $0 + local.get $1 + local.get $3 + call $22 + local.get $3 + i32.const 16 + i32.add + global.set $8 + ) + + (func $45 (type $4) + (param $0 i32) + (param $1 i32) + (param $2 i32) + (param $3 i32) + (result i32) + (local $4 i32) + global.get $8 + i32.const 16 + i32.sub + local.tee $4 + global.set $8 + local.get $4 + local.get $3 + i32.store + local.get $0 + local.get $1 + local.get $2 + local.get $4 + call $23 + local.get $4 + i32.const 16 + i32.add + global.set $8 + ) + + (func $46 (type $2) + (param $0 i32) + (result i32) + local.get $0 + call $24 + ) + + (func $47 (type $2) + (param $0 i32) + (result i32) + local.get $0 + call $25 + ) + + (func $48 (type $0) + (param $0 i32) + (param $1 i32) + (param $2 i32) + (result i32) + local.get $0 + local.get $1 + local.get $2 + call $26 + ) + + (func $49 (type $0) + (param $0 i32) + (param $1 i32) + (param $2 i32) + (result i32) + local.get $0 + local.get $1 + local.get $2 + call $27 + ) + + (func $50 (type $1) + (param $0 i32) + (param $1 i32) + (result i32) + local.get $0 + local.get $1 + call $28 + ) + + (func $51 (type $1) + (param $0 i32) + (param $1 i32) + (result i32) + local.get $0 + local.get $1 + call $29 + ) + + (func $52 (type $1) + (param $0 i32) + (param $1 i32) + (result i32) + local.get $0 + local.get $1 + call $30 + ) + + (func $53 (type $2) + (param $0 i32) + (result i32) + local.get $0 + call $31 + ) + + (func $54 (type $0) + (param $0 i32) + (param $1 i32) + (param $2 i32) + (result i32) + local.get $0 + local.get $1 + local.get $2 + call $32 + ) + + (func $55 (type $0) + (param $0 i32) + (param $1 i32) + (param $2 i32) + (result i32) + local.get $0 + local.get $1 + local.get $2 + call $33 + ) + + ;;(custom_section "producers" + ;; (after code) + ;; "\01\0cprocessed-by\01\05clangV11.0.0 (ht" + ;; "tps://github.com/llvm/llvm-proje" + ;; "ct 176249bd6732a8044d457092ed932" + ;; "768724a6f06)") + + ) \ No newline at end of file diff --git a/tests/unit/wasm-vm/wasm-apps/app2/main.c b/tests/unit/wasm-vm/wasm-apps/app2/main.c new file mode 100644 index 0000000000..160d834a50 --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app2/main.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include + +void +on_init() +{} + +int +my_sqrt(int x, int y) +{ + return x * x + y * y; +} + +void * +null_pointer() +{ + void *ptr = NULL; + return ptr; +} + +void * +my_malloc(int size) +{ + return malloc(size); +} + +void * +my_calloc(int nmemb, int size) +{ + return calloc(nmemb, size); +} + +void +my_free(void *ptr) +{ + free(ptr); +} + +void * +my_memcpy(void *dst, void *src, int size) +{ + return memcpy(dst, src, size); +} + +char * +my_strdup(const char *s) +{ + return strdup(s); +} + +int +my_memcmp(const void *buf1, const void *buf2, int size) +{ + return memcmp(buf1, buf2, size); +} + +int +my_printf(const char *format, char *s) +{ + return printf(format, s); +} + +int +my_sprintf(char *buf1, const char *format, char *buf2) +{ + return sprintf(buf1, format, buf2); +} + +int +my_snprintf(char *buf1, int size, const char *format, char *buf2) +{ + return snprintf(buf1, size, format, buf2); +} + +int +my_puts(const char *s) +{ + return puts(s); +} + +int +my_putchar(int s) +{ + return putchar(s); +} + +void * +my_memmove(void *buf1, const void *buf2, int size) +{ + return memmove(buf1, buf2, size); +} + +void * +my_memset(void *buf, int c, int size) +{ + return memset(buf, c, size); +} + +char * +my_strchr(const char *s, int c) +{ + return strchr(s, c); +} + +int +my_strcmp(const char *buf1, const char *buf2) +{ + return strcmp(buf1, buf2); +} + +char * +my_strcpy(char *buf1, const char *buf2) +{ + return strcpy(buf1, buf2); +} + +int +my_strlen(const char *s) +{ + return (int)strlen(s); +} + +int +my_strncmp(const char *buf1, const char *buf2, int n) +{ + return strncmp(buf1, buf2, n); +} + +char * +my_strncpy(char *buf1, const char *buf2, int n) +{ + return strncpy(buf1, buf2, n); +} diff --git a/tests/unit/wasm-vm/wasm-apps/app2_wasm.h b/tests/unit/wasm-vm/wasm-apps/app2_wasm.h new file mode 100644 index 0000000000..d89f7e57da --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app2_wasm.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +unsigned char app2_wasm[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x26, 0x07, 0x60, + 0x03, 0x7F, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x01, 0x7F, 0x00, 0x60, 0x04, 0x7F, + 0x7F, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x00, 0x00, 0x60, 0x00, 0x01, 0x7F, + 0x02, 0xFB, 0x01, 0x13, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x61, 0x6C, + 0x6C, 0x6F, 0x63, 0x00, 0x02, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x63, 0x61, + 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x66, + 0x72, 0x65, 0x65, 0x00, 0x03, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x65, + 0x6D, 0x63, 0x70, 0x79, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x73, + 0x74, 0x72, 0x64, 0x75, 0x70, 0x00, 0x02, 0x03, 0x65, 0x6E, 0x76, 0x06, + 0x6D, 0x65, 0x6D, 0x63, 0x6D, 0x70, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, + 0x06, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, + 0x76, 0x07, 0x73, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00, 0x03, + 0x65, 0x6E, 0x76, 0x08, 0x73, 0x6E, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, + 0x00, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x04, 0x70, 0x75, 0x74, 0x73, 0x00, + 0x02, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x70, 0x75, 0x74, 0x63, 0x68, 0x61, + 0x72, 0x00, 0x02, 0x03, 0x65, 0x6E, 0x76, 0x07, 0x6D, 0x65, 0x6D, 0x6D, + 0x6F, 0x76, 0x65, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D, 0x65, + 0x6D, 0x73, 0x65, 0x74, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x73, + 0x74, 0x72, 0x63, 0x68, 0x72, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x06, + 0x73, 0x74, 0x72, 0x63, 0x6D, 0x70, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, + 0x06, 0x73, 0x74, 0x72, 0x63, 0x70, 0x79, 0x00, 0x01, 0x03, 0x65, 0x6E, + 0x76, 0x06, 0x73, 0x74, 0x72, 0x6C, 0x65, 0x6E, 0x00, 0x02, 0x03, 0x65, + 0x6E, 0x76, 0x07, 0x73, 0x74, 0x72, 0x6E, 0x63, 0x6D, 0x70, 0x00, 0x00, + 0x03, 0x65, 0x6E, 0x76, 0x07, 0x73, 0x74, 0x72, 0x6E, 0x63, 0x70, 0x79, + 0x00, 0x00, 0x03, 0x17, 0x16, 0x05, 0x01, 0x06, 0x02, 0x01, 0x03, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x04, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x02, 0x00, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x29, 0x07, 0x7F, + 0x01, 0x41, 0x80, 0x28, 0x0B, 0x7F, 0x00, 0x41, 0x80, 0x08, 0x0B, 0x7F, + 0x00, 0x41, 0x80, 0x08, 0x0B, 0x7F, 0x00, 0x41, 0x80, 0x08, 0x0B, 0x7F, + 0x00, 0x41, 0x80, 0x28, 0x0B, 0x7F, 0x00, 0x41, 0x00, 0x0B, 0x7F, 0x00, + 0x41, 0x01, 0x0B, 0x07, 0x81, 0x03, 0x1E, 0x06, 0x6D, 0x65, 0x6D, 0x6F, + 0x72, 0x79, 0x02, 0x00, 0x11, 0x5F, 0x5F, 0x77, 0x61, 0x73, 0x6D, 0x5F, + 0x63, 0x61, 0x6C, 0x6C, 0x5F, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x00, 0x13, + 0x07, 0x6F, 0x6E, 0x5F, 0x69, 0x6E, 0x69, 0x74, 0x00, 0x13, 0x07, 0x6D, + 0x79, 0x5F, 0x73, 0x71, 0x72, 0x74, 0x00, 0x14, 0x0C, 0x6E, 0x75, 0x6C, + 0x6C, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x15, 0x09, + 0x6D, 0x79, 0x5F, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x16, 0x09, + 0x6D, 0x79, 0x5F, 0x63, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x17, 0x07, + 0x6D, 0x79, 0x5F, 0x66, 0x72, 0x65, 0x65, 0x00, 0x18, 0x09, 0x6D, 0x79, + 0x5F, 0x6D, 0x65, 0x6D, 0x63, 0x70, 0x79, 0x00, 0x19, 0x09, 0x6D, 0x79, + 0x5F, 0x73, 0x74, 0x72, 0x64, 0x75, 0x70, 0x00, 0x1A, 0x09, 0x6D, 0x79, + 0x5F, 0x6D, 0x65, 0x6D, 0x63, 0x6D, 0x70, 0x00, 0x1B, 0x09, 0x6D, 0x79, + 0x5F, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x1C, 0x0A, 0x6D, 0x79, + 0x5F, 0x73, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x1D, 0x0B, 0x6D, + 0x79, 0x5F, 0x73, 0x6E, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x1E, + 0x07, 0x6D, 0x79, 0x5F, 0x70, 0x75, 0x74, 0x73, 0x00, 0x1F, 0x0A, 0x6D, + 0x79, 0x5F, 0x70, 0x75, 0x74, 0x63, 0x68, 0x61, 0x72, 0x00, 0x20, 0x0A, + 0x6D, 0x79, 0x5F, 0x6D, 0x65, 0x6D, 0x6D, 0x6F, 0x76, 0x65, 0x00, 0x21, + 0x09, 0x6D, 0x79, 0x5F, 0x6D, 0x65, 0x6D, 0x73, 0x65, 0x74, 0x00, 0x22, + 0x09, 0x6D, 0x79, 0x5F, 0x73, 0x74, 0x72, 0x63, 0x68, 0x72, 0x00, 0x23, + 0x09, 0x6D, 0x79, 0x5F, 0x73, 0x74, 0x72, 0x63, 0x6D, 0x70, 0x00, 0x24, + 0x09, 0x6D, 0x79, 0x5F, 0x73, 0x74, 0x72, 0x63, 0x70, 0x79, 0x00, 0x25, + 0x09, 0x6D, 0x79, 0x5F, 0x73, 0x74, 0x72, 0x6C, 0x65, 0x6E, 0x00, 0x26, + 0x0A, 0x6D, 0x79, 0x5F, 0x73, 0x74, 0x72, 0x6E, 0x63, 0x6D, 0x70, 0x00, + 0x27, 0x0A, 0x6D, 0x79, 0x5F, 0x73, 0x74, 0x72, 0x6E, 0x63, 0x70, 0x79, + 0x00, 0x28, 0x0C, 0x5F, 0x5F, 0x64, 0x73, 0x6F, 0x5F, 0x68, 0x61, 0x6E, + 0x64, 0x6C, 0x65, 0x03, 0x01, 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, 0x61, + 0x5F, 0x65, 0x6E, 0x64, 0x03, 0x02, 0x0D, 0x5F, 0x5F, 0x67, 0x6C, 0x6F, + 0x62, 0x61, 0x6C, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x03, 0x0B, 0x5F, + 0x5F, 0x68, 0x65, 0x61, 0x70, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x04, + 0x0D, 0x5F, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x5F, 0x62, 0x61, + 0x73, 0x65, 0x03, 0x05, 0x0C, 0x5F, 0x5F, 0x74, 0x61, 0x62, 0x6C, 0x65, + 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x06, 0x0A, 0x94, 0x02, 0x16, 0x03, + 0x00, 0x01, 0x0B, 0x0D, 0x00, 0x20, 0x01, 0x20, 0x01, 0x6C, 0x20, 0x00, + 0x20, 0x00, 0x6C, 0x6A, 0x0B, 0x04, 0x00, 0x41, 0x00, 0x0B, 0x06, 0x00, + 0x20, 0x00, 0x10, 0x00, 0x0B, 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, + 0x01, 0x0B, 0x06, 0x00, 0x20, 0x00, 0x10, 0x02, 0x0B, 0x0A, 0x00, 0x20, + 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, 0x03, 0x0B, 0x06, 0x00, 0x20, 0x00, + 0x10, 0x04, 0x0B, 0x0A, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, + 0x05, 0x0B, 0x21, 0x01, 0x01, 0x7F, 0x23, 0x00, 0x41, 0x10, 0x6B, 0x22, + 0x02, 0x24, 0x00, 0x20, 0x02, 0x20, 0x01, 0x36, 0x02, 0x00, 0x20, 0x00, + 0x20, 0x02, 0x10, 0x06, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x24, 0x00, 0x0B, + 0x23, 0x01, 0x01, 0x7F, 0x23, 0x00, 0x41, 0x10, 0x6B, 0x22, 0x03, 0x24, + 0x00, 0x20, 0x03, 0x20, 0x02, 0x36, 0x02, 0x00, 0x20, 0x00, 0x20, 0x01, + 0x20, 0x03, 0x10, 0x07, 0x20, 0x03, 0x41, 0x10, 0x6A, 0x24, 0x00, 0x0B, + 0x25, 0x01, 0x01, 0x7F, 0x23, 0x00, 0x41, 0x10, 0x6B, 0x22, 0x04, 0x24, + 0x00, 0x20, 0x04, 0x20, 0x03, 0x36, 0x02, 0x00, 0x20, 0x00, 0x20, 0x01, + 0x20, 0x02, 0x20, 0x04, 0x10, 0x08, 0x20, 0x04, 0x41, 0x10, 0x6A, 0x24, + 0x00, 0x0B, 0x06, 0x00, 0x20, 0x00, 0x10, 0x09, 0x0B, 0x06, 0x00, 0x20, + 0x00, 0x10, 0x0A, 0x0B, 0x0A, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, + 0x10, 0x0B, 0x0B, 0x0A, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, + 0x0C, 0x0B, 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x0D, 0x0B, 0x08, + 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x0E, 0x0B, 0x08, 0x00, 0x20, 0x00, + 0x20, 0x01, 0x10, 0x0F, 0x0B, 0x06, 0x00, 0x20, 0x00, 0x10, 0x10, 0x0B, + 0x0A, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, 0x11, 0x0B, 0x0A, + 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, 0x12, 0x0B, 0x00, 0x76, + 0x09, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x72, 0x73, 0x01, 0x0C, + 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x2D, 0x62, 0x79, + 0x01, 0x05, 0x63, 0x6C, 0x61, 0x6E, 0x67, 0x56, 0x31, 0x31, 0x2E, 0x30, + 0x2E, 0x30, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x6C, + 0x6C, 0x76, 0x6D, 0x2F, 0x6C, 0x6C, 0x76, 0x6D, 0x2D, 0x70, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x31, 0x37, 0x36, 0x32, 0x34, 0x39, 0x62, + 0x64, 0x36, 0x37, 0x33, 0x32, 0x61, 0x38, 0x30, 0x34, 0x34, 0x64, 0x34, + 0x35, 0x37, 0x30, 0x39, 0x32, 0x65, 0x64, 0x39, 0x33, 0x32, 0x37, 0x36, + 0x38, 0x37, 0x32, 0x34, 0x61, 0x36, 0x66, 0x30, 0x36, 0x29 +}; diff --git a/tests/unit/wasm-vm/wasm-apps/app3.wast b/tests/unit/wasm-vm/wasm-apps/app3.wast new file mode 100644 index 0000000000..7c29ca5180 --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app3.wast @@ -0,0 +1,63 @@ +(module + (type $0 (func (param i32) (result i32))) + (type $1 (func)) + (type $2 (func (result i32))) + (type $3 (func (param i32 i32) (result i32))) + (import "env" "malloc" (func $11 (param i32) (result i32))) + (memory $4 1) + (global $5 i32 (i32.const 1024)) + (global $6 i32 (i32.const 1024)) + (global $7 i32 (i32.const 1024)) + (global $8 i32 (i32.const 5120)) + (global $9 i32 (i32.const 0)) + (global $10 i32 (i32.const 1)) + (export "memory" (memory $4)) + (export "__wasm_call_ctors" (func $12)) + (export "on_init" (func $12)) + (export "my_sqrt" (func $13)) + (export "null_pointer" (func $14)) + (export "my_malloc" (func $15)) + (export "__dso_handle" (global $5)) + (export "__data_end" (global $6)) + (export "__global_base" (global $7)) + (export "__heap_base" (global $8)) + (export "__memory_base" (global $9)) + (export "__table_base" (global $10)) + + (func $12 (type $1) + nop + ) + + (func $13 (type $3) + (param $0 i32) + (param $1 i32) + (result i32) + local.get $1 + local.get $1 + i32.mul + local.get $0 + local.get $0 + i32.mul + i32.add + ) + + (func $14 (type $2) + (result i32) + i32.const 0 + ) + + (func $15 (type $0) + (param $0 i32) + (result i32) + local.get $0 + call $11 + ) + + ;;(custom_section "producers" + ;; (after code) + ;; "\01\0cprocessed-by\01\05clangV11.0.0 (ht" + ;; "tps://github.com/llvm/llvm-proje" + ;; "ct 176249bd6732a8044d457092ed932" + ;; "768724a6f06)") + + ) \ No newline at end of file diff --git a/tests/unit/wasm-vm/wasm-apps/app3/main.c b/tests/unit/wasm-vm/wasm-apps/app3/main.c new file mode 100644 index 0000000000..000331ee98 --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app3/main.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include + +void +on_init() +{} + +int +my_sqrt(int x, int y) +{ + return x * x + y * y; +} + +void * +null_pointer() +{ + void *ptr = NULL; + return ptr; +} + +void * +my_malloc(int size) +{ + return malloc(size); +} diff --git a/tests/unit/wasm-vm/wasm-apps/app3_wasm.h b/tests/unit/wasm-vm/wasm-apps/app3_wasm.h new file mode 100644 index 0000000000..5c2ee5236b --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app3_wasm.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +unsigned char app3_wasm[] = { + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x13, 0x04, 0x60, + 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x00, 0x00, 0x60, 0x00, 0x01, 0x7F, 0x60, + 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x02, 0x0E, 0x01, 0x03, 0x65, 0x6E, 0x76, + 0x06, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x05, 0x04, + 0x01, 0x03, 0x02, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x23, 0x06, + 0x7F, 0x00, 0x41, 0x80, 0x08, 0x0B, 0x7F, 0x00, 0x41, 0x80, 0x08, 0x0B, + 0x7F, 0x00, 0x41, 0x80, 0x08, 0x0B, 0x7F, 0x00, 0x41, 0x80, 0x28, 0x0B, + 0x7F, 0x00, 0x41, 0x00, 0x0B, 0x7F, 0x00, 0x41, 0x01, 0x0B, 0x07, 0xA6, + 0x01, 0x0C, 0x06, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x11, + 0x5F, 0x5F, 0x77, 0x61, 0x73, 0x6D, 0x5F, 0x63, 0x61, 0x6C, 0x6C, 0x5F, + 0x63, 0x74, 0x6F, 0x72, 0x73, 0x00, 0x01, 0x07, 0x6F, 0x6E, 0x5F, 0x69, + 0x6E, 0x69, 0x74, 0x00, 0x01, 0x07, 0x6D, 0x79, 0x5F, 0x73, 0x71, 0x72, + 0x74, 0x00, 0x02, 0x0C, 0x6E, 0x75, 0x6C, 0x6C, 0x5F, 0x70, 0x6F, 0x69, + 0x6E, 0x74, 0x65, 0x72, 0x00, 0x03, 0x09, 0x6D, 0x79, 0x5F, 0x6D, 0x61, + 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x04, 0x0C, 0x5F, 0x5F, 0x64, 0x73, 0x6F, + 0x5F, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x03, 0x00, 0x0A, 0x5F, 0x5F, + 0x64, 0x61, 0x74, 0x61, 0x5F, 0x65, 0x6E, 0x64, 0x03, 0x01, 0x0D, 0x5F, + 0x5F, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x5F, 0x62, 0x61, 0x73, 0x65, + 0x03, 0x02, 0x0B, 0x5F, 0x5F, 0x68, 0x65, 0x61, 0x70, 0x5F, 0x62, 0x61, + 0x73, 0x65, 0x03, 0x03, 0x0D, 0x5F, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72, + 0x79, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x04, 0x0C, 0x5F, 0x5F, 0x74, + 0x61, 0x62, 0x6C, 0x65, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x05, 0x0A, + 0x1F, 0x04, 0x03, 0x00, 0x01, 0x0B, 0x0D, 0x00, 0x20, 0x01, 0x20, 0x01, + 0x6C, 0x20, 0x00, 0x20, 0x00, 0x6C, 0x6A, 0x0B, 0x04, 0x00, 0x41, 0x00, + 0x0B, 0x06, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0B, 0x00, 0x76, 0x09, 0x70, + 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x72, 0x73, 0x01, 0x0C, 0x70, 0x72, + 0x6F, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x2D, 0x62, 0x79, 0x01, 0x05, + 0x63, 0x6C, 0x61, 0x6E, 0x67, 0x56, 0x31, 0x31, 0x2E, 0x30, 0x2E, 0x30, + 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x6C, 0x6C, 0x76, + 0x6D, 0x2F, 0x6C, 0x6C, 0x76, 0x6D, 0x2D, 0x70, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x31, 0x37, 0x36, 0x32, 0x34, 0x39, 0x62, 0x64, 0x36, + 0x37, 0x33, 0x32, 0x61, 0x38, 0x30, 0x34, 0x34, 0x64, 0x34, 0x35, 0x37, + 0x30, 0x39, 0x32, 0x65, 0x64, 0x39, 0x33, 0x32, 0x37, 0x36, 0x38, 0x37, + 0x32, 0x34, 0x61, 0x36, 0x66, 0x30, 0x36, 0x29 +}; diff --git a/tests/unit/wasm-vm/wasm-apps/app4/m1.wasm b/tests/unit/wasm-vm/wasm-apps/app4/m1.wasm new file mode 100644 index 0000000000..6979e1801e Binary files /dev/null and b/tests/unit/wasm-vm/wasm-apps/app4/m1.wasm differ diff --git a/tests/unit/wasm-vm/wasm-apps/app4/m1.wat b/tests/unit/wasm-vm/wasm-apps/app4/m1.wat new file mode 100644 index 0000000000..2b97af8ec3 --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app4/m1.wat @@ -0,0 +1,14 @@ +(module + (func $f1 (export "f1") (result i32) (i32.const 1)) + + (memory $m1 1 2) + (table $t1 0 funcref) + (global $g1 i32 (i32.const 1)) + + (export "m1" (memory $m1)) + (export "m1_alias" (memory $m1)) + (export "t1" (table $t1)) + (export "t1_alias" (table $t1)) + (export "g1" (global $g1)) + (export "g1_alias" (global $g1)) +) \ No newline at end of file diff --git a/tests/unit/wasm-vm/wasm-apps/app4/m2.wasm b/tests/unit/wasm-vm/wasm-apps/app4/m2.wasm new file mode 100644 index 0000000000..e1a3059b35 Binary files /dev/null and b/tests/unit/wasm-vm/wasm-apps/app4/m2.wasm differ diff --git a/tests/unit/wasm-vm/wasm-apps/app4/m2.wat b/tests/unit/wasm-vm/wasm-apps/app4/m2.wat new file mode 100644 index 0000000000..340a3436bc --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app4/m2.wat @@ -0,0 +1,24 @@ +(module + (import "m1" "f1" (func $m1-f1 (result i32))) + (export "m1-f1" (func $m1-f1)) + + (import "m1" "m1" (memory $m1-m1 1 2)) + (import "m1" "t1" (table $m1-t1 0 funcref)) + (import "m1" "g1" (global $m1-g1 i32)) + + (func $f2 (export "f2") (param i32) (result i32) + (i32.add (call $m1-f1) (local.get 0)) + ) + + (func $f4 (result i32) (i32.const 3)) + + (func $f3 (export "f3") (param i32 i32) (result i32) + (i32.add + (call $m1-f1) + (i32.add + (call $f4) + (call $f2 (local.get 0)) + ) + ) + ) +) \ No newline at end of file diff --git a/tests/unit/wasm-vm/wasm-apps/app4/m3.wasm b/tests/unit/wasm-vm/wasm-apps/app4/m3.wasm new file mode 100644 index 0000000000..ecbff3d7b6 Binary files /dev/null and b/tests/unit/wasm-vm/wasm-apps/app4/m3.wasm differ diff --git a/tests/unit/wasm-vm/wasm-apps/app4/m3.wat b/tests/unit/wasm-vm/wasm-apps/app4/m3.wat new file mode 100644 index 0000000000..e300121ef5 --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/app4/m3.wat @@ -0,0 +1,7 @@ +(module + (import "m1" "f1" (func $m1-f1 (result i32))) + (import "m1" "m1_alias" (memory $m1-m1 1 2)) + (import "m1" "t1_alias" (table $m1-t1 0 funcref)) + (import "m1" "g1_alias" (global $m1-g1 i32)) + (import "m2" "f2" (func $m2-f2 (param i32) (result i32))) +) \ No newline at end of file diff --git a/tests/unit/wasm-vm/wasm-apps/binarydump b/tests/unit/wasm-vm/wasm-apps/binarydump new file mode 100755 index 0000000000..e7c4d2a1da Binary files /dev/null and b/tests/unit/wasm-vm/wasm-apps/binarydump differ diff --git a/tests/unit/wasm-vm/wasm-apps/build.sh b/tests/unit/wasm-vm/wasm-apps/build.sh new file mode 100755 index 0000000000..dbf062ae7a --- /dev/null +++ b/tests/unit/wasm-vm/wasm-apps/build.sh @@ -0,0 +1,32 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +## build app1 +/opt/wasi-sdk/bin/clang -O3 \ + -z stack-size=4096 -Wl,--initial-memory=65536 \ + -o app1/app1.wasm app1/main.c -Wl,--export-all \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--no-entry -nostdlib -Wl,--allow-undefined +./binarydump -o app1_wasm.h -n app1_wasm app1/app1.wasm +wavm disassemble app1/app1.wasm app1.wast +rm -f app1/app1.wasm + +## build app2 +/opt/wasi-sdk/bin/clang -O3 \ + -z stack-size=4096 -Wl,--initial-memory=65536 \ + -o app2/app2.wasm app2/main.c -Wl,--export-all \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--no-entry -nostdlib -Wl,--allow-undefined +./binarydump -o app2_wasm.h -n app2_wasm app2/app2.wasm +wavm disassemble app2/app2.wasm app2.wast +rm -f app2/app2.wasm + +## build app3 +/opt/wasi-sdk/bin/clang -O3 \ + -z stack-size=4096 -Wl,--initial-memory=65536 \ + -o app3/app3.wasm app3/main.c -Wl,--export-all \ + -Wl,--export=__heap_base,--export=__data_end \ + -Wl,--no-entry -nostdlib -Wl,--allow-undefined +./binarydump -o app3_wasm.h -n app3_wasm app3/app3.wasm +wavm disassemble app3/app3.wasm app3.wast +rm -f app3/app3.wasm diff --git a/tests/unit/wasm-vm/wasm_vm.cc b/tests/unit/wasm-vm/wasm_vm.cc new file mode 100644 index 0000000000..f4f5a834d1 --- /dev/null +++ b/tests/unit/wasm-vm/wasm_vm.cc @@ -0,0 +1,716 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "gtest/gtest.h" +#include "bh_platform.h" +#include "bh_read_file.h" +#include "wasm_export.h" +#if WASM_ENABLE_MULTI_MODULE != 0 +#include "wasm.h" +#include "wasm_runtime.h" +#endif +#include "wasm-apps/app1_wasm.h" +#include "wasm-apps/app2_wasm.h" +#include "wasm-apps/app3_wasm.h" + +#define EightK (8 * 1024) +// To use a test fixture, derive a class from testing::Test. +class WasmVMTest : public testing::Test +{ + protected: + // You should make the members protected s.t. they can be + // accessed from sub-classes. + + // virtual void SetUp() will be called before each test is run. You + // should define it if you need to initialize the varaibles. + // Otherwise, this can be skipped. + void SetUp() + { + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + ASSERT_EQ(wasm_runtime_full_init(&init_args), true); + + // bh_log_set_verbose_level(5); + + clean = true; + } + + // virtual void TearDown() will be called after each test is run. + // You should define it if there is cleanup work to do. Otherwise, + // you don't have to provide it. + // + void TearDown() + { + if (clean) { + wasm_runtime_destroy(); + } + } + + public: + wasm_module_t module = NULL; + wasm_module_inst_t module_inst = NULL; + wasm_function_inst_t func_inst = NULL; + wasm_exec_env_t exec_env = NULL; + char error_buf[128]; + char global_heap_buf[512 * 1024]; + RuntimeInitArgs init_args; + bool clean = true; +}; + +TEST_F(WasmVMTest, Test_app1) +{ + unsigned argv[10]; + + ASSERT_TRUE(app1_wasm != NULL); + + /* Load module */ + module = wasm_runtime_load(app1_wasm, sizeof(app1_wasm), error_buf, + sizeof(error_buf)); + if (module == nullptr) { + printf("error: %s\n", error_buf); + } + + ASSERT_TRUE(module != NULL); + + /* Initiate module */ + module_inst = wasm_runtime_instantiate(module, 8 * 1024, 8 * 1024, + error_buf, sizeof(error_buf)); + ASSERT_TRUE(module_inst != NULL); + + exec_env = wasm_runtime_create_exec_env(module_inst, 8 * 1024); + ASSERT_TRUE(exec_env != NULL); + + /* _on_init() function doesn't exist */ + func_inst = wasm_runtime_lookup_function(module_inst, "_on_init"); + ASSERT_TRUE(func_inst == NULL); + + /* on_init() function exists */ + func_inst = wasm_runtime_lookup_function(module_inst, "on_init"); + ASSERT_TRUE(func_inst != NULL); + + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_inst, 0, NULL) == true); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + + /* call my_malloc */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_malloc"); + ASSERT_TRUE(func_inst != NULL); + + /* malloc with very large size */ + argv[0] = 10 * 1024; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + wasm_runtime_clear_exception(module_inst); + ASSERT_EQ(argv[0], 0); + + /* malloc 1K, should success */ + argv[0] = 1024; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + + /* convert to native address */ + ASSERT_TRUE(wasm_runtime_validate_app_addr(module_inst, argv[0], 1)); + char *buf = (char *)wasm_runtime_addr_app_to_native(module_inst, argv[0]); + ASSERT_TRUE(buf != NULL); + + ASSERT_EQ(wasm_runtime_addr_native_to_app(module_inst, buf), argv[0]); + int32 buf_offset = argv[0]; + + /* call memcpy */ + char *buf1 = buf + 100; + memcpy(buf1, "123456", 7); + func_inst = wasm_runtime_lookup_function(module_inst, "my_memcpy"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset; + argv[1] = buf_offset + 100; + argv[2] = 7; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + ASSERT_TRUE(strcmp(buf, buf1) == 0); + + /* call strdup */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_strdup"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + + int32 buf_offset1 = argv[0]; + ASSERT_NE(buf_offset, buf_offset1); + + buf1 = (char *)wasm_runtime_addr_app_to_native(module_inst, buf_offset1); + ASSERT_TRUE(strcmp(buf, buf1) == 0); + + wasm_runtime_deinstantiate(module_inst); + wasm_runtime_unload(module); + wasm_runtime_destroy_exec_env(exec_env); +} + +TEST_F(WasmVMTest, Test_app2) +{ + unsigned argv[10]; + + /* Load module */ + module = wasm_runtime_load(app2_wasm, sizeof(app2_wasm), error_buf, + sizeof(error_buf)); + + ASSERT_TRUE(module != NULL); + + /* Initiate module */ + module_inst = wasm_runtime_instantiate(module, 8 * 1024, 8 * 1024, + error_buf, sizeof(error_buf)); + ASSERT_TRUE(module_inst != NULL); + + exec_env = wasm_runtime_create_exec_env(module_inst, 8 * 1024); + ASSERT_TRUE(exec_env != NULL); + + /* _on_init() function doesn't exist */ + func_inst = wasm_runtime_lookup_function(module_inst, "_on_init"); + ASSERT_TRUE(func_inst == NULL); + + /* on_init() function exists */ + func_inst = wasm_runtime_lookup_function(module_inst, "on_init"); + ASSERT_TRUE(func_inst != NULL); + + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_inst, 0, NULL) == true); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + + /* call my_malloc */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_malloc"); + ASSERT_TRUE(func_inst != NULL); + + /* malloc 1K, should success */ + argv[0] = 1024; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + + /* convert to native address */ + ASSERT_TRUE(wasm_runtime_validate_app_addr(module_inst, argv[0], 1)); + char *buf = (char *)wasm_runtime_addr_app_to_native(module_inst, argv[0]); + ASSERT_TRUE(buf != NULL); + + ASSERT_EQ(wasm_runtime_addr_native_to_app(module_inst, buf), argv[0]); + int32 buf_offset = argv[0]; + + /* call memcpy */ + char *buf1 = buf + 100; + memcpy(buf1, "123456", 7); + func_inst = wasm_runtime_lookup_function(module_inst, "my_memcpy"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset; + argv[1] = buf_offset + 100; + argv[2] = 7; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + ASSERT_TRUE(strcmp(buf, buf1) == 0); + + /* call memcmp */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_memcmp"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset; + argv[1] = buf_offset + 100; + argv[2] = 7; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + + ASSERT_TRUE(argv[0] == 0); + + /* call printf */ + char *format = buf + 200; + memcpy(format, "string0 is %s", 13); + func_inst = wasm_runtime_lookup_function(module_inst, "my_printf"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = wasm_runtime_addr_native_to_app(module_inst, format); + argv[1] = buf_offset; + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + ASSERT_TRUE(argv[0] == 17); + + /* call sprintf */ + memcpy(format, "string1 is %s", 13); + func_inst = wasm_runtime_lookup_function(module_inst, "my_sprintf"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset + 300; + int32 argv0_tmp = argv[0]; + argv[1] = wasm_runtime_addr_native_to_app(module_inst, format); + argv[2] = buf_offset; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + + ASSERT_TRUE( + memcmp((char *)wasm_runtime_addr_app_to_native(module_inst, argv0_tmp), + "string1 is 123456", 17) + == 0); + ASSERT_TRUE(argv[0] == 17); + + /* call snprintf */ + memcpy(format, "string2 is %s", 13); + func_inst = wasm_runtime_lookup_function(module_inst, "my_snprintf"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset + 400; + argv0_tmp = argv[0]; + argv[1] = 3; + argv[2] = wasm_runtime_addr_native_to_app(module_inst, format); + argv[3] = buf_offset; + wasm_runtime_call_wasm(exec_env, func_inst, 4, argv); + + ASSERT_TRUE( + memcmp((char *)wasm_runtime_addr_app_to_native(module_inst, argv0_tmp), + "st\0", 3) + == 0); + ASSERT_TRUE(argv[0] == 17); + + /* call puts */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_puts"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + + ASSERT_TRUE(argv[0] != EOF); + + /* call putchar */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_putchar"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + + ASSERT_TRUE(argv[0] != EOF); + + /* call memmove without memory coverage*/ + func_inst = wasm_runtime_lookup_function(module_inst, "my_memmove"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset + 10; + argv[1] = buf_offset + 100; + argv[2] = 6; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + + buf1 = (char *)wasm_runtime_addr_app_to_native(module_inst, argv[0]); + ASSERT_TRUE(strcmp(buf + 100, buf1) == 0); + ASSERT_TRUE(memcmp(buf1, "123456", 6) == 0); + + /* call memmove with memory coverage*/ + func_inst = wasm_runtime_lookup_function(module_inst, "my_memmove"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset + 95; + argv[1] = buf_offset + 100; + argv[2] = 6; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + + buf1 = (char *)wasm_runtime_addr_app_to_native(module_inst, argv[0]); + ASSERT_TRUE(strcmp(buf + 100, buf1) != 0); + ASSERT_TRUE(memcmp(buf1, "123456", 6) == 0); + ASSERT_TRUE(memcmp(buf + 100, "623456", 6) == 0); + + /* call memset*/ + func_inst = wasm_runtime_lookup_function(module_inst, "my_memset"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset + 100; + argv[1] = 48; + argv[2] = 4; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + ASSERT_TRUE(memcmp(buf + 100, "000056", 6) == 0); + + /* call strchr*/ + func_inst = wasm_runtime_lookup_function(module_inst, "my_strchr"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset; + argv[1] = 49; // asc2 for char "1" + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + + buf1 = (char *)wasm_runtime_addr_app_to_native(module_inst, argv[0]); + ASSERT_TRUE(buf1 - buf == 0); + + /* call strcmp */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_strcmp"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset; + argv[1] = buf_offset; + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + + ASSERT_TRUE(argv[0] == 0); + + argv[0] = buf_offset; + argv[1] = buf_offset + 1; + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + + ASSERT_TRUE(argv[0] != 0); + + /* call strcpy */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_strcpy"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset + 110; + argv[1] = buf_offset; + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + ASSERT_TRUE(memcmp(buf + 110, "123456", 6) == 0); + + /* call strlen */ + buf1 = buf + 110; + memcpy(buf1, "123456\0", 7); + func_inst = wasm_runtime_lookup_function(module_inst, "my_strlen"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset + 110; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + + ASSERT_TRUE(argv[0] == 6); + + /* call strncmp */ + buf1 = buf + 110; + memcpy(buf1, "123457", 6); + func_inst = wasm_runtime_lookup_function(module_inst, "my_strncmp"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset; + argv[1] = buf_offset + 110; + argv[2] = 5; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + + ASSERT_TRUE(argv[0] == 0); + + argv[0] = buf_offset; + argv[1] = buf_offset + 110; + argv[2] = 6; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + + ASSERT_TRUE(argv[0] != 0); + + /* call strncpy */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_strncpy"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset + 130; + argv[1] = buf_offset; + argv[2] = 5; + wasm_runtime_call_wasm(exec_env, func_inst, 3, argv); + + buf1 = (char *)wasm_runtime_addr_app_to_native(module_inst, argv[0]); + ASSERT_TRUE(memcmp(buf, buf1, 5) == 0); + ASSERT_TRUE(memcmp(buf, buf1, 6) != 0); + + /* call _my_calloc */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_calloc"); + ASSERT_TRUE(func_inst != NULL); + /* calloc, should success */ + argv[0] = 10; + argv[1] = 4; + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + + /* convert to native address */ + ASSERT_TRUE(wasm_runtime_validate_app_addr(module_inst, argv[0], 40)); + char *buf2 = (char *)wasm_runtime_addr_app_to_native(module_inst, argv[0]); + ASSERT_TRUE(buf2 != NULL); + + ASSERT_EQ(wasm_runtime_addr_native_to_app(module_inst, buf2), argv[0]); + int32 buf_offset1 = argv[0]; + + /* call _my_free */ + memcpy(buf2, "123456", 6); + func_inst = wasm_runtime_lookup_function(module_inst, "my_free"); + ASSERT_TRUE(func_inst != NULL); + argv[0] = buf_offset1; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + + ASSERT_TRUE(memcmp(buf2, "123456", 6) != 0); + + wasm_runtime_deinstantiate(module_inst); + wasm_runtime_unload(module); + wasm_runtime_destroy_exec_env(exec_env); +} + +TEST_F(WasmVMTest, Test_app3) +{ + unsigned argv[10]; + + /* Load module */ + module = wasm_runtime_load(app3_wasm, sizeof(app3_wasm), error_buf, + sizeof(error_buf)); + + ASSERT_TRUE(module != NULL); + + /* Initiate module */ + module_inst = wasm_runtime_instantiate(module, 8 * 1024, 8 * 1024, + error_buf, sizeof(error_buf)); + ASSERT_TRUE(module_inst != NULL); + + exec_env = wasm_runtime_create_exec_env(module_inst, 8 * 1024); + ASSERT_TRUE(exec_env != NULL); + + /* _on_init() function doesn't exist */ + func_inst = wasm_runtime_lookup_function(module_inst, "_on_init"); + ASSERT_TRUE(func_inst == NULL); + + /* on_init() function exists */ + func_inst = wasm_runtime_lookup_function(module_inst, "on_init"); + ASSERT_TRUE(func_inst != NULL); + + ASSERT_TRUE(wasm_runtime_call_wasm(exec_env, func_inst, 0, NULL) == true); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + + /* call my_malloc */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_malloc"); + ASSERT_TRUE(func_inst != NULL); + + /* malloc with very large size */ + argv[0] = 10 * 1024; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + wasm_runtime_clear_exception(module_inst); + ASSERT_EQ(argv[0], 0); + + /* malloc 1K, should success */ + argv[0] = 1024; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + + /* convert to native address */ + ASSERT_TRUE(wasm_runtime_validate_app_addr(module_inst, argv[0], 1)); + char *buf = (char *)wasm_runtime_addr_app_to_native(module_inst, argv[0]); + ASSERT_TRUE(buf != NULL); + + ASSERT_EQ(wasm_runtime_addr_native_to_app(module_inst, buf), argv[0]); + int32 buf_offset = argv[0]; + + /* call my_malloc */ + func_inst = wasm_runtime_lookup_function(module_inst, "my_malloc"); + ASSERT_TRUE(func_inst != NULL); + + /* malloc, should success */ + argv[0] = 10; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + + /* convert to native address */ + ASSERT_TRUE(wasm_runtime_validate_app_addr(module_inst, argv[0], 1)); + char *buf1 = (char *)wasm_runtime_addr_app_to_native(module_inst, argv[0]); + ASSERT_TRUE(buf1 != NULL); + + ASSERT_EQ(wasm_runtime_addr_native_to_app(module_inst, buf1), argv[0]); + int32 buf_offset1 = argv[0]; + + wasm_runtime_deinstantiate(module_inst); + wasm_runtime_unload(module); + wasm_runtime_destroy_exec_env(exec_env); +} + +#if WASM_ENABLE_MULTI_MODULE != 0 +static const char *module_search_path = "."; +static bool call_destroyer = false; +static bool +module_reader_callback(package_type_t module_type, const char *module_name, + uint8 **p_buffer, uint32 *p_size) +{ + const char *format = "%s/%s.wasm"; + int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + + strlen(".wasm") + 1; + char *wasm_file_name = (char *)BH_MALLOC(sz); + if (!wasm_file_name) { + return false; + } + + snprintf(wasm_file_name, sz, format, module_search_path, module_name); + printf("going to open %s\n", wasm_file_name); + + call_destroyer = false; + *p_buffer = (uint8_t *)bh_read_file_to_buffer(wasm_file_name, p_size); + + BH_FREE(wasm_file_name); + return *p_buffer != NULL; +} + +static void +module_destroyer_callback(uint8 *buffer, uint32 size) +{ + wasm_runtime_free(buffer); + call_destroyer = true; +} + +TEST_F(WasmVMTest, Test_app4_single) +{ + uint8 *buffer = NULL; + uint32 buffer_size = 0; + bool ret = false; + unsigned argv[10]; + + wasm_runtime_set_module_reader(&module_reader_callback, + &module_destroyer_callback); + + /* m1 only */ + ret = module_reader_callback(Wasm_Module_Bytecode, "m1", &buffer, + &buffer_size); + ASSERT_TRUE(ret); + ASSERT_TRUE(buffer_size > 0); + ASSERT_TRUE(buffer != NULL); + + module = + wasm_runtime_load(buffer, buffer_size, error_buf, sizeof(error_buf)); + ASSERT_TRUE(module != NULL); + + ASSERT_FALSE(wasm_runtime_find_module_registered("m1")); + + wasm_runtime_register_module("m1", module, error_buf, sizeof(error_buf)); + + ASSERT_TRUE(wasm_runtime_find_module_registered("m1")); + + module_inst = wasm_runtime_instantiate(module, EightK, EightK, error_buf, + sizeof(error_buf)); + ASSERT_TRUE(module_inst != NULL); + + exec_env = wasm_runtime_create_exec_env(module_inst, EightK); + ASSERT_TRUE(exec_env != NULL); + + func_inst = wasm_runtime_lookup_function(module_inst, "f1"); + ASSERT_TRUE(func_inst != NULL); + ASSERT_FALSE(((WASMFunctionInstance *)func_inst)->is_import_func); + ASSERT_TRUE(((WASMFunctionInstance *)func_inst)->param_cell_num == 0); + ASSERT_TRUE(((WASMFunctionInstance *)func_inst)->ret_cell_num == 1); + + wasm_runtime_call_wasm(exec_env, func_inst, 0, argv); + printf("exception is %s", wasm_runtime_get_exception(module_inst)); + + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + ASSERT_TRUE(argv[0] == 1); + + wasm_runtime_destroy_exec_env(exec_env); + wasm_runtime_deinstantiate(module_inst); + wasm_runtime_unload(module); + + // call destroyer and without exception + ASSERT_FALSE(call_destroyer); + module_destroyer_callback(buffer, buffer_size); + + clean = false; + wasm_runtime_destroy(); +} + +TEST_F(WasmVMTest, Test_app4_plus_one) +{ + uint8 *buffer = NULL; + uint32 buffer_size = 0; + bool ret = false; + uint32_t argv[10] = { 0 }; + + wasm_runtime_set_module_reader(&module_reader_callback, + &module_destroyer_callback); + + /* m2 -> m1 */ + ret = module_reader_callback(Wasm_Module_Bytecode, "m2", &buffer, + &buffer_size); + ASSERT_TRUE(ret); + ASSERT_TRUE(buffer_size > 0); + ASSERT_TRUE(buffer != NULL); + + module = + wasm_runtime_load(buffer, buffer_size, error_buf, sizeof(error_buf)); + ASSERT_TRUE(module != NULL); + + module_inst = wasm_runtime_instantiate(module, EightK, EightK, error_buf, + sizeof(error_buf)); + ASSERT_TRUE(module_inst != NULL); + + exec_env = wasm_runtime_create_exec_env(module_inst, EightK); + ASSERT_TRUE(exec_env != NULL); + + printf("------------------- m1-f1 ---------------------\n"); + func_inst = wasm_runtime_lookup_function(module_inst, "m1-f1"); + ASSERT_TRUE(func_inst != NULL); + ASSERT_TRUE(((WASMFunctionInstance *)func_inst)->is_import_func); + ASSERT_TRUE(((WASMFunctionInstance *)func_inst)->param_cell_num == 0); + ASSERT_TRUE(((WASMFunctionInstance *)func_inst)->ret_cell_num == 1); + + wasm_runtime_call_wasm(exec_env, func_inst, 0, argv); + printf("exception is %s\n", wasm_runtime_get_exception(module_inst)); + + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + ASSERT_TRUE(argv[0] == 1); + + printf("------------------- f2 ---------------------\n"); + func_inst = wasm_runtime_lookup_function(module_inst, "f2"); + ASSERT_TRUE(func_inst != NULL); + ASSERT_FALSE(((WASMFunctionInstance *)func_inst)->is_import_func); + ASSERT_TRUE(((WASMFunctionInstance *)func_inst)->param_cell_num == 1); + ASSERT_TRUE(((WASMFunctionInstance *)func_inst)->ret_cell_num == 1); + + argv[0] = 2; + wasm_runtime_call_wasm(exec_env, func_inst, 1, argv); + printf("exception is %s\n", wasm_runtime_get_exception(module_inst)); + + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + ASSERT_TRUE(argv[0] == 3); + + printf("------------------- f3 ---------------------\n"); + func_inst = wasm_runtime_lookup_function(module_inst, "f3"); + ASSERT_TRUE(func_inst != NULL); + ASSERT_FALSE(((WASMFunctionInstance *)func_inst)->is_import_func); + ASSERT_TRUE(((WASMFunctionInstance *)func_inst)->param_cell_num == 2); + ASSERT_TRUE(((WASMFunctionInstance *)func_inst)->ret_cell_num == 1); + + argv[0] = 4; + argv[1] = 9; + wasm_runtime_call_wasm(exec_env, func_inst, 2, argv); + printf("exception is %s\n", wasm_runtime_get_exception(module_inst)); + + ASSERT_TRUE(wasm_runtime_get_exception(module_inst) == NULL); + ASSERT_TRUE(argv[0] == 9); + + wasm_runtime_destroy_exec_env(exec_env); + wasm_runtime_deinstantiate(module_inst); + + wasm_runtime_unload(module); + ASSERT_FALSE(call_destroyer); +} + +TEST_F(WasmVMTest, Test_app4_family) +{ + uint8 *buffer = NULL; + uint32 buffer_size = 0; + bool ret = false; + + wasm_runtime_set_module_reader(&module_reader_callback, + &module_destroyer_callback); + + /* m3 -> m2[->m1], m1 */ + ret = module_reader_callback(Wasm_Module_Bytecode, "m3", &buffer, + &buffer_size); + ASSERT_TRUE(ret); + ASSERT_TRUE(buffer_size > 0); + ASSERT_TRUE(buffer != NULL); + module = + wasm_runtime_load(buffer, buffer_size, error_buf, sizeof(error_buf)); + ASSERT_TRUE(module != NULL); + + wasm_runtime_unload(module); + ASSERT_FALSE(call_destroyer); +} + +static const WASMModule * +search_sub_module(const WASMModule *parent_module, const char *sub_module_name) +{ + WASMRegisteredModule *node = (WASMRegisteredModule *)bh_list_first_elem( + parent_module->import_module_list); + while (node && strcmp(node->module_name, sub_module_name)) { + node = (WASMRegisteredModule *)bh_list_elem_next(node); + } + return node ? (WASMModule *)node->module : NULL; +} + +TEST_F(WasmVMTest, Test_app4_reuse) +{ + uint8 *buffer = NULL; + uint32 buffer_size = 0; + bool ret = false; + + wasm_runtime_set_module_reader(&module_reader_callback, + &module_destroyer_callback); + + /* m3 -> m2[->m1], m1 */ + ret = module_reader_callback(Wasm_Module_Bytecode, "m3", &buffer, + &buffer_size); + ASSERT_TRUE(buffer != NULL); + + WASMModule *m3 = (WASMModule *)wasm_runtime_load( + buffer, buffer_size, error_buf, sizeof(error_buf)); + ASSERT_TRUE(m3 != NULL); + + const WASMModule *m2 = search_sub_module(m3, "m2"); + const WASMModule *m1_in_m2 = search_sub_module(m2, "m1"); + const WASMModule *m1_in_m3 = search_sub_module(m3, "m1"); + ASSERT_EQ(m1_in_m2, m1_in_m3); +} +#endif /* WASM_ENABLE_MULTI_MODULE */