diff --git a/.gitignore b/.gitignore index 1dd19478c2c..b88109b38e0 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ options-pinned.h # files related to building in-tree CMakeFiles *.cmake -!src/tools/wasm2c/gen-wasm2c-templates.cmake /CMakeCache.txt /Makefile /*.ninja diff --git a/.gitmodules b/.gitmodules index 6251faea65b..a674125e389 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,3 @@ [submodule "third_party/mimalloc"] path = third_party/mimalloc url = https://github.com/microsoft/mimalloc.git -[submodule "third_party/simde"] - path = third_party/simde - url = https://github.com/simd-everywhere/simde -[submodule "third_party/picosha2"] - path = third_party/picosha2 - url = https://github.com/okdshin/PicoSHA2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 878b5603965..1c139b6a985 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,8 +409,8 @@ else() # MSVC add_compile_flag("-Wno-unknown-warning-option") add_compile_flag("-Wswitch") # we explicitly expect this in the code add_compile_flag("-Wimplicit-fallthrough") - add_compile_flag("-Wnon-virtual-dtor" "CXX_ONLY") - add_compile_flag("-Wsuggest-override" "CXX_ONLY") + add_compile_flag("-Wnon-virtual-dtor") + add_compile_flag("-Wsuggest-override") if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # Google style requires this, so make sure we compile cleanly with it. diff --git a/check.py b/check.py index 6fae58c85dc..3d1ca8aef46 100755 --- a/check.py +++ b/check.py @@ -25,15 +25,7 @@ from multiprocessing.pool import ThreadPool from pathlib import Path -from scripts.test import ( - binaryenjs, - finalize, - shared, - support, - wasm2c, - wasm2js, - wasm_opt, -) +from scripts.test import binaryenjs, finalize, shared, support, wasm2js, wasm_opt from scripts.test.shared import print_heading assert sys.version_info >= (3, 10), 'requires Python 3.10' @@ -450,7 +442,6 @@ def wrapper(*args, **kwargs): 'spec': run_spec_tests, 'finalize': finalize.test_wasm_emscripten_finalize, 'wasm2js': wasm2js.test_wasm2js, - 'wasm2c-spec': wasm2c.test_wasm2c_spec, 'validator': run_validator_tests, 'example': run_example_tests, 'unit': run_unittest, diff --git a/scripts/clang-tidy-diff.sh b/scripts/clang-tidy-diff.sh index 21eb3120e3f..84ddda9b30f 100755 --- a/scripts/clang-tidy-diff.sh +++ b/scripts/clang-tidy-diff.sh @@ -24,7 +24,7 @@ function realpath() { CLANG_DIR=$(dirname $(dirname $(realpath $CLANG_TIDY))) CLANG_TIDY_DIFF=$CLANG_DIR/share/clang/clang-tidy-diff.py -ARG="-quiet -p1 -only-check-in-db -iregex=src/.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm)" +ARG="-quiet -p1 -iregex=src/.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm)" if [ ! -e "$CLANG_TIDY_DIFF" ]; then echo "Failed to find clang-tidy-diff.py ($CLANG_TIDY_DIFF)" exit 1 diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 30b560481bf..042c784c511 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -207,7 +207,6 @@ def is_exe(fpath): WASM_AS = [os.path.join(options.binaryen_bin, 'wasm-as')] WASM_DIS = [os.path.join(options.binaryen_bin, 'wasm-dis')] WASM2JS = [os.path.join(options.binaryen_bin, 'wasm2js')] -WASM2C = [os.path.join(options.binaryen_bin, 'wasm2c')] WASM_CTOR_EVAL = [os.path.join(options.binaryen_bin, 'wasm-ctor-eval')] WASM_SHELL = [os.path.join(options.binaryen_bin, 'wasm-shell')] WASM_REDUCE = [os.path.join(options.binaryen_bin, 'wasm-reduce')] diff --git a/scripts/test/wasm2c.py b/scripts/test/wasm2c.py deleted file mode 100644 index a5643f34703..00000000000 --- a/scripts/test/wasm2c.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2026 WebAssembly Community Group participants -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pathlib - -from . import shared, support -from .shared import print_heading - -spec_tests = [ -] - - -def test_wasm2c_spec_output(): - for t in shared.options.spec_tests: - test_path = pathlib.Path(t) - if test_path.name not in spec_tests: - continue - - print('..', test_path.name) - - is_fail_test = '.fail' in test_path.name - - test_subdir = f'wasm2c_spec_{test_path.stem}' - test_subdir_path = pathlib.Path(test_subdir) - test_subdir_path.mkdir(exist_ok=True) - - wasm2c_cmd = [shared.WASM2C[0], t, '-o', f'{test_subdir}/{test_path.stem}.c', '--allow-asserts'] - support.run_command(wasm2c_cmd, expected_status=(1 if is_fail_test else 0)) - - c_sources = sorted(test_subdir_path.glob('*.c')) - - wasm_rt_dir = pathlib.Path(shared.options.binaryen_root) / 'src' / 'tools' / 'wasm2c' / 'wasm-rt' - c_sources.append(wasm_rt_dir / 'wasm-rt-impl.c') - c_sources.append(wasm_rt_dir / 'wasm-rt-mem-impl.c') - c_sources.append(wasm_rt_dir / 'wasm-rt-exceptions-impl.c') - - compile_cmd = [shared.NATIVECC, '-O2', '-std=c11', '-D_GNU_SOURCE', '-D_DEFAULT_SOURCE', '-I.', f"-I{wasm_rt_dir}"] + [str(s) for s in c_sources] + ['-o', f'{test_subdir}/spec_test_runner'] - - compile_cmd += ['-fno-optimize-sibling-calls', '-frounding-math'] - if 'gcc' in shared.NATIVECC.lower(): - compile_cmd.append('-fsignaling-nans') - - compile_cmd.append('-lm') - compile_cmd.append('-lpthread') - - support.run_command(compile_cmd) - - # Run spec test runner binary and assert success - support.run_command([f'{test_subdir}/spec_test_runner']) - - -def test_wasm2c_spec(): - print_heading('checking wasm2c spec testcases...') - if shared.skip_if_on_windows('wasm2c-spec'): - return - test_wasm2c_spec_output() diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 4bd2c41d0b3..91fea46b1df 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -11,7 +11,6 @@ set(fuzzing_SOURCES binaryen_add_executable(wasm-opt "${fuzzing_SOURCES};wasm-opt.cpp") binaryen_add_executable(wasm-metadce wasm-metadce.cpp) binaryen_add_executable(wasm2js wasm2js.cpp) -add_subdirectory(wasm2c) binaryen_add_executable(wasm-emscripten-finalize wasm-emscripten-finalize.cpp) binaryen_add_executable(wasm-as wasm-as.cpp) binaryen_add_executable(wasm-dis wasm-dis.cpp) diff --git a/src/tools/wasm2c/CMakeLists.txt b/src/tools/wasm2c/CMakeLists.txt deleted file mode 100644 index 63453c6b771..00000000000 --- a/src/tools/wasm2c/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -set(PREBUILT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/prebuilt) - -set(WASM2C_TEMPLATE_SOURCES - ${PREBUILT_DIR}/wasm2c_header_top.cpp - ${PREBUILT_DIR}/wasm2c_header_bottom.cpp - ${PREBUILT_DIR}/wasm2c_source_includes.cpp - ${PREBUILT_DIR}/wasm2c_source_declarations.cpp - ${PREBUILT_DIR}/wasm2c_simd_source_declarations.cpp - ${PREBUILT_DIR}/wasm2c_atomicops_source_declarations.cpp - ${PREBUILT_DIR}/wasm2c_spec_top.cpp -) - -binaryen_add_executable(wasm2c "wasm2c-builder.cpp;assertion-emitter.cpp;wasm2c.cpp;${WASM2C_TEMPLATE_SOURCES}") -# TODO: https://github.com/WebAssembly/binaryen/issues/8775 - stop using picosha2 -target_include_directories(wasm2c PRIVATE ${PROJECT_SOURCE_DIR}/third_party/picosha2 ${PROJECT_SOURCE_DIR}/src/tools/wasm2c) diff --git a/src/tools/wasm2c/README.md b/src/tools/wasm2c/README.md deleted file mode 100644 index b7ab3bca2e4..00000000000 --- a/src/tools/wasm2c/README.md +++ /dev/null @@ -1,722 +0,0 @@ -# wasm2c: Convert wasm files to C source and header - -`wasm2c` takes a WebAssembly module and produces an equivalent C source and -header. Some examples: - -```sh -# parse binary file test.wasm and write test.c and test.h -$ wasm2c test.wasm -o test.c - -# parse test.wasm, write test.c and test.h, but ignore the debug names, if any -$ wasm2c test.wasm --no-debug-names -o test.c -``` - -The C code produced targets the C99 standard. If, however, the Wasm module uses -Wasm threads/atomics, the code produced targets the C11 standard. - -## Tutorial: .wat -> .wasm -> .c - -Let's look at a simple example of a factorial function. - -```wasm -(memory $mem 1) -(func (export "fac") (param $x i32) (result i32) - (if (result i32) (i32.eq (local.get $x) (i32.const 0)) - (then (i32.const 1)) - (else - (i32.mul (local.get $x) (call 0 (i32.sub (local.get $x) (i32.const 1)))) - ) - ) -) -``` - -Save this to `fac.wat`. We can convert this to a `.wasm` file by using the -`wat2wasm` tool: - -```sh -$ wat2wasm fac.wat -o fac.wasm -``` - -We can then convert it to a C source and header by using the `wasm2c` tool: - -```sh -$ wasm2c fac.wasm -o fac.c -``` - -This generates two files, `fac.c` and `fac.h`. We'll take a closer look at -these files below, but first let's show a simple example of how to use these -files. - -## Using the generated module - -To actually use our `fac` module, we'll use create a new file, `main.c`, that -include `fac.h`, initializes the module, and calls `fac`. - -`wasm2c` generates a few C symbols based on the `fac.wasm` module. -The first is `w2c_fac`, a type that represents an instance of the -`fac` module. `wasm2c` generates functions that construct and free a -`w2c_fac` instance: `wasm2c_fac_instantiate` and -`wasm2c_fac_free`. Finally, `wasm2c` generates the exported `fac` -function itself (`w2c_fac_fac`), which acts on a `w2c_fac` instance. - -All the exported symbols shared a common module ID (`fac`) which, by default, is -based on the name section in the module or the name of input file. This prefix -can be overridden using the `-n/--module-name` command line flag. - -```c -#include -#include - -#include "fac.h" - -int main(int argc, char** argv) { - /* Make sure there is at least one command-line argument. */ - if (argc < 2) { - printf("Invalid argument. Expected '%s NUMBER'\n", argv[0]); - return 1; - } - - /* Convert the argument from a string to an int. We'll implicitly cast the int - to a `u32`, which is what `fac` expects. */ - u32 x = atoi(argv[1]); - - /* Initialize the Wasm runtime. */ - wasm_rt_init(); - - /* Declare an instance of the `fac` module. */ - w2c_fac fac; - - /* Construct the module instance. */ - wasm2c_fac_instantiate(&fac); - - /* Call `fac`, using the mangled name. */ - u32 result = w2c_fac_fac(&fac, x); - - /* Print the result. */ - printf("fac(%u) -> %u\n", x, result); - - /* Free the fac module. */ - wasm2c_fac_free(&fac); - - /* Free the Wasm runtime state. */ - wasm_rt_free(); - - return 0; -} - -``` - -## Compiling the wasm2c output - -To compile the executable, we need to use `main.c` and the generated `fac.c`. -We'll also include `wasm-rt-impl.c` and `wasm-rt-mem-impl.c`, which have implementations of the various -`wasm_rt_*` functions used by `fac.c` and `fac.h`. - -```sh -$ cc -o fac main.c fac.c wasm2c/wasm-rt-impl.c wasm2c/wasm-rt-mem-impl.c -Iwasm2c -lm -``` - -A note on compiling with optimization: wasm2c relies on certain -behavior from the C compiler to maintain conformance with the -WebAssembly specification, especially with regards to requirements to -convert "signaling" to "quiet" floating-point NaN values and for -infinite recursion to produce a trap. When compiling with optimization -(e.g. `-O2` or `-O3`), it's necessary to disable some optimizations to -preserve conformance. With GCC 11, adding the command-line arguments -`-fno-optimize-sibling-calls -frounding-math -fsignaling-nans` appears -to be sufficient. With clang 14, just `-fno-optimize-sibling-calls --frounding-math` appears to be sufficient. - -Now let's test it out! - -```sh -$ ./fac 1 -fac(1) -> 1 -$ ./fac 5 -fac(5) -> 120 -$ ./fac 10 -fac(10) -> 3628800 -``` - -You can take a look at the all of these files in -[wasm2c/examples/fac](/wasm2c/examples/fac). - -### Enabling extra sanity checks - -Wasm2c provides a macro `WASM_RT_SANITY_CHECKS` that if defined enables -additional sanity checks in the produced Wasm2c code. Note that this may have a -high performance overhead, and is thus only recommended for debug builds. - -### Enabling Segue (a Linux x86_64 target specific optimization) - -Wasm2c can use the "Segue" optimization if allowed. The segue optimization uses -an x86 segment register to store the location of Wasm's linear memory, when -compiling a Wasm module with clang, running on x86_64 Linux, the macro -`WASM_RT_ALLOW_SEGUE` is defined, and the flag `-mfsgsbase` is passed to clang. -Segue is not used if - -1. The Wasm module uses a more than a single unshared imported or exported - memory -2. The wasm2c code is compiled with GCC. Segue requires intrinsics for - (rd|wr)gsbase, "address namespaces" for accessing pointers, and support for - memcpy on pointers with custom "address namespaces". GCC does not support the - memcpy requirement. -3. The code is compiled for Windows as Windows doesn't restore the segment - register on context switch. - -The wasm2c generated code automatically sets the unused segment register (the -`%gs` register on x86_64 Linux) during the function calls into wasm2c generated -module, restores it after calls to external modules etc. Any host function -written in C would continue to work without changes as C code does not modify -the unused segment register `%gs` (See -[here](https://www.kernel.org/doc/html/next/x86/x86_64/fsgs.html) for details). -However, any host functions written in assembly that clobber the free segment -register must restore the value of this register prior to executing or returning -control to wasm2c generated code. - -As an additional optimization, if the host program does not use the `%gs` -segment register for any other purpose (which is typically the case in most -programs), you can additionally allow wasm2c to unconditionally overwrite the -value of the `%gs` register without restoring the old value. This can be done -defining the macro `WASM_RT_SEGUE_FREE_SEGMENT`. - -You can test the performance of the Segue optimization by running Dhrystone with -and without Segue: - -```bash -cd wasm2c/benchmarks/segue && make -``` - -## Looking at the generated header, `fac.h` - -The generated header file looks something like this: - -```c -/* Automatically generated by wasm2c */ -#ifndef FAC_H_GENERATED_ -#define FAC_H_GENERATED_ - -... - -#include "wasm-rt.h" - -... -#ifndef WASM_RT_CORE_TYPES_DEFINED -#define WASM_RT_CORE_TYPES_DEFINED - -... - -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct w2c_fac { - char dummy_member; -} w2c_fac; - -void wasm2c_fac_instantiate(w2c_fac*); -void wasm2c_fac_free(w2c_fac*); -wasm_rt_func_type_t wasm2c_fac_get_func_type(uint32_t param_count, uint32_t result_count, ...); - -/* export: 'fac' */ -u32 w2c_fac_fac(w2c_fac*, u32); - -#ifdef __cplusplus -} -#endif - -#endif /* FAC_H_GENERATED_ */ - -``` - -Let's look at each section. The outer `#ifndef` is standard C -boilerplate for a header. This `WASM_RT_CORE_TYPES_DEFINED` section -contains a number of definitions required for all WebAssembly -modules. The `extern "C"` part makes sure to not mangle the symbols if -using this header in C++. - -The included `wasm-rt.h` file also includes a number of relevant definitions. -First is the `wasm_rt_trap_t` enum, which is used to give the reason a trap -occurred. - -```c -typedef enum { - WASM_RT_TRAP_NONE, - WASM_RT_TRAP_OOB, - WASM_RT_TRAP_INT_OVERFLOW, - WASM_RT_TRAP_DIV_BY_ZERO, - WASM_RT_TRAP_INVALID_CONVERSION, - WASM_RT_TRAP_UNREACHABLE, - WASM_RT_TRAP_CALL_INDIRECT, - WASM_RT_TRAP_UNCAUGHT_EXCEPTION, - WASM_RT_TRAP_EXHAUSTION, -} wasm_rt_trap_t; -``` - -Next is the `wasm_rt_type_t` enum, which is used for specifying function -signatures. Six WebAssembly value types are included: - -```c -typedef enum { - WASM_RT_I32, - WASM_RT_I64, - WASM_RT_F32, - WASM_RT_F64, - WASM_RT_FUNCREF, - WASM_RT_EXTERNREF, -} wasm_rt_type_t; - -Next is `wasm_rt_function_ptr_t`, the function signature for a generic function -callback. Since a WebAssembly table can contain functions of any given -signature, it is necessary to convert them to a canonical form: - -```c -typedef void (*wasm_rt_function_ptr_t)(void); -``` - -Next is the definition for a function reference (in WebAssembly 1.0, -this was the type of all table elements, but funcrefs can now also be -used as ordinary values, and tables can alternately be declared as -type externref). In this structure, `wasm_rt_func_type_t` is an opaque -256-bit ID that can be looked up via the `Z_[modname]_get_func_type` -function. (A demonstration of this can be found in the `callback` -example.) `module_instance` is the pointer to the function's -originating module instance, which will be passed in when the func is -called. - -```c -typedef struct { - wasm_rt_func_type_t func_type; - wasm_rt_function_ptr_t func; - void* module_instance; -} wasm_rt_funcref_t; - -``` - -Next is the definition of a memory instance. The `data` field is a pointer to -`size` bytes of linear memory. The `size` field of `wasm_rt_memory_t` is the -current size of the memory instance in bytes, `pages` is the current -size in pages, and `page_size` contains the page size in bytes (65,536 by default). -`max_pages` is the maximum number of pages specified by the module or allowed -by the memory index type (`is64` is true for memories that can grow to 2^64 bytes; -`false` for memories limited to 2^32 bytes). - -```c -typedef struct { - uint8_t* data; - uint32_t page_size; - uint64_t pages, max_pages; - uint64_t size; - bool is64; -} wasm_rt_memory_t; -``` - -This is followed by the definition of a shared memory instance. This is similar -to a regular memory instance, but represents memory that can be used by multiple -Wasm instances, and thus enforces a minimum amount of memory order on -operations. The Shared memory definition has one additional member, `mem_lock`, -which is a lock that is used during memory grow operations for thread safety. - -```c -typedef struct { - _Atomic volatile uint8_t* data; - uint64_t pages, max_pages; - uint64_t size; - bool is64; - mtx_t mem_lock; -} wasm_rt_shared_memory_t; -``` - -Next is the definition of a table instance. The `data` field is a pointer to -`size` elements. Like a memory instance, `size` is the current size of a table, -and `max_size` is the maximum size of the table, or `0xffffffff` if there is no -limit. - -```c -typedef struct { - wasm_rt_funcref_t* data; - uint32_t max_size; - uint32_t size; -} wasm_rt_funcref_table_t; -``` - -## Symbols that must be defined by the embedder - -Next in `wasm-rt.h` are a collection of function declarations that must be implemented by -the embedder (i.e. you) before this C source can be used. - -A C implementation of these functions is defined in -[`wasm-rt-impl.h`](wasm-rt-impl.h) and [`wasm-rt-impl.c`](wasm-rt-impl.c). - -```c -void wasm_rt_init(void); -bool wasm_rt_is_initialized(void); -void wasm_rt_free(void); -void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn)); -const char* wasm_rt_strerror(wasm_rt_trap_t trap); -void wasm_rt_allocate_memory(wasm_rt_memory_t*, uint32_t initial_pages, uint32_t max_pages, bool is64, uint32_t page_size); -uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages); -void wasm_rt_free_memory(wasm_rt_memory_t*); -void wasm_rt_allocate_memory_shared(wasm_rt_shared_memory_t*, uint32_t initial_pages, uint32_t max_pages, bool is64, uint32_t page_size); -uint32_t wasm_rt_grow_memory_shared(wasm_rt_shared_memory_t*, uint32_t pages); -void wasm_rt_free_memory_shared(wasm_rt_shared_memory_t*); -void wasm_rt_allocate_funcref_table(wasm_rt_table_t*, uint32_t elements, uint32_t max_elements); -void wasm_rt_allocate_externref_table(wasm_rt_externref_table_t*, uint32_t elements, uint32_t max_elements); -void wasm_rt_free_funcref_table(wasm_rt_table_t*); -void wasm_rt_free_externref_table(wasm_rt_table_t*); -uint32_t wasm_rt_call_stack_depth; /* on platforms that don't use the signal handler to detect exhaustion */ -void wasm_rt_init_thread(void); -void wasm_rt_free_thread(void); -``` - -`wasm_rt_init` must be called by the embedder before anything else, to -initialize the runtime. `wasm_rt_free` frees any global -state. `wasm_rt_is_initialized` can be used to confirm that the -runtime has been initialized. - -`wasm_rt_trap` is a function that is called when the module traps. Some possible -implementations are to throw a C++ exception, or to just abort the program -execution. The default runtime included in wasm2c unwinds the stack using -`longjmp`. The host can overide this call to `longjmp` by compiling the runtime -with `WASM_RT_TRAP_HANDLER` defined to the name of a trap handler function. The -handler function should be a function taking a `wasm_rt_trap_t` as a parameter -and returning `void`. e.g. `-DWASM_RT_TRAP_HANDLER=my_trap_handler` - -`wasm_rt_allocate_memory` initializes a memory instance, and allocates -at least enough space for the given number of initial pages, each of -size `page_size` (which must be `WASM_DEFAULT_PAGE_SIZE`, equal to 64 -KiB, unless using the custom-page-sizes feature). The memory must be -cleared to zero. The `is64` parameter indicates if the memory is -indexed with an i32 or i64 address. - -`wasm_rt_grow_memory` must grow the given memory instance by the given number of -pages. If there isn't enough memory to do so, or the new page count would be -greater than the maximum page count, the function must fail by returning -`0xffffffff`. If the function succeeds, it must return the previous size of the -memory instance, in pages. The host can optionally be notified of failures by -compiling the runtime with `WASM_RT_GROW_FAILED_HANDLER` defined to the name of -a handler function. The handler function should be a function taking no -arguments and returning `void` . e.g. -`-DWASM_RT_GROW_FAILED_HANDLER=my_growfail_handler` - -`wasm_rt_free_memory` frees the memory instance. - -`wasm_rt_allocate_memory_shared` initializes a memory instance that can be -shared by different Wasm threads. Its operation is otherwise similar to -`wasm_rt_allocate_memory`. - -`wasm_rt_grow_memory_shared` must grow the given shared memory instance by the -given number of pages. It's operation is otherwise similar to -`wasm_rt_grow_memory`. - -`wasm_rt_free_memory_shared` frees the shared memory instance. - -`wasm_rt_allocate_funcref_table` and the similar `..._externref_table` -initialize a table instance of the given type, and allocate at least -enough space for the given number of initial elements. The elements -must be cleared to zero. - -`wasm_rt_free_funcref_table` and `..._externref_table` free the table instance. - -`wasm_rt_call_stack_depth` is the current stack call depth. Since this is -shared between modules, it must be defined only once, by the embedder. -It is only used on platforms that don't use the signal handler to detect -exhaustion. - -`wasm_rt_init_thread` and `wasm_rt_free_thread` are used to initialize -and free the runtime state for a given thread (other than the one that -called `wasm_rt_init`). An example can be found in -`wasm2c/examples/threads`. - -### Runtime support for exception handling - -Several additional symbols must be defined if wasm2c is being run with support -for exceptions (`--enable-exceptions`). These are defined in -`wasm-rt-exceptions.h`. These symbols are: - -```c -void wasm_rt_load_exception(const char* tag, uint32_t size, const void* values); -WASM_RT_NO_RETURN void wasm_rt_throw(void); -WASM_RT_UNWIND_TARGET -WASM_RT_UNWIND_TARGET* wasm_rt_get_unwind_target(void); -void wasm_rt_set_unwind_target(WASM_RT_UNWIND_TARGET* target); -uint32_t wasm_rt_exception_tag(void); -uint32_t wasm_rt_exception_size(void); -void* wasm_rt_exception(void); -wasm_rt_try(target) -``` - -A C implementation of these functions is also available in -[`wasm-rt-exceptions-impl.c`](wasm-rt-exceptions-impl.c). - -`wasm_rt_load_exception` sets the active exception to a given tag, size, and contents. - -`wasm_rt_throw` throws the active exception. - -`WASM_RT_UNWIND_TARGET` is the type of an unwind target if an -exception is thrown and caught. - -`wasm_rt_get_unwind_target` gets the current unwind target if an exception is thrown. - -`wasm_rt_set_unwind_target` sets the unwind target if an exception is thrown. - -Three functions provide access to the active exception: -`wasm_rt_exception_tag`, `wasm_rt_exception_size`, and -`wasm_rt_exception` return its tag, size, and contents, respectively. - -`wasm_rt_try(target)` is a macro that captures the current calling -environment as an unwind target and stores it into `target`, which -must be of type `WASM_RT_UNWIND_TARGET`. - -## Exported symbols - -Finally, `fac.h` defines the module instance type (which in the case -of `fac` is essentially empty), and the exported symbols provided by -the module. In our example, the only function we exported was -`fac`. - -`wasm2c_fac_instantiate(w2c_fac*)` creates an instance of -the module and must be called before the module instance can be -used. `wasm2c_fac_free(w2c_fac*)` frees the instance. -`wasm2c_fac_get_func_type` can be used to look up a function type ID -at runtime. It is a variadic function where the first two arguments -give the number of parameters and results, and the following arguments -are the types from the wasm_rt_type_t enum described above. The -`callback` example demonstrates using this to pass a host function to -a WebAssembly module dynamically at runtime. - -```c -typedef struct w2c_fac { - char dummy_member; -} w2c_fac; - -void wasm2c_fac_instantiate(w2c_fac*); -void wasm2c_fac_free(w2c_fac*); -wasm_rt_func_type_t wasm2c_fac_get_func_type(uint32_t param_count, uint32_t result_count, ...); - -/* export: 'fac' */ -u32 w2c_fac_fac(w2c_fac*, u32); -``` - -## Handling other kinds of imports and exports of modules - -Exported functions are handled by declaring a prefixed equivalent -function in the header. If a module imports a function, `wasm2c` -declares the function in the output header file, and the host function -is responsible for defining the function. - -Exports of other kinds (globals, memories, tables) are handled -differently, since they are part of the module instance, and each -instance can have its own exports. For these cases, `wasm2c` provides -a function that takes in a module instance as argument, and returns -the corresponding export. For example, if `fac` exported a memory as -such: - -```wasm -(export "mem" (memory $mem)) -``` - -then `wasm2c` would declare the following function in the header: - -```c -/* export: 'mem' */ -wasm_rt_memory_t* w2c_fac_mem(w2c_fac* instance); - -``` - -which would be defined as: -```c -/* export: 'mem' */ -wasm_rt_memory_t* w2c_fac_mem(w2c_fac* instance) { - return &instance->w2c_mem; -} -``` - -## A quick look at `fac.c` - -The contents of `fac.c` are internals, but it is useful to see a little about -how it works. - -The first few hundred lines define macros that are used to implement the -various WebAssembly instructions. Their implementations may be interesting to -the curious reader, but are out of scope for this document. - -Following those definitions are various initialization functions (`init`, `free`, -`init_func_types`, `init_globals`, `init_memory`, `init_table`, and -`init_exports`.) In our example, most of these functions are empty, since the -module doesn't use any globals, memory or tables. - -The most interesting part is the definition of the function `fac`: - -```c -static u32 w2c_fac_fac_0(w2c_fac* instance, u32 var_p0) { - FUNC_PROLOGUE; - u32 var_i0, var_i1, var_i2; - var_i0 = var_p0; - var_i1 = 0u; - var_i0 = var_i0 == var_i1; - if (var_i0) { - var_i0 = 1u; - } else { - var_i0 = var_p0; - var_i1 = var_p0; - var_i2 = 1u; - var_i1 -= var_i2; - var_i1 = w2c_fac_fac_0(instance, var_i1); - var_i0 *= var_i1; - } - FUNC_EPILOGUE; - return var_i0; -} -``` - -If you look at the original WebAssembly text in the flat format, you can see -that there is a 1-1 mapping in the output: - -```wasm -(func $fac (param $x i32) (result i32) - local.get $x - i32.const 0 - i32.eq - if (result i32) - i32.const 1 - else - local.get $x - local.get $x - i32.const 1 - i32.sub - call 0 - i32.mul - end) -``` - -This looks different than the factorial function above because it is using the -"flat format" instead of the "folded format". You can use `wat-desugar` to -convert between the two to be sure: - -```sh -$ wat-desugar fac-flat.wat --fold -o fac-folded.wat -``` - -```wasm -(module - (func (;0;) (param i32) (result i32) - (if (result i32) ;; label = @1 - (i32.eq - (local.get 0) - (i32.const 0)) - (then - (i32.const 1)) - (else - (i32.mul - (local.get 0) - (call 0 - (i32.sub - (local.get 0) - (i32.const 1))))))) - (export "fac" (func 0)) - (type (;0;) (func (param i32) (result i32)))) -``` - -The formatting is different and the variable and function names are gone, but -the structure is the same. - -## Create multiple instances of a module - -Since information about the execution context, such as memories, is encapsulated -in the module instance structure, and a pointer to the structure is being passed through -function calls, multiple instances of the same module can be instantiated alongside -one another. - -We can take a look at another version of the `main` function for a `rot13` example. By -declaring two sets of context information, two instances of `rot13` can be instantiated -in the same address space. - -```c -#include -#include -#include - -#include "rot13.h" - -/* Define structure to hold the imports */ -typedef struct w2c_host { - wasm_rt_memory_t memory; - char* input; -} w2c_host; - -/* Accessor to access the memory member of the host */ -wasm_rt_memory_t* w2c_host_mem(w2c_host* instance) { - return &instance->memory; -} - -int main(int argc, char** argv) { - /* Make sure there is at least one command-line argument. */ - if (argc < 2) { - printf("Invalid argument. Expected '%s WORD...'\n", argv[0]); - return 1; - } - /* Initialize the Wasm runtime. */ - wasm_rt_init(); - - /* Create two `host` instances to store the memory and current string */ - w2c_host host_1, host_2; - wasm_rt_allocate_memory(&host_1.memory, 1, 1, false, WASM_DEFAULT_PAGE_SIZE); - wasm_rt_allocate_memory(&host_2.memory, 1, 1, false, WASM_DEFAULT_PAGE_SIZE); - - /* Construct the `rot13` module instances */ - w2c_rot13 rot13_1, rot13_2; - wasm2c_rot13_instantiate(&rot13_1, &host_1); - wasm2c_rot13_instantiate(&rot13_2, &host_2); - - /* Call `rot13` on the first two arguments. */ - assert(argc > 2); - host_1.input = argv[1]; - w2c_rot13_rot13(&rot13_1); - host_2.input = argv[2]; - w2c_rot13_rot13(&rot13_2); - - /* Free the rot13 instances. */ - wasm2c_rot13_free(&rot13_1); - wasm2c_rot13_free(&rot13_2); - - /* Free the Wasm runtime state. */ - wasm_rt_free(); - - return 0; -} - -/* Fill the wasm buffer with the input to be rot13'd. - * - * params: - * instance: An instance of the w2c_host structure - * ptr: The wasm memory address of the buffer to fill data. - * size: The size of the buffer in wasm memory. - * result: - * The number of bytes filled into the buffer. (Must be <= size). - */ -u32 w2c_host_fill_buf(w2c_host* instance, u32 ptr, u32 size) { - for (size_t i = 0; i < size; ++i) { - if (instance->input[i] == 0) { - return i; - } - instance->memory.data[ptr + i] = instance->input[i]; - } - return size; -} - -/* Called when the wasm buffer has been rot13'd. - * - * params: - * w2c_host: An instance of the w2c_host structure - * ptr: The wasm memory address of the buffer. - * size: The size of the buffer in wasm memory. - */ -void w2c_host_buf_done(w2c_host* instance, u32 ptr, u32 size) { - /* The output buffer is not necessarily null-terminated, so use the %*.s - * printf format to limit the number of characters printed. */ - printf("%s -> %.*s\n", instance->input, (int)size, &instance->memory.data[ptr]); -} -``` diff --git a/src/tools/wasm2c/assertion-emitter.cpp b/src/tools/wasm2c/assertion-emitter.cpp deleted file mode 100644 index 895a40fdb27..00000000000 --- a/src/tools/wasm2c/assertion-emitter.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2026 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "parser/wat-parser.h" -#include "support/file.h" -#include "tools/wasm2c/assertion-emitter.h" -#include "tools/wasm2c/c-printer.h" -#include "wasm.h" - -// code to be inserted into the generated output -extern const char* SpecTop; - -namespace wasm { - -namespace { - -inline std::string stripExtension(const std::string& path) { - size_t lastDot = path.find_last_of('.'); - if (lastDot == std::string::npos) { - return path; - } - size_t lastSlash = path.find_last_of("/\\"); - if (lastSlash != std::string::npos && lastDot < lastSlash) { - return path; - } - return path.substr(0, lastDot); -} - -inline std::string getBasename(const std::string& path) { - size_t lastSlash = path.find_last_of("/\\"); - if (lastSlash == std::string::npos) { - return path; - } - return path.substr(lastSlash + 1); -} - -} // anonymous namespace - -AssertionEmitter::AssertionEmitter(WATParser::WASTScript& script, - Wasm2CBuilder::Flags flags) - : script(script), flags(flags) {} - -void AssertionEmitter::emit(std::ostream& cOut, - const std::string& outputCPath) { - CPrinter c(cOut); - - std::string basePath = - outputCPath.empty() ? "spec" : stripExtension(outputCPath); - std::string baseBasename = getBasename(basePath); - - // Loop sequentially through WASTScript AST commands - for (size_t i = 0; i < script.size(); i++) { - auto& entry = script[i]; - auto& cmd = entry.cmd; - - if (auto* mod = std::get_if(&cmd)) { - if (mod->isDefinition) { - Fatal() << "Module definition is not supported"; - } - auto* w = std::get_if>(&mod->module); - assert(w && "expected parsed Module pointer inside WASTModule"); - - auto wasm = *w; - size_t currentIdx = moduleCounter++; - std::string prefix = "spec_" + std::to_string(currentIdx); - - // Generate separate files for this module - std::string modHFilename = - baseBasename + "." + std::to_string(currentIdx) + ".h"; - - std::string modCPath = basePath + "." + std::to_string(currentIdx) + ".c"; - std::string modHPath = basePath + "." + std::to_string(currentIdx) + ".h"; - - Output modCOut(modCPath, Flags::Text); - Output modHOut(modHPath, Flags::Text); - - Wasm2CBuilder::Flags modFlags = flags; - modFlags.moduleName = prefix; - modFlags.headerName = modHFilename; - - Wasm2CBuilder builder(modFlags); - builder.processWasm(wasm.get(), modCOut.getStream(), modHOut.getStream()); - - c << "#include \"" << modHFilename << "\"" << endl; - c << SpecTop << endl << endl; - - } else if (std::get_if(&cmd)) { - Fatal() << "register is not yet supported"; - } else if (std::get_if(&cmd)) { - Fatal() << "assertions are not yet supported"; - } else { - Fatal() << "unsupported command"; - } - } - - // Write main execution entry point - c << "void run_spec_tests() {" << endl; - c << "}" << endl; -} - -} // namespace wasm diff --git a/src/tools/wasm2c/assertion-emitter.h b/src/tools/wasm2c/assertion-emitter.h deleted file mode 100644 index 3389ca6a91d..00000000000 --- a/src/tools/wasm2c/assertion-emitter.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2026 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef wasm_tools_wasm2c_assertion_emitter_h -#define wasm_tools_wasm2c_assertion_emitter_h - -#include - -#include "parser/wat-parser.h" -#include "tools/wasm2c/wasm2c-builder.h" - -namespace wasm { - -class AssertionEmitter { -public: - AssertionEmitter(WATParser::WASTScript& script, Wasm2CBuilder::Flags flags); - - void emit(std::ostream& cOut, const std::string& outputCPath); - -private: - WATParser::WASTScript& script; - Wasm2CBuilder::Flags flags; - - size_t moduleCounter = 0; -}; - -} // namespace wasm - -#endif // wasm_tools_wasm2c_assertion_emitter_h diff --git a/src/tools/wasm2c/c-printer.h b/src/tools/wasm2c/c-printer.h deleted file mode 100644 index 561f290088b..00000000000 --- a/src/tools/wasm2c/c-printer.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2026 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef wasm_tools_wasm2c_c_printer_h -#define wasm_tools_wasm2c_c_printer_h - -#include - -namespace wasm { - -class CPrinter; -typedef CPrinter& (*CPrinterManipulator)(CPrinter&); - -class CPrinter { -public: - std::ostream& out; - int indentLevel = 0; - bool startOfLine = true; - - CPrinter(std::ostream& out) : out(out) {} - - void indent() { indentLevel++; } - void outdent() { indentLevel--; } - - CPrinter& operator<<(CPrinter& (*pf)(CPrinter&)) { return pf(*this); } - - template CPrinter& operator<<(const T& val) { - if (startOfLine) { - for (int i = 0; i < indentLevel * 2; i++) { - out << ' '; - } - startOfLine = false; - } - out << val; - return *this; - } -}; - -inline CPrinter& endl(CPrinter& p) { - p.out << '\n'; - p.startOfLine = true; - return p; -} - -} // namespace wasm - -#endif // wasm_tools_wasm2c_c_printer_h diff --git a/src/tools/wasm2c/prebuilt/wasm2c_atomicops_source_declarations.cpp b/src/tools/wasm2c/prebuilt/wasm2c_atomicops_source_declarations.cpp deleted file mode 100644 index 29e41312998..00000000000 --- a/src/tools/wasm2c/prebuilt/wasm2c_atomicops_source_declarations.cpp +++ /dev/null @@ -1,238 +0,0 @@ -const char* AtomicsOpsSourceDeclarations = R"w2c_template(#include - -#ifndef WASM_RT_C11_AVAILABLE -#error "C11 is required for Wasm threads and shared memory support" -#endif - -#define ATOMIC_ALIGNMENT_CHECK(addr, t1) \ - if (UNLIKELY(addr % sizeof(t1))) { \ - TRAP(UNALIGNED); \ - } - -#define DEFINE_SHARED_LOAD(name, t1, t2, t3, force_read) \ - static inline t3 name##_unchecked(wasm_rt_shared_memory_t* mem, u64 addr) { \ - t1 result; \ - result = atomic_load_explicit( \ - (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), \ - memory_order_relaxed); \ - force_read(result); \ - return (t3)(t2)result; \ - } \ - DEF_MEM_CHECKS0(name, _shared_, t1, return, t3) - -DEFINE_SHARED_LOAD(i32_load_shared, u32, u32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load_shared, u64, u64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(f32_load_shared, f32, f32, f32, FORCE_READ_FLOAT) -DEFINE_SHARED_LOAD(f64_load_shared, f64, f64, f64, FORCE_READ_FLOAT) -DEFINE_SHARED_LOAD(i32_load8_s_shared, s8, s32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load8_s_shared, s8, s64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i32_load8_u_shared, u8, u32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load8_u_shared, u8, u64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i32_load16_s_shared, s16, s32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load16_s_shared, s16, s64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i32_load16_u_shared, u16, u32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load16_u_shared, u16, u64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load32_s_shared, s32, s64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load32_u_shared, u32, u64, u64, FORCE_READ_INT) - -#define DEFINE_SHARED_STORE(name, t1, t2) \ - static inline void name##_unchecked(wasm_rt_shared_memory_t* mem, u64 addr, \ - t2 value) { \ - t1 wrapped = (t1)value; \ - atomic_store_explicit( \ - (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), wrapped, \ - memory_order_relaxed); \ - } \ - DEF_MEM_CHECKS1(name, _shared_, t1, , void, t2) - -DEFINE_SHARED_STORE(i32_store_shared, u32, u32) -DEFINE_SHARED_STORE(i64_store_shared, u64, u64) -DEFINE_SHARED_STORE(f32_store_shared, f32, f32) -DEFINE_SHARED_STORE(f64_store_shared, f64, f64) -DEFINE_SHARED_STORE(i32_store8_shared, u8, u32) -DEFINE_SHARED_STORE(i32_store16_shared, u16, u32) -DEFINE_SHARED_STORE(i64_store8_shared, u8, u64) -DEFINE_SHARED_STORE(i64_store16_shared, u16, u64) -DEFINE_SHARED_STORE(i64_store32_shared, u32, u64) - -#define DEFINE_ATOMIC_LOAD(name, t1, t2, t3, force_read) \ - static inline t3 name##_unchecked(wasm_rt_memory_t* mem, u64 addr) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR(mem, addr, sizeof(t1)), sizeof(t1)); \ - force_read(result); \ - return (t3)(t2)result; \ - } \ - DEF_MEM_CHECKS0(name, _, t1, return, t3) \ - static inline t3 name##_shared_unchecked(wasm_rt_shared_memory_t* mem, \ - u64 addr) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 result; \ - result = \ - atomic_load((_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1))); \ - force_read(result); \ - return (t3)(t2)result; \ - } \ - DEF_MEM_CHECKS0(name##_shared, _shared_, t1, return, t3) - -DEFINE_ATOMIC_LOAD(i32_atomic_load, u32, u32, u32, FORCE_READ_INT) -DEFINE_ATOMIC_LOAD(i64_atomic_load, u64, u64, u64, FORCE_READ_INT) -DEFINE_ATOMIC_LOAD(i32_atomic_load8_u, u8, u32, u32, FORCE_READ_INT) -DEFINE_ATOMIC_LOAD(i64_atomic_load8_u, u8, u64, u64, FORCE_READ_INT) -DEFINE_ATOMIC_LOAD(i32_atomic_load16_u, u16, u32, u32, FORCE_READ_INT) -DEFINE_ATOMIC_LOAD(i64_atomic_load16_u, u16, u64, u64, FORCE_READ_INT) -DEFINE_ATOMIC_LOAD(i64_atomic_load32_u, u32, u64, u64, FORCE_READ_INT) - -#define DEFINE_ATOMIC_STORE(name, t1, t2) \ - static inline void name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \ - t2 value) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR(mem, addr, sizeof(t1)), &wrapped, sizeof(t1)); \ - } \ - DEF_MEM_CHECKS1(name, _, t1, , void, t2) \ - static inline void name##_shared_unchecked(wasm_rt_shared_memory_t* mem, \ - u64 addr, t2 value) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - atomic_store((_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), \ - wrapped); \ - } \ - DEF_MEM_CHECKS1(name##_shared, _shared_, t1, , void, t2) - -DEFINE_ATOMIC_STORE(i32_atomic_store, u32, u32) -DEFINE_ATOMIC_STORE(i64_atomic_store, u64, u64) -DEFINE_ATOMIC_STORE(i32_atomic_store8, u8, u32) -DEFINE_ATOMIC_STORE(i32_atomic_store16, u16, u32) -DEFINE_ATOMIC_STORE(i64_atomic_store8, u8, u64) -DEFINE_ATOMIC_STORE(i64_atomic_store16, u16, u64) -DEFINE_ATOMIC_STORE(i64_atomic_store32, u32, u64) - -#define DEFINE_ATOMIC_RMW(name, opname, op, t1, t2) \ - static inline t2 name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \ - t2 value) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - t1 ret; \ - wasm_rt_memcpy(&ret, MEM_ADDR(mem, addr, sizeof(t1)), sizeof(t1)); \ - ret = ret op wrapped; \ - wasm_rt_memcpy(MEM_ADDR(mem, addr, sizeof(t1)), &ret, sizeof(t1)); \ - return (t2)ret; \ - } \ - DEF_MEM_CHECKS1(name, _, t1, return, t2, t2) \ - static inline t2 name##_shared_unchecked(wasm_rt_shared_memory_t* mem, \ - u64 addr, t2 value) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - t1 ret = atomic_##opname( \ - (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), wrapped); \ - return (t2)ret; \ - } \ - DEF_MEM_CHECKS1(name##_shared, _shared_, t1, return, t2, t2) - -DEFINE_ATOMIC_RMW(i32_atomic_rmw8_add_u, fetch_add, +, u8, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw16_add_u, fetch_add, +, u16, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw_add, fetch_add, +, u32, u32) -DEFINE_ATOMIC_RMW(i64_atomic_rmw8_add_u, fetch_add, +, u8, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw16_add_u, fetch_add, +, u16, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw32_add_u, fetch_add, +, u32, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw_add, fetch_add, +, u64, u64) - -DEFINE_ATOMIC_RMW(i32_atomic_rmw8_sub_u, fetch_sub, -, u8, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw16_sub_u, fetch_sub, -, u16, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw_sub, fetch_sub, -, u32, u32) -DEFINE_ATOMIC_RMW(i64_atomic_rmw8_sub_u, fetch_sub, -, u8, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw16_sub_u, fetch_sub, -, u16, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw32_sub_u, fetch_sub, -, u32, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw_sub, fetch_sub, -, u64, u64) - -DEFINE_ATOMIC_RMW(i32_atomic_rmw8_and_u, fetch_and, &, u8, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw16_and_u, fetch_and, &, u16, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw_and, fetch_and, &, u32, u32) -DEFINE_ATOMIC_RMW(i64_atomic_rmw8_and_u, fetch_and, &, u8, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw16_and_u, fetch_and, &, u16, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw32_and_u, fetch_and, &, u32, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw_and, fetch_and, &, u64, u64) - -DEFINE_ATOMIC_RMW(i32_atomic_rmw8_or_u, fetch_or, |, u8, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw16_or_u, fetch_or, |, u16, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw_or, fetch_or, |, u32, u32) -DEFINE_ATOMIC_RMW(i64_atomic_rmw8_or_u, fetch_or, |, u8, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw16_or_u, fetch_or, |, u16, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw32_or_u, fetch_or, |, u32, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw_or, fetch_or, |, u64, u64) - -DEFINE_ATOMIC_RMW(i32_atomic_rmw8_xor_u, fetch_xor, ^, u8, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw16_xor_u, fetch_xor, ^, u16, u32) -DEFINE_ATOMIC_RMW(i32_atomic_rmw_xor, fetch_xor, ^, u32, u32) -DEFINE_ATOMIC_RMW(i64_atomic_rmw8_xor_u, fetch_xor, ^, u8, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw16_xor_u, fetch_xor, ^, u16, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw32_xor_u, fetch_xor, ^, u32, u64) -DEFINE_ATOMIC_RMW(i64_atomic_rmw_xor, fetch_xor, ^, u64, u64) - -#define DEFINE_ATOMIC_XCHG(name, opname, t1, t2) \ - static inline t2 name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \ - t2 value) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - t1 ret; \ - wasm_rt_memcpy(&ret, MEM_ADDR(mem, addr, sizeof(t1)), sizeof(t1)); \ - wasm_rt_memcpy(MEM_ADDR(mem, addr, sizeof(t1)), &wrapped, sizeof(t1)); \ - return (t2)ret; \ - } \ - DEF_MEM_CHECKS1(name, _, t1, return, t2, t2) \ - static inline t2 name##_shared_unchecked(wasm_rt_shared_memory_t* mem, \ - u64 addr, t2 value) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - t1 ret = atomic_##opname( \ - (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), wrapped); \ - return (t2)ret; \ - } \ - DEF_MEM_CHECKS1(name##_shared, _shared_, t1, return, t2, t2) - -DEFINE_ATOMIC_XCHG(i32_atomic_rmw8_xchg_u, exchange, u8, u32) -DEFINE_ATOMIC_XCHG(i32_atomic_rmw16_xchg_u, exchange, u16, u32) -DEFINE_ATOMIC_XCHG(i32_atomic_rmw_xchg, exchange, u32, u32) -DEFINE_ATOMIC_XCHG(i64_atomic_rmw8_xchg_u, exchange, u8, u64) -DEFINE_ATOMIC_XCHG(i64_atomic_rmw16_xchg_u, exchange, u16, u64) -DEFINE_ATOMIC_XCHG(i64_atomic_rmw32_xchg_u, exchange, u32, u64) -DEFINE_ATOMIC_XCHG(i64_atomic_rmw_xchg, exchange, u64, u64) - -#define DEFINE_ATOMIC_CMP_XCHG(name, t1, t2) \ - static inline t1 name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \ - t1 expected, t1 replacement) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t2); \ - t2 expected_wrapped = (t2)expected; \ - t2 replacement_wrapped = (t2)replacement; \ - t2 ret; \ - wasm_rt_memcpy(&ret, MEM_ADDR(mem, addr, sizeof(t2)), sizeof(t2)); \ - if (ret == expected_wrapped) { \ - wasm_rt_memcpy(MEM_ADDR(mem, addr, sizeof(t2)), &replacement_wrapped, \ - sizeof(t2)); \ - } \ - return (t1)expected_wrapped; \ - } \ - DEF_MEM_CHECKS2(name, _, t2, return, t1, t1, t1) \ - static inline t1 name##_shared_unchecked( \ - wasm_rt_shared_memory_t* mem, u64 addr, t1 expected, t1 replacement) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t2); \ - t2 expected_wrapped = (t2)expected; \ - t2 replacement_wrapped = (t2)replacement; \ - atomic_compare_exchange_strong( \ - (_Atomic volatile t2*)MEM_ADDR(mem, addr, sizeof(t2)), \ - &expected_wrapped, replacement_wrapped); \ - return (t1)expected_wrapped; \ - } \ - DEF_MEM_CHECKS2(name##_shared, _shared_, t2, return, t1, t1, t1) - -DEFINE_ATOMIC_CMP_XCHG(i32_atomic_rmw8_cmpxchg_u, u32, u8); -DEFINE_ATOMIC_CMP_XCHG(i32_atomic_rmw16_cmpxchg_u, u32, u16); -DEFINE_ATOMIC_CMP_XCHG(i32_atomic_rmw_cmpxchg, u32, u32); -DEFINE_ATOMIC_CMP_XCHG(i64_atomic_rmw8_cmpxchg_u, u64, u8); -DEFINE_ATOMIC_CMP_XCHG(i64_atomic_rmw16_cmpxchg_u, u64, u16); -DEFINE_ATOMIC_CMP_XCHG(i64_atomic_rmw32_cmpxchg_u, u64, u32); -DEFINE_ATOMIC_CMP_XCHG(i64_atomic_rmw_cmpxchg, u64, u64); - -#define atomic_fence() atomic_thread_fence(memory_order_seq_cst) -)w2c_template"; diff --git a/src/tools/wasm2c/prebuilt/wasm2c_header_bottom.cpp b/src/tools/wasm2c/prebuilt/wasm2c_header_bottom.cpp deleted file mode 100644 index 54047968bf1..00000000000 --- a/src/tools/wasm2c/prebuilt/wasm2c_header_bottom.cpp +++ /dev/null @@ -1,4 +0,0 @@ -const char* HeaderBottom = R"w2c_template(#ifdef __cplusplus -} -#endif -)w2c_template"; diff --git a/src/tools/wasm2c/prebuilt/wasm2c_header_top.cpp b/src/tools/wasm2c/prebuilt/wasm2c_header_top.cpp deleted file mode 100644 index f3b52a9a897..00000000000 --- a/src/tools/wasm2c/prebuilt/wasm2c_header_top.cpp +++ /dev/null @@ -1,20 +0,0 @@ -const char* HeaderTop = R"w2c_template(#include - -#ifndef WASM_RT_CORE_TYPES_DEFINED -#define WASM_RT_CORE_TYPES_DEFINED -typedef uint8_t u8; -typedef int8_t s8; -typedef uint16_t u16; -typedef int16_t s16; -typedef uint32_t u32; -typedef int32_t s32; -typedef uint64_t u64; -typedef int64_t s64; -typedef float f32; -typedef double f64; -#endif - -#ifdef __cplusplus -extern "C" { -#endif -)w2c_template"; diff --git a/src/tools/wasm2c/prebuilt/wasm2c_simd_source_declarations.cpp b/src/tools/wasm2c/prebuilt/wasm2c_simd_source_declarations.cpp deleted file mode 100644 index 293f3610a43..00000000000 --- a/src/tools/wasm2c/prebuilt/wasm2c_simd_source_declarations.cpp +++ /dev/null @@ -1,345 +0,0 @@ -const char* SimdSourceDeclarations = R"w2c_template( -#if defined(__GNUC__) && defined(__x86_64__) -#define SIMD_FORCE_READ(var) __asm__("" ::"x"(var)); -#elif defined(__GNUC__) && defined(__aarch64__) -#define SIMD_FORCE_READ(var) __asm__("" ::"w"(var)); -#elif defined(__s390x__) -#define SIMD_FORCE_READ(var) __asm__("" ::"d"(var)); -#else -#define SIMD_FORCE_READ(var) -#endif -// TODO: equivalent constraint for ARM and other architectures - -#define DEFINE_SIMD_LOAD_FUNC(name, func, t) \ - static inline v128 name##_unchecked(wasm_rt_memory_t* mem, u64 addr) { \ - v128 result = func(MEM_ADDR(mem, addr, sizeof(t))); \ - SIMD_FORCE_READ(result); \ - return result; \ - } \ - DEF_MEM_CHECKS0(name, _, t, return, v128); - -#define DEFINE_SIMD_LOAD_LANE(name, func, t, lane) \ - static inline v128 name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \ - v128 vec) { \ - v128 result = func(MEM_ADDR(mem, addr, sizeof(t)), vec, lane); \ - SIMD_FORCE_READ(result); \ - return result; \ - } \ - DEF_MEM_CHECKS1(name, _, t, return, v128, v128); - -#define DEFINE_SIMD_STORE(name, t) \ - static inline void name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \ - v128 value) { \ - simde_wasm_v128_store(MEM_ADDR(mem, addr, sizeof(t)), value); \ - } \ - DEF_MEM_CHECKS1(name, _, t, , void, v128); - -#define DEFINE_SIMD_STORE_LANE(name, func, t, lane) \ - static inline void name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \ - v128 value) { \ - func(MEM_ADDR(mem, addr, sizeof(t)), value, lane); \ - } \ - DEF_MEM_CHECKS1(name, _, t, , void, v128); - -// clang-format off -#if WASM_RT_BIG_ENDIAN -static inline v128 v128_impl_load32_zero(const void* a) { - return simde_wasm_i8x16_swizzle( - simde_wasm_v128_load32_zero(a), - simde_wasm_i8x16_const(12,13,14,15,8,9,10,11,4,5,6,7,0,1,2,3)); -} -static inline v128 v128_impl_load64_zero(const void* a) { - return simde_wasm_i8x16_swizzle( - simde_wasm_v128_load64_zero(a), - simde_wasm_i8x16_const(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)); -} -#else -#define v128_impl_load32_zero simde_wasm_v128_load32_zero -#define v128_impl_load64_zero simde_wasm_v128_load64_zero -#endif - -DEFINE_SIMD_LOAD_FUNC(v128_load, simde_wasm_v128_load, v128) - -DEFINE_SIMD_LOAD_FUNC(v128_load8_splat, simde_wasm_v128_load8_splat, u8) -DEFINE_SIMD_LOAD_FUNC(v128_load16_splat, simde_wasm_v128_load16_splat, u16) -DEFINE_SIMD_LOAD_FUNC(v128_load32_splat, simde_wasm_v128_load32_splat, u32) -DEFINE_SIMD_LOAD_FUNC(v128_load64_splat, simde_wasm_v128_load64_splat, u64) - -DEFINE_SIMD_LOAD_FUNC(i16x8_load8x8, simde_wasm_i16x8_load8x8, u64) -DEFINE_SIMD_LOAD_FUNC(u16x8_load8x8, simde_wasm_u16x8_load8x8, u64) -DEFINE_SIMD_LOAD_FUNC(i32x4_load16x4, simde_wasm_i32x4_load16x4, u64) -DEFINE_SIMD_LOAD_FUNC(u32x4_load16x4, simde_wasm_u32x4_load16x4, u64) -DEFINE_SIMD_LOAD_FUNC(i64x2_load32x2, simde_wasm_i64x2_load32x2, u64) -DEFINE_SIMD_LOAD_FUNC(u64x2_load32x2, simde_wasm_u64x2_load32x2, u64) - -DEFINE_SIMD_LOAD_FUNC(v128_load32_zero, v128_impl_load32_zero, u32) -DEFINE_SIMD_LOAD_FUNC(v128_load64_zero, v128_impl_load64_zero, u64) - -#if WASM_RT_BIG_ENDIAN -DEFINE_SIMD_LOAD_LANE(v128_load8_lane0, simde_wasm_v128_load8_lane, u8, 15) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane1, simde_wasm_v128_load8_lane, u8, 14) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane2, simde_wasm_v128_load8_lane, u8, 13) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane3, simde_wasm_v128_load8_lane, u8, 12) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane4, simde_wasm_v128_load8_lane, u8, 11) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane5, simde_wasm_v128_load8_lane, u8, 10) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane6, simde_wasm_v128_load8_lane, u8, 9) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane7, simde_wasm_v128_load8_lane, u8, 8) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane8, simde_wasm_v128_load8_lane, u8, 7) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane9, simde_wasm_v128_load8_lane, u8, 6) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane10, simde_wasm_v128_load8_lane, u8, 5) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane11, simde_wasm_v128_load8_lane, u8, 4) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane12, simde_wasm_v128_load8_lane, u8, 3) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane13, simde_wasm_v128_load8_lane, u8, 2) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane14, simde_wasm_v128_load8_lane, u8, 1) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane15, simde_wasm_v128_load8_lane, u8, 0) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane0, simde_wasm_v128_load16_lane, u16, 7) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane1, simde_wasm_v128_load16_lane, u16, 6) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane2, simde_wasm_v128_load16_lane, u16, 5) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane3, simde_wasm_v128_load16_lane, u16, 4) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane4, simde_wasm_v128_load16_lane, u16, 3) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane5, simde_wasm_v128_load16_lane, u16, 2) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane6, simde_wasm_v128_load16_lane, u16, 1) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane7, simde_wasm_v128_load16_lane, u16, 0) -DEFINE_SIMD_LOAD_LANE(v128_load32_lane0, simde_wasm_v128_load32_lane, u32, 3) -DEFINE_SIMD_LOAD_LANE(v128_load32_lane1, simde_wasm_v128_load32_lane, u32, 2) -DEFINE_SIMD_LOAD_LANE(v128_load32_lane2, simde_wasm_v128_load32_lane, u32, 1) -DEFINE_SIMD_LOAD_LANE(v128_load32_lane3, simde_wasm_v128_load32_lane, u32, 0) -DEFINE_SIMD_LOAD_LANE(v128_load64_lane0, simde_wasm_v128_load64_lane, u64, 1) -DEFINE_SIMD_LOAD_LANE(v128_load64_lane1, simde_wasm_v128_load64_lane, u64, 0) -#else -DEFINE_SIMD_LOAD_LANE(v128_load8_lane0, simde_wasm_v128_load8_lane, u8, 0) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane1, simde_wasm_v128_load8_lane, u8, 1) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane2, simde_wasm_v128_load8_lane, u8, 2) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane3, simde_wasm_v128_load8_lane, u8, 3) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane4, simde_wasm_v128_load8_lane, u8, 4) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane5, simde_wasm_v128_load8_lane, u8, 5) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane6, simde_wasm_v128_load8_lane, u8, 6) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane7, simde_wasm_v128_load8_lane, u8, 7) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane8, simde_wasm_v128_load8_lane, u8, 8) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane9, simde_wasm_v128_load8_lane, u8, 9) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane10, simde_wasm_v128_load8_lane, u8, 10) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane11, simde_wasm_v128_load8_lane, u8, 11) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane12, simde_wasm_v128_load8_lane, u8, 12) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane13, simde_wasm_v128_load8_lane, u8, 13) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane14, simde_wasm_v128_load8_lane, u8, 14) -DEFINE_SIMD_LOAD_LANE(v128_load8_lane15, simde_wasm_v128_load8_lane, u8, 15) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane0, simde_wasm_v128_load16_lane, u16, 0) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane1, simde_wasm_v128_load16_lane, u16, 1) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane2, simde_wasm_v128_load16_lane, u16, 2) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane3, simde_wasm_v128_load16_lane, u16, 3) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane4, simde_wasm_v128_load16_lane, u16, 4) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane5, simde_wasm_v128_load16_lane, u16, 5) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane6, simde_wasm_v128_load16_lane, u16, 6) -DEFINE_SIMD_LOAD_LANE(v128_load16_lane7, simde_wasm_v128_load16_lane, u16, 7) -DEFINE_SIMD_LOAD_LANE(v128_load32_lane0, simde_wasm_v128_load32_lane, u32, 0) -DEFINE_SIMD_LOAD_LANE(v128_load32_lane1, simde_wasm_v128_load32_lane, u32, 1) -DEFINE_SIMD_LOAD_LANE(v128_load32_lane2, simde_wasm_v128_load32_lane, u32, 2) -DEFINE_SIMD_LOAD_LANE(v128_load32_lane3, simde_wasm_v128_load32_lane, u32, 3) -DEFINE_SIMD_LOAD_LANE(v128_load64_lane0, simde_wasm_v128_load64_lane, u64, 0) -DEFINE_SIMD_LOAD_LANE(v128_load64_lane1, simde_wasm_v128_load64_lane, u64, 1) -#endif - -DEFINE_SIMD_STORE(v128_store, v128) - -#if WASM_RT_BIG_ENDIAN -DEFINE_SIMD_STORE_LANE(v128_store8_lane0, simde_wasm_v128_store8_lane, u8, 15) -DEFINE_SIMD_STORE_LANE(v128_store8_lane1, simde_wasm_v128_store8_lane, u8, 14) -DEFINE_SIMD_STORE_LANE(v128_store8_lane2, simde_wasm_v128_store8_lane, u8, 13) -DEFINE_SIMD_STORE_LANE(v128_store8_lane3, simde_wasm_v128_store8_lane, u8, 12) -DEFINE_SIMD_STORE_LANE(v128_store8_lane4, simde_wasm_v128_store8_lane, u8, 11) -DEFINE_SIMD_STORE_LANE(v128_store8_lane5, simde_wasm_v128_store8_lane, u8, 10) -DEFINE_SIMD_STORE_LANE(v128_store8_lane6, simde_wasm_v128_store8_lane, u8, 9) -DEFINE_SIMD_STORE_LANE(v128_store8_lane7, simde_wasm_v128_store8_lane, u8, 8) -DEFINE_SIMD_STORE_LANE(v128_store8_lane8, simde_wasm_v128_store8_lane, u8, 7) -DEFINE_SIMD_STORE_LANE(v128_store8_lane9, simde_wasm_v128_store8_lane, u8, 6) -DEFINE_SIMD_STORE_LANE(v128_store8_lane10, simde_wasm_v128_store8_lane, u8, 5) -DEFINE_SIMD_STORE_LANE(v128_store8_lane11, simde_wasm_v128_store8_lane, u8, 4) -DEFINE_SIMD_STORE_LANE(v128_store8_lane12, simde_wasm_v128_store8_lane, u8, 3) -DEFINE_SIMD_STORE_LANE(v128_store8_lane13, simde_wasm_v128_store8_lane, u8, 2) -DEFINE_SIMD_STORE_LANE(v128_store8_lane14, simde_wasm_v128_store8_lane, u8, 1) -DEFINE_SIMD_STORE_LANE(v128_store8_lane15, simde_wasm_v128_store8_lane, u8, 0) -DEFINE_SIMD_STORE_LANE(v128_store16_lane0, simde_wasm_v128_store16_lane, u16, 7) -DEFINE_SIMD_STORE_LANE(v128_store16_lane1, simde_wasm_v128_store16_lane, u16, 6) -DEFINE_SIMD_STORE_LANE(v128_store16_lane2, simde_wasm_v128_store16_lane, u16, 5) -DEFINE_SIMD_STORE_LANE(v128_store16_lane3, simde_wasm_v128_store16_lane, u16, 4) -DEFINE_SIMD_STORE_LANE(v128_store16_lane4, simde_wasm_v128_store16_lane, u16, 3) -DEFINE_SIMD_STORE_LANE(v128_store16_lane5, simde_wasm_v128_store16_lane, u16, 2) -DEFINE_SIMD_STORE_LANE(v128_store16_lane6, simde_wasm_v128_store16_lane, u16, 1) -DEFINE_SIMD_STORE_LANE(v128_store16_lane7, simde_wasm_v128_store16_lane, u16, 0) -DEFINE_SIMD_STORE_LANE(v128_store32_lane0, simde_wasm_v128_store32_lane, u32, 3) -DEFINE_SIMD_STORE_LANE(v128_store32_lane1, simde_wasm_v128_store32_lane, u32, 2) -DEFINE_SIMD_STORE_LANE(v128_store32_lane2, simde_wasm_v128_store32_lane, u32, 1) -DEFINE_SIMD_STORE_LANE(v128_store32_lane3, simde_wasm_v128_store32_lane, u32, 0) -DEFINE_SIMD_STORE_LANE(v128_store64_lane0, simde_wasm_v128_store64_lane, u64, 1) -DEFINE_SIMD_STORE_LANE(v128_store64_lane1, simde_wasm_v128_store64_lane, u64, 0) -#else -DEFINE_SIMD_STORE_LANE(v128_store8_lane0, simde_wasm_v128_store8_lane, u8, 0) -DEFINE_SIMD_STORE_LANE(v128_store8_lane1, simde_wasm_v128_store8_lane, u8, 1) -DEFINE_SIMD_STORE_LANE(v128_store8_lane2, simde_wasm_v128_store8_lane, u8, 2) -DEFINE_SIMD_STORE_LANE(v128_store8_lane3, simde_wasm_v128_store8_lane, u8, 3) -DEFINE_SIMD_STORE_LANE(v128_store8_lane4, simde_wasm_v128_store8_lane, u8, 4) -DEFINE_SIMD_STORE_LANE(v128_store8_lane5, simde_wasm_v128_store8_lane, u8, 5) -DEFINE_SIMD_STORE_LANE(v128_store8_lane6, simde_wasm_v128_store8_lane, u8, 6) -DEFINE_SIMD_STORE_LANE(v128_store8_lane7, simde_wasm_v128_store8_lane, u8, 7) -DEFINE_SIMD_STORE_LANE(v128_store8_lane8, simde_wasm_v128_store8_lane, u8, 8) -DEFINE_SIMD_STORE_LANE(v128_store8_lane9, simde_wasm_v128_store8_lane, u8, 9) -DEFINE_SIMD_STORE_LANE(v128_store8_lane10, simde_wasm_v128_store8_lane, u8, 10) -DEFINE_SIMD_STORE_LANE(v128_store8_lane11, simde_wasm_v128_store8_lane, u8, 11) -DEFINE_SIMD_STORE_LANE(v128_store8_lane12, simde_wasm_v128_store8_lane, u8, 12) -DEFINE_SIMD_STORE_LANE(v128_store8_lane13, simde_wasm_v128_store8_lane, u8, 13) -DEFINE_SIMD_STORE_LANE(v128_store8_lane14, simde_wasm_v128_store8_lane, u8, 14) -DEFINE_SIMD_STORE_LANE(v128_store8_lane15, simde_wasm_v128_store8_lane, u8, 15) -DEFINE_SIMD_STORE_LANE(v128_store16_lane0, simde_wasm_v128_store16_lane, u16, 0) -DEFINE_SIMD_STORE_LANE(v128_store16_lane1, simde_wasm_v128_store16_lane, u16, 1) -DEFINE_SIMD_STORE_LANE(v128_store16_lane2, simde_wasm_v128_store16_lane, u16, 2) -DEFINE_SIMD_STORE_LANE(v128_store16_lane3, simde_wasm_v128_store16_lane, u16, 3) -DEFINE_SIMD_STORE_LANE(v128_store16_lane4, simde_wasm_v128_store16_lane, u16, 4) -DEFINE_SIMD_STORE_LANE(v128_store16_lane5, simde_wasm_v128_store16_lane, u16, 5) -DEFINE_SIMD_STORE_LANE(v128_store16_lane6, simde_wasm_v128_store16_lane, u16, 6) -DEFINE_SIMD_STORE_LANE(v128_store16_lane7, simde_wasm_v128_store16_lane, u16, 7) -DEFINE_SIMD_STORE_LANE(v128_store32_lane0, simde_wasm_v128_store32_lane, u32, 0) -DEFINE_SIMD_STORE_LANE(v128_store32_lane1, simde_wasm_v128_store32_lane, u32, 1) -DEFINE_SIMD_STORE_LANE(v128_store32_lane2, simde_wasm_v128_store32_lane, u32, 2) -DEFINE_SIMD_STORE_LANE(v128_store32_lane3, simde_wasm_v128_store32_lane, u32, 3) -DEFINE_SIMD_STORE_LANE(v128_store64_lane0, simde_wasm_v128_store64_lane, u64, 0) -DEFINE_SIMD_STORE_LANE(v128_store64_lane1, simde_wasm_v128_store64_lane, u64, 1) -#endif -)w2c_template" - R"w2c_template( -#if WASM_RT_BIG_ENDIAN -#define v128_const(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) simde_wasm_i8x16_const(p,o,n,m,l,k,j,i,h,g,f,e,d,c,b,a) -#define v128_i8x16_extract_lane(v, l) simde_wasm_i8x16_extract_lane(v, 15-(l)) -#define v128_u8x16_extract_lane(v, l) simde_wasm_u8x16_extract_lane(v, 15-(l)) -#define v128_i16x8_extract_lane(v, l) simde_wasm_i16x8_extract_lane(v, 7-(l)) -#define v128_u16x8_extract_lane(v, l) simde_wasm_u16x8_extract_lane(v, 7-(l)) -#define v128_i32x4_extract_lane(v, l) simde_wasm_i32x4_extract_lane(v, 3-(l)) -#define v128_i64x2_extract_lane(v, l) simde_wasm_i64x2_extract_lane(v, 1-(l)) -#define v128_f32x4_extract_lane(v, l) simde_wasm_f32x4_extract_lane(v, 3-(l)) -#define v128_f64x2_extract_lane(v, l) simde_wasm_f64x2_extract_lane(v, 1-(l)) -#define v128_i8x16_replace_lane(v, l, x) simde_wasm_i8x16_replace_lane(v, 15-(l), x) -#define v128_u8x16_replace_lane(v, l, x) simde_wasm_u8x16_replace_lane(v, 15-(l), x) -#define v128_i16x8_replace_lane(v, l, x) simde_wasm_i16x8_replace_lane(v, 7-(l), x) -#define v128_u16x8_replace_lane(v, l, x) simde_wasm_u16x8_replace_lane(v, 7-(l), x) -#define v128_i32x4_replace_lane(v, l, x) simde_wasm_i32x4_replace_lane(v, 3-(l), x) -#define v128_i64x2_replace_lane(v, l, x) simde_wasm_i64x2_replace_lane(v, 1-(l), x) -#define v128_f32x4_replace_lane(v, l, x) simde_wasm_f32x4_replace_lane(v, 3-(l), x) -#define v128_f64x2_replace_lane(v, l, x) simde_wasm_f64x2_replace_lane(v, 1-(l), x) -#define v128_i8x16_bitmask(v) simde_wasm_i8x16_bitmask(simde_wasm_i8x16_swizzle(v, simde_wasm_i8x16_const(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))) -#define v128_i16x8_bitmask(v) simde_wasm_i16x8_bitmask(simde_wasm_i8x16_swizzle(v, simde_wasm_i8x16_const(14,15,12,13,10,11,8,9,6,7,4,5,2,3,0,1))) -#define v128_i32x4_bitmask(v) simde_wasm_i32x4_bitmask(simde_wasm_i8x16_swizzle(v, simde_wasm_i8x16_const(12,13,14,15,8,9,10,11,4,5,6,7,0,1,2,3))) -#define v128_i64x2_bitmask(v) simde_wasm_i64x2_bitmask(simde_wasm_i8x16_swizzle(v, simde_wasm_i8x16_const(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7))) -#define v128_i8x16_swizzle(v1, v2) simde_wasm_i8x16_swizzle(v1, simde_wasm_v128_xor(v2, simde_wasm_i8x16_splat(15))) -#define v128_i8x16_shuffle(v1,v2,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) simde_wasm_i8x16_shuffle(v2,v1,31-(p),31-(o),31-(n),31-(m),31-(l),31-(k),31-(j),31-(i),31-(h),31-(g),31-(f),31-(e),31-(d),31-(c),31-(b),31-(a)) -#define v128_i16x8_extmul_high_i8x16 simde_wasm_i16x8_extmul_low_i8x16 -#define v128_u16x8_extmul_high_u8x16 simde_wasm_u16x8_extmul_low_u8x16 -#define v128_i16x8_extmul_low_i8x16 simde_wasm_i16x8_extmul_high_i8x16 -#define v128_u16x8_extmul_low_u8x16 simde_wasm_u16x8_extmul_high_u8x16 -#define v128_i32x4_extmul_high_i16x8 simde_wasm_i32x4_extmul_low_i16x8 -#define v128_u32x4_extmul_high_u16x8 simde_wasm_u32x4_extmul_low_u16x8 -#define v128_i32x4_extmul_low_i16x8 simde_wasm_i32x4_extmul_high_i16x8 -#define v128_u32x4_extmul_low_u16x8 simde_wasm_u32x4_extmul_high_u16x8 -#define v128_i64x2_extmul_high_i32x4 simde_wasm_i64x2_extmul_low_i32x4 -#define v128_u64x2_extmul_high_u32x4 simde_wasm_u64x2_extmul_low_u32x4 -#define v128_i64x2_extmul_low_i32x4 simde_wasm_i64x2_extmul_high_i32x4 -#define v128_u64x2_extmul_low_u32x4 simde_wasm_u64x2_extmul_high_u32x4 -#define v128_i16x8_extend_high_i8x16 simde_wasm_i16x8_extend_low_i8x16 -#define v128_u16x8_extend_high_u8x16 simde_wasm_u16x8_extend_low_u8x16 -#define v128_i16x8_extend_low_i8x16 simde_wasm_i16x8_extend_high_i8x16 -#define v128_u16x8_extend_low_u8x16 simde_wasm_u16x8_extend_high_u8x16 -#define v128_i32x4_extend_high_i16x8 simde_wasm_i32x4_extend_low_i16x8 -#define v128_u32x4_extend_high_u16x8 simde_wasm_u32x4_extend_low_u16x8 -#define v128_i32x4_extend_low_i16x8 simde_wasm_i32x4_extend_high_i16x8 -#define v128_u32x4_extend_low_u16x8 simde_wasm_u32x4_extend_high_u16x8 -#define v128_i64x2_extend_high_i32x4 simde_wasm_i64x2_extend_low_i32x4 -#define v128_u64x2_extend_high_u32x4 simde_wasm_u64x2_extend_low_u32x4 -#define v128_i64x2_extend_low_i32x4 simde_wasm_i64x2_extend_high_i32x4 -#define v128_u64x2_extend_low_u32x4 simde_wasm_u64x2_extend_high_u32x4 -#define v128_i32x4_trunc_sat_f64x2_zero(a) \ - simde_wasm_i8x16_swizzle( \ - simde_wasm_i32x4_trunc_sat_f64x2_zero(a), \ - simde_wasm_i8x16_const(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)) -#define v128_u32x4_trunc_sat_f64x2_zero(a) \ - simde_wasm_i8x16_swizzle( \ - simde_wasm_u32x4_trunc_sat_f64x2_zero(a), \ - simde_wasm_i8x16_const(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)) -#define v128_i16x8_narrow_i32x4(a,b) simde_wasm_i16x8_narrow_i32x4(b,a) -#define v128_u16x8_narrow_i32x4(a,b) simde_wasm_u16x8_narrow_i32x4(b,a) -#define v128_i8x16_narrow_i16x8(a,b) simde_wasm_i8x16_narrow_i16x8(b,a) -#define v128_u8x16_narrow_i16x8(a,b) simde_wasm_u8x16_narrow_i16x8(b,a) -#define v128_f64x2_promote_low_f32x4(a) \ - simde_wasm_f64x2_promote_low_f32x4(simde_wasm_i8x16_swizzle( \ - a, \ - simde_wasm_i8x16_const(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7))) -#define v128_f32x4_demote_f64x2_zero(a) \ - simde_wasm_i8x16_swizzle( \ - simde_wasm_f32x4_demote_f64x2_zero(a), \ - simde_wasm_i8x16_const(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)) -#define v128_f64x2_convert_low_i32x4(a) \ - simde_wasm_f64x2_convert_low_i32x4(simde_wasm_i8x16_swizzle( \ - a, \ - simde_wasm_i8x16_const(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7))) -#define v128_f64x2_convert_low_u32x4(a) \ - simde_wasm_f64x2_convert_low_u32x4(simde_wasm_i8x16_swizzle( \ - a, \ - simde_wasm_i8x16_const(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7))) -#else -#define v128_const simde_wasm_i8x16_const -#define v128_i8x16_extract_lane simde_wasm_i8x16_extract_lane -#define v128_u8x16_extract_lane simde_wasm_u8x16_extract_lane -#define v128_i16x8_extract_lane simde_wasm_i16x8_extract_lane -#define v128_u16x8_extract_lane simde_wasm_u16x8_extract_lane -#define v128_i32x4_extract_lane simde_wasm_i32x4_extract_lane -#define v128_i64x2_extract_lane simde_wasm_i64x2_extract_lane -#define v128_f32x4_extract_lane simde_wasm_f32x4_extract_lane -#define v128_f64x2_extract_lane simde_wasm_f64x2_extract_lane -#define v128_i8x16_replace_lane simde_wasm_i8x16_replace_lane -#define v128_u8x16_replace_lane simde_wasm_u8x16_replace_lane -#define v128_i16x8_replace_lane simde_wasm_i16x8_replace_lane -#define v128_u16x8_replace_lane simde_wasm_u16x8_replace_lane -#define v128_i32x4_replace_lane simde_wasm_i32x4_replace_lane -#define v128_i64x2_replace_lane simde_wasm_i64x2_replace_lane -#define v128_f32x4_replace_lane simde_wasm_f32x4_replace_lane -#define v128_f64x2_replace_lane simde_wasm_f64x2_replace_lane -#define v128_i8x16_bitmask simde_wasm_i8x16_bitmask -#define v128_i16x8_bitmask simde_wasm_i16x8_bitmask -#define v128_i32x4_bitmask simde_wasm_i32x4_bitmask -#define v128_i64x2_bitmask simde_wasm_i64x2_bitmask -#define v128_i8x16_swizzle simde_wasm_i8x16_swizzle -#define v128_i8x16_shuffle simde_wasm_i8x16_shuffle -#define v128_i16x8_extmul_high_i8x16 simde_wasm_i16x8_extmul_high_i8x16 -#define v128_u16x8_extmul_high_u8x16 simde_wasm_u16x8_extmul_high_u8x16 -#define v128_i16x8_extmul_low_i8x16 simde_wasm_i16x8_extmul_low_i8x16 -#define v128_u16x8_extmul_low_u8x16 simde_wasm_u16x8_extmul_low_u8x16 -#define v128_i32x4_extmul_high_i16x8 simde_wasm_i32x4_extmul_high_i16x8 -#define v128_u32x4_extmul_high_u16x8 simde_wasm_u32x4_extmul_high_u16x8 -#define v128_i32x4_extmul_low_i16x8 simde_wasm_i32x4_extmul_low_i16x8 -#define v128_u32x4_extmul_low_u16x8 simde_wasm_u32x4_extmul_low_u16x8 -#define v128_i64x2_extmul_high_i32x4 simde_wasm_i64x2_extmul_high_i32x4 -#define v128_u64x2_extmul_high_u32x4 simde_wasm_u64x2_extmul_high_u32x4 -#define v128_i64x2_extmul_low_i32x4 simde_wasm_i64x2_extmul_low_i32x4 -#define v128_u64x2_extmul_low_u32x4 simde_wasm_u64x2_extmul_low_u32x4 -#define v128_i16x8_extend_high_i8x16 simde_wasm_i16x8_extend_high_i8x16 -#define v128_u16x8_extend_high_u8x16 simde_wasm_u16x8_extend_high_u8x16 -#define v128_i16x8_extend_low_i8x16 simde_wasm_i16x8_extend_low_i8x16 -#define v128_u16x8_extend_low_u8x16 simde_wasm_u16x8_extend_low_u8x16 -#define v128_i32x4_extend_high_i16x8 simde_wasm_i32x4_extend_high_i16x8 -#define v128_u32x4_extend_high_u16x8 simde_wasm_u32x4_extend_high_u16x8 -#define v128_i32x4_extend_low_i16x8 simde_wasm_i32x4_extend_low_i16x8 -#define v128_u32x4_extend_low_u16x8 simde_wasm_u32x4_extend_low_u16x8 -#define v128_i64x2_extend_high_i32x4 simde_wasm_i64x2_extend_high_i32x4 -#define v128_u64x2_extend_high_u32x4 simde_wasm_u64x2_extend_high_u32x4 -#define v128_i64x2_extend_low_i32x4 simde_wasm_i64x2_extend_low_i32x4 -#define v128_u64x2_extend_low_u32x4 simde_wasm_u64x2_extend_low_u32x4 -#define v128_i32x4_trunc_sat_f64x2_zero simde_wasm_i32x4_trunc_sat_f64x2_zero -#define v128_u32x4_trunc_sat_f64x2_zero simde_wasm_u32x4_trunc_sat_f64x2_zero -#define v128_i16x8_narrow_i32x4 simde_wasm_i16x8_narrow_i32x4 -#define v128_u16x8_narrow_i32x4 simde_wasm_u16x8_narrow_i32x4 -#define v128_i8x16_narrow_i16x8 simde_wasm_i8x16_narrow_i16x8 -#define v128_u8x16_narrow_i16x8 simde_wasm_u8x16_narrow_i16x8 -#define v128_f64x2_promote_low_f32x4 simde_wasm_f64x2_promote_low_f32x4 -#define v128_f32x4_demote_f64x2_zero simde_wasm_f32x4_demote_f64x2_zero -#define v128_f64x2_convert_low_i32x4 simde_wasm_f64x2_convert_low_i32x4 -#define v128_f64x2_convert_low_u32x4 simde_wasm_f64x2_convert_low_u32x4 -#endif -// clang-format on -)w2c_template"; diff --git a/src/tools/wasm2c/prebuilt/wasm2c_source_declarations.cpp b/src/tools/wasm2c/prebuilt/wasm2c_source_declarations.cpp deleted file mode 100644 index 9ded51204a3..00000000000 --- a/src/tools/wasm2c/prebuilt/wasm2c_source_declarations.cpp +++ /dev/null @@ -1,727 +0,0 @@ -const char* SourceDeclarations = R"w2c_template( -// Computes a pointer to an object of the given size in a little-endian memory. -// -// On a little-endian host, this is just &mem->data[addr] - the object's size is -// unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -// is the object's size. -// -// Note that mem may be evaluated multiple times. -// -// Parameters: -// mem - The memory. -// addr - The address. -// n - The size of the object. -// -// Result: -// A pointer for an object of size n. -#if WASM_RT_BIG_ENDIAN -#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -#else -#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) -#endif - -// We can only use Segue for this module if it uses a single unshared imported -// or exported memory -#if WASM_RT_USE_SEGUE && IS_SINGLE_UNSHARED_MEMORY -#define WASM_RT_USE_SEGUE_FOR_THIS_MODULE 1 -#else -#define WASM_RT_USE_SEGUE_FOR_THIS_MODULE 0 -#endif - -#if WASM_RT_USE_SEGUE_FOR_THIS_MODULE -// POSIX uses FS for TLS, GS is free -static inline void* wasm_rt_segue_read_base() { - if (wasm_rt_fsgsbase_inst_supported) { - return (void*)__builtin_ia32_rdgsbase64(); - } else { - return wasm_rt_syscall_get_segue_base(); - } -} -static inline void wasm_rt_segue_write_base(void* base) { -#if WASM_RT_SEGUE_FREE_SEGMENT - if (wasm_rt_last_segment_val == base) { - return; - } - - wasm_rt_last_segment_val = base; -#endif - - if (wasm_rt_fsgsbase_inst_supported) { - __builtin_ia32_wrgsbase64((uintptr_t)base); - } else { - wasm_rt_syscall_set_segue_base(base); - } -} -#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) -#else -#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) -#endif - -#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) - -#if WASM_RT_STACK_DEPTH_COUNT -#define FUNC_PROLOGUE \ - if (++wasm_rt_call_stack_depth > WASM_RT_MAX_CALL_STACK_DEPTH) \ - TRAP(EXHAUSTION); - -#define FUNC_EPILOGUE --wasm_rt_call_stack_depth -#else -#define FUNC_PROLOGUE - -#define FUNC_EPILOGUE -#endif - -#define UNREACHABLE TRAP(UNREACHABLE) - -static inline bool func_types_eq(const wasm_rt_func_type_t a, - const wasm_rt_func_type_t b) { - return (a == b) || LIKELY(a && b && !memcmp(a, b, 32)); -} - -#define CHECK_CALL_INDIRECT(table, ft, x) \ - (LIKELY((x) < table.size && table.data[x].func && \ - func_types_eq(ft, table.data[x].func_type)) || \ - TRAP(CALL_INDIRECT)) - -#define DO_CALL_INDIRECT(table, t, x, ...) ((t)table.data[x].func)(__VA_ARGS__) - -#define CALL_INDIRECT(table, t, ft, x, ...) \ - (CHECK_CALL_INDIRECT(table, ft, x), \ - DO_CALL_INDIRECT(table, t, x, __VA_ARGS__)) - -static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) { -#if __has_builtin(__builtin_add_overflow) - return __builtin_add_overflow(a, b, resptr); -#elif defined(_MSC_VER) - return _addcarry_u64(0, a, b, resptr); -#else -#error "Missing implementation of __builtin_add_overflow or _addcarry_u64" -#endif -} - -#define RANGE_CHECK(mem, offset, len) \ - do { \ - uint64_t res; \ - if (UNLIKELY(add_overflow(offset, len, &res))) \ - TRAP(OOB); \ - if (UNLIKELY(res > (mem)->size)) \ - TRAP(OOB); \ - } while (0); - -#if WASM_RT_USE_SEGUE_FOR_THIS_MODULE && WASM_RT_SANITY_CHECKS -#include -#define WASM_RT_CHECK_BASE(mem) \ - if (((uintptr_t)((mem)->data)) != ((uintptr_t)wasm_rt_segue_read_base())) { \ - puts("Segment register mismatch\n"); \ - abort(); \ - } -#else -#define WASM_RT_CHECK_BASE(mem) -#endif - -// MEMCHECK_DEFAULT32 is an "accelerated" MEMCHECK used only for -// default-page-size, 32-bit memories. It may do nothing at all -// (if hardware bounds-checking is enabled via guard pages) -// or it may do a slightly faster RANGE_CHECK. -#if WASM_RT_MEMCHECK_GUARD_PAGES -#define MEMCHECK_DEFAULT32(mem, a, t) WASM_RT_CHECK_BASE(mem); -#else -#define MEMCHECK_DEFAULT32(mem, a, t) \ - WASM_RT_CHECK_BASE(mem); \ - if (UNLIKELY(a + (uint64_t)sizeof(t) > mem->size)) \ - TRAP(OOB); -#endif - -// MEMCHECK_GENERAL can be used for any memory -#define MEMCHECK_GENERAL(mem, a, t) \ - WASM_RT_CHECK_BASE(mem); \ - RANGE_CHECK(mem, a, sizeof(t)); - -#ifdef __GNUC__ -#define FORCE_READ_INT(var) __asm__("" ::"r"(var)); -// Clang on Mips requires "f" constraints on floats -// See https://github.com/llvm/llvm-project/issues/64241 -#if defined(__clang__) && \ - (defined(mips) || defined(__mips__) || defined(__mips)) -#define FORCE_READ_FLOAT(var) __asm__("" ::"f"(var)); -#else -#define FORCE_READ_FLOAT(var) __asm__("" ::"r"(var)); -#endif -#else -#define FORCE_READ_INT(var) -#define FORCE_READ_FLOAT(var) -#endif - -static inline void load_data(u8* dest, const u8* src, size_t n) { - if (!n) { - return; - } -#if WASM_RT_BIG_ENDIAN - for (size_t i = 0; i < n; i++) { - dest[i] = src[n - i - 1]; - } -#else - wasm_rt_memcpy(dest, src, n); -#endif -} - -#define LOAD_DATA(m, o, i, s) \ - do { \ - RANGE_CHECK((&m), o, s); \ - load_data(MEM_ADDR(&m, o, s), i, s); \ - } while (0) - -#define DEF_MEM_CHECKS0(name, shared, mem_type, ret_kw, return_type) \ - static inline return_type name##_default32(wasm_rt##shared##memory_t* mem, \ - u64 addr) { \ - MEMCHECK_DEFAULT32(mem, addr, mem_type); \ - ret_kw name##_unchecked(mem, addr); \ - } \ - static inline return_type name(wasm_rt##shared##memory_t* mem, u64 addr) { \ - MEMCHECK_GENERAL(mem, addr, mem_type); \ - ret_kw name##_unchecked(mem, addr); \ - } - -#define DEF_MEM_CHECKS1(name, shared, mem_type, ret_kw, return_type, \ - val_type1) \ - static inline return_type name##_default32(wasm_rt##shared##memory_t* mem, \ - u64 addr, val_type1 val1) { \ - MEMCHECK_DEFAULT32(mem, addr, mem_type); \ - ret_kw name##_unchecked(mem, addr, val1); \ - } \ - static inline return_type name(wasm_rt##shared##memory_t* mem, u64 addr, \ - val_type1 val1) { \ - MEMCHECK_GENERAL(mem, addr, mem_type); \ - ret_kw name##_unchecked(mem, addr, val1); \ - } - -#define DEF_MEM_CHECKS2(name, shared, mem_type, ret_kw, return_type, \ - val_type1, val_type2) \ - static inline return_type name##_default32(wasm_rt##shared##memory_t* mem, \ - u64 addr, val_type1 val1, \ - val_type2 val2) { \ - MEMCHECK_DEFAULT32(mem, addr, mem_type); \ - ret_kw name##_unchecked(mem, addr, val1, val2); \ - } \ - static inline return_type name(wasm_rt##shared##memory_t* mem, u64 addr, \ - val_type1 val1, val_type2 val2) { \ - MEMCHECK_GENERAL(mem, addr, mem_type); \ - ret_kw name##_unchecked(mem, addr, val1, val2); \ - } - -#define DEFINE_LOAD(name, t1, t2, t3, force_read) \ - static inline t3 name##_unchecked(wasm_rt_memory_t* mem, u64 addr) { \ - t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ - force_read(result); \ - return (t3)(t2)result; \ - } \ - DEF_MEM_CHECKS0(name, _, t1, return, t3) - -#define DEFINE_STORE(name, t1, t2) \ - static inline void name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \ - t2 value) { \ - t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ - } \ - DEF_MEM_CHECKS1(name, _, t1, , void, t2) - -DEFINE_LOAD(i32_load, u32, u32, u32, FORCE_READ_INT) -DEFINE_LOAD(i64_load, u64, u64, u64, FORCE_READ_INT) -DEFINE_LOAD(f32_load, f32, f32, f32, FORCE_READ_FLOAT) -DEFINE_LOAD(f64_load, f64, f64, f64, FORCE_READ_FLOAT) -DEFINE_LOAD(i32_load8_s, s8, s32, u32, FORCE_READ_INT) -DEFINE_LOAD(i64_load8_s, s8, s64, u64, FORCE_READ_INT) -DEFINE_LOAD(i32_load8_u, u8, u32, u32, FORCE_READ_INT) -DEFINE_LOAD(i64_load8_u, u8, u64, u64, FORCE_READ_INT) -DEFINE_LOAD(i32_load16_s, s16, s32, u32, FORCE_READ_INT) -DEFINE_LOAD(i64_load16_s, s16, s64, u64, FORCE_READ_INT) -DEFINE_LOAD(i32_load16_u, u16, u32, u32, FORCE_READ_INT) -DEFINE_LOAD(i64_load16_u, u16, u64, u64, FORCE_READ_INT) -DEFINE_LOAD(i64_load32_s, s32, s64, u64, FORCE_READ_INT) -DEFINE_LOAD(i64_load32_u, u32, u64, u64, FORCE_READ_INT) -DEFINE_STORE(i32_store, u32, u32) -DEFINE_STORE(i64_store, u64, u64) -DEFINE_STORE(f32_store, f32, f32) -DEFINE_STORE(f64_store, f64, f64) -DEFINE_STORE(i32_store8, u8, u32) -DEFINE_STORE(i32_store16, u16, u32) -DEFINE_STORE(i64_store8, u8, u64) -DEFINE_STORE(i64_store16, u16, u64) -DEFINE_STORE(i64_store32, u32, u64) - -#if defined(_MSC_VER) - -// Adapted from -// https://github.com/nemequ/portable-snippets/blob/master/builtin/builtin.h - -static inline int I64_CLZ(unsigned long long v) { - unsigned long r = 0; -#if defined(_M_AMD64) || defined(_M_ARM) - if (_BitScanReverse64(&r, v)) { - return 63 - r; - } -#else - if (_BitScanReverse(&r, (unsigned long)(v >> 32))) { - return 31 - r; - } else if (_BitScanReverse(&r, (unsigned long)v)) { - return 63 - r; - } -#endif - return 64; -} - -static inline int I32_CLZ(unsigned long v) { - unsigned long r = 0; - if (_BitScanReverse(&r, v)) { - return 31 - r; - } - return 32; -} - -static inline int I64_CTZ(unsigned long long v) { - if (!v) { - return 64; - } - unsigned long r = 0; -#if defined(_M_AMD64) || defined(_M_ARM) - _BitScanForward64(&r, v); - return (int)r; -#else - if (_BitScanForward(&r, (unsigned int)(v))) { - return (int)(r); - } - - _BitScanForward(&r, (unsigned int)(v >> 32)); - return (int)(r + 32); -#endif -} - -static inline int I32_CTZ(unsigned long v) { - if (!v) { - return 32; - } - unsigned long r = 0; - _BitScanForward(&r, v); - return (int)r; -} - -#define POPCOUNT_DEFINE_PORTABLE(f_n, T) \ - static inline u32 f_n(T x) { \ - x = x - ((x >> 1) & (T) ~(T)0 / 3); \ - x = (x & (T) ~(T)0 / 15 * 3) + ((x >> 2) & (T) ~(T)0 / 15 * 3); \ - x = (x + (x >> 4)) & (T) ~(T)0 / 255 * 15; \ - return (T)(x * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8; \ - } - -POPCOUNT_DEFINE_PORTABLE(I32_POPCNT, u32) -POPCOUNT_DEFINE_PORTABLE(I64_POPCNT, u64) - -#undef POPCOUNT_DEFINE_PORTABLE - -#else - -#define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32) -#define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64) -#define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32) -#define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64) -#define I32_POPCNT(x) (__builtin_popcount(x)) -#define I64_POPCNT(x) (__builtin_popcountll(x)) - -#endif - -#define DIV_S(ut, min, x, y) \ - ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ - : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \ - : (ut)((x) / (y))) - -#define REM_S(ut, min, x, y) \ - ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ - : (UNLIKELY((x) == min && (y) == -1)) ? 0 \ - : (ut)((x) % (y))) - -#define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y) -#define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y) -#define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y) -#define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y) - -#define DIVREM_U(op, x, y) \ - ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x)op(y))) - -#define DIV_U(x, y) DIVREM_U(/, x, y) -#define REM_U(x, y) DIVREM_U(%, x, y) - -#define ROTL(x, y, mask) \ - (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask)))) -#define ROTR(x, y, mask) \ - (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask)))) - -#define I32_ROTL(x, y) ROTL(x, y, 31) -#define I64_ROTL(x, y) ROTL(x, y, 63) -#define I32_ROTR(x, y) ROTR(x, y, 31) -#define I64_ROTR(x, y) ROTR(x, y, 63) - -#define FMIN(x, y) \ - ((UNLIKELY((x) != (x))) ? NAN \ - : (UNLIKELY((y) != (y))) ? NAN \ - : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \ - : (x < y) ? x \ - : y) - -#define FMAX(x, y) \ - ((UNLIKELY((x) != (x))) ? NAN \ - : (UNLIKELY((y) != (y))) ? NAN \ - : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \ - : (x > y) ? x \ - : y) - -#define TRUNC_S(ut, st, ft, min, minop, max, x) \ - ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ - : (UNLIKELY(!((x)minop(min) && (x) < (max)))) ? TRAP(INT_OVERFLOW) \ - : (ut)(st)(x)) - -#define I32_TRUNC_S_F32(x) \ - TRUNC_S(u32, s32, f32, (f32)INT32_MIN, >=, 2147483648.f, x) -#define I64_TRUNC_S_F32(x) \ - TRUNC_S(u64, s64, f32, (f32)INT64_MIN, >=, (f32)INT64_MAX, x) -#define I32_TRUNC_S_F64(x) \ - TRUNC_S(u32, s32, f64, -2147483649., >, 2147483648., x) -#define I64_TRUNC_S_F64(x) \ - TRUNC_S(u64, s64, f64, (f64)INT64_MIN, >=, (f64)INT64_MAX, x) - -#define TRUNC_U(ut, ft, max, x) \ - ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ - : (UNLIKELY(!((x) > (ft) - 1 && (x) < (max)))) ? TRAP(INT_OVERFLOW) \ - : (ut)(x)) - -#define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, 4294967296.f, x) -#define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, (f32)UINT64_MAX, x) -#define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, 4294967296., x) -#define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, (f64)UINT64_MAX, x) - -#define TRUNC_SAT_S(ut, st, ft, min, smin, minop, max, smax, x) \ - ((UNLIKELY((x) != (x))) ? 0 \ - : (UNLIKELY(!((x)minop(min)))) ? smin \ - : (UNLIKELY(!((x) < (max)))) ? smax \ - : (ut)(st)(x)) - -#define I32_TRUNC_SAT_S_F32(x) \ - TRUNC_SAT_S(u32, s32, f32, (f32)INT32_MIN, INT32_MIN, >=, 2147483648.f, \ - INT32_MAX, x) -#define I64_TRUNC_SAT_S_F32(x) \ - TRUNC_SAT_S(u64, s64, f32, (f32)INT64_MIN, INT64_MIN, >=, (f32)INT64_MAX, \ - INT64_MAX, x) -#define I32_TRUNC_SAT_S_F64(x) \ - TRUNC_SAT_S(u32, s32, f64, -2147483649., INT32_MIN, >, 2147483648., \ - INT32_MAX, x) -#define I64_TRUNC_SAT_S_F64(x) \ - TRUNC_SAT_S(u64, s64, f64, (f64)INT64_MIN, INT64_MIN, >=, (f64)INT64_MAX, \ - INT64_MAX, x) -)w2c_template" - R"w2c_template( -#define TRUNC_SAT_U(ut, ft, max, smax, x) \ - ((UNLIKELY((x) != (x))) ? 0 \ - : (UNLIKELY(!((x) > (ft) - 1))) ? 0 \ - : (UNLIKELY(!((x) < (max)))) ? smax \ - : (ut)(x)) - -#define I32_TRUNC_SAT_U_F32(x) \ - TRUNC_SAT_U(u32, f32, 4294967296.f, UINT32_MAX, x) -#define I64_TRUNC_SAT_U_F32(x) \ - TRUNC_SAT_U(u64, f32, (f32)UINT64_MAX, UINT64_MAX, x) -#define I32_TRUNC_SAT_U_F64(x) TRUNC_SAT_U(u32, f64, 4294967296., UINT32_MAX, x) -#define I64_TRUNC_SAT_U_F64(x) \ - TRUNC_SAT_U(u64, f64, (f64)UINT64_MAX, UINT64_MAX, x) - -#define DEFINE_REINTERPRET(name, t1, t2) \ - static inline t2 name(t1 x) { \ - t2 result; \ - wasm_rt_memcpy(&result, &x, sizeof(result)); \ - return result; \ - } - -DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32) -DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32) -DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64) -DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64) - -static float quiet_nanf(float x) { - uint32_t tmp; - wasm_rt_memcpy(&tmp, &x, 4); - tmp |= 0x7fc00000lu; - wasm_rt_memcpy(&x, &tmp, 4); - return x; -} - -static double quiet_nan(double x) { - uint64_t tmp; - wasm_rt_memcpy(&tmp, &x, 8); - tmp |= 0x7ff8000000000000llu; - wasm_rt_memcpy(&x, &tmp, 8); - return x; -} - -static double wasm_quiet(double x) { - if (UNLIKELY(isnan(x))) { - return quiet_nan(x); - } - return x; -} - -static float wasm_quietf(float x) { - if (UNLIKELY(isnan(x))) { - return quiet_nanf(x); - } - return x; -} - -static double wasm_floor(double x) { - if (UNLIKELY(isnan(x))) { - return quiet_nan(x); - } - return floor(x); -} - -static float wasm_floorf(float x) { - if (UNLIKELY(isnan(x))) { - return quiet_nanf(x); - } - return floorf(x); -} - -static double wasm_ceil(double x) { - if (UNLIKELY(isnan(x))) { - return quiet_nan(x); - } - return ceil(x); -} - -static float wasm_ceilf(float x) { - if (UNLIKELY(isnan(x))) { - return quiet_nanf(x); - } - return ceilf(x); -} - -static double wasm_trunc(double x) { - if (UNLIKELY(isnan(x))) { - return quiet_nan(x); - } - return trunc(x); -} - -static float wasm_truncf(float x) { - if (UNLIKELY(isnan(x))) { - return quiet_nanf(x); - } - return truncf(x); -} - -static float wasm_nearbyintf(float x) { - if (UNLIKELY(isnan(x))) { - return quiet_nanf(x); - } - return nearbyintf(x); -} - -static double wasm_nearbyint(double x) { - if (UNLIKELY(isnan(x))) { - return quiet_nan(x); - } - return nearbyint(x); -} - -static float wasm_fabsf(float x) { - if (UNLIKELY(isnan(x))) { - uint32_t tmp; - wasm_rt_memcpy(&tmp, &x, 4); - tmp = tmp & ~(1UL << 31); - wasm_rt_memcpy(&x, &tmp, 4); - return x; - } - return fabsf(x); -} - -static double wasm_fabs(double x) { - if (UNLIKELY(isnan(x))) { - uint64_t tmp; - wasm_rt_memcpy(&tmp, &x, 8); - tmp = tmp & ~(1ULL << 63); - wasm_rt_memcpy(&x, &tmp, 8); - return x; - } - return fabs(x); -} - -static double wasm_sqrt(double x) { - if (UNLIKELY(isnan(x))) { - return quiet_nan(x); - } - return sqrt(x); -} - -static float wasm_sqrtf(float x) { - if (UNLIKELY(isnan(x))) { - return quiet_nanf(x); - } - return sqrtf(x); -} - -static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { - RANGE_CHECK(mem, d, n); - memset(MEM_ADDR(mem, d, n), val, n); -} - -static inline void memory_copy(wasm_rt_memory_t* dest, - const wasm_rt_memory_t* src, - u64 dest_addr, - u64 src_addr, - u64 n) { - RANGE_CHECK(dest, dest_addr, n); - RANGE_CHECK(src, src_addr, n); - memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); -} - -static inline void memory_init(wasm_rt_memory_t* dest, - const u8* src, - u32 src_size, - u64 dest_addr, - u32 src_addr, - u32 n) { - if (UNLIKELY(src_addr + (uint64_t)n > src_size)) - TRAP(OOB); - LOAD_DATA((*dest), dest_addr, src + src_addr, n); -} - -typedef enum { RefFunc, RefNull, GlobalGet } wasm_elem_segment_expr_type_t; - -typedef struct { - wasm_elem_segment_expr_type_t expr_type; - wasm_rt_func_type_t type; - wasm_rt_function_ptr_t func; - wasm_rt_tailcallee_t func_tailcallee; - size_t module_offset; -} wasm_elem_segment_expr_t; - -static inline void funcref_table_init(wasm_rt_funcref_table_t* dest, - const wasm_elem_segment_expr_t* src, - u32 src_size, - u64 dest_addr, - u32 src_addr, - u32 n, - void* module_instance) { - if (UNLIKELY(src_addr + (uint64_t)n > src_size)) - TRAP(OOB); - RANGE_CHECK(dest, dest_addr, n); - for (u32 i = 0; i < n; i++) { - const wasm_elem_segment_expr_t* const src_expr = &src[src_addr + i]; - wasm_rt_funcref_t* const dest_val = &(dest->data[dest_addr + i]); - switch (src_expr->expr_type) { - case RefFunc: - *dest_val = (wasm_rt_funcref_t){ - src_expr->type, src_expr->func, src_expr->func_tailcallee, - (char*)module_instance + src_expr->module_offset}; - break; - case RefNull: - *dest_val = wasm_rt_funcref_null_value; - break; - case GlobalGet: - *dest_val = **(wasm_rt_funcref_t**)((char*)module_instance + - src_expr->module_offset); - break; - } - } -} - -// Currently wasm2c only supports initializing externref tables with ref.null. -static inline void externref_table_init(wasm_rt_externref_table_t* dest, - u32 src_size, - u64 dest_addr, - u32 src_addr, - u32 n) { - if (UNLIKELY(src_addr + (uint64_t)n > src_size)) - TRAP(OOB); - RANGE_CHECK(dest, dest_addr, n); - for (u32 i = 0; i < n; i++) { - dest->data[dest_addr + i] = wasm_rt_externref_null_value; - } -} - -#define DEFINE_TABLE_COPY(type) \ - static inline void type##_table_copy(wasm_rt_##type##_table_t* dest, \ - const wasm_rt_##type##_table_t* src, \ - u64 dest_addr, u64 src_addr, u64 n) { \ - RANGE_CHECK(dest, dest_addr, n); \ - RANGE_CHECK(src, src_addr, n); \ - memmove(dest->data + dest_addr, src->data + src_addr, \ - n * sizeof(wasm_rt_##type##_t)); \ - } - -DEFINE_TABLE_COPY(funcref) -DEFINE_TABLE_COPY(externref) - -#define DEFINE_TABLE_GET(type) \ - static inline wasm_rt_##type##_t type##_table_get( \ - const wasm_rt_##type##_table_t* table, u64 i) { \ - if (UNLIKELY(i >= table->size)) \ - TRAP(OOB); \ - return table->data[i]; \ - } - -DEFINE_TABLE_GET(funcref) -DEFINE_TABLE_GET(externref) - -#define DEFINE_TABLE_SET(type) \ - static inline void type##_table_set(const wasm_rt_##type##_table_t* table, \ - u64 i, const wasm_rt_##type##_t val) { \ - if (UNLIKELY(i >= table->size)) \ - TRAP(OOB); \ - table->data[i] = val; \ - } - -DEFINE_TABLE_SET(funcref) -DEFINE_TABLE_SET(externref) - -#define DEFINE_TABLE_FILL(type) \ - static inline void type##_table_fill(const wasm_rt_##type##_table_t* table, \ - u64 d, const wasm_rt_##type##_t val, \ - u64 n) { \ - RANGE_CHECK(table, d, n); \ - for (uint32_t i = d; i < d + n; i++) { \ - table->data[i] = val; \ - } \ - } - -DEFINE_TABLE_FILL(funcref) -DEFINE_TABLE_FILL(externref) - -#if defined(__GNUC__) || defined(__clang__) -#define FUNC_TYPE_DECL_EXTERN_T(x) extern const char* const x -#define FUNC_TYPE_EXTERN_T(x) const char* const x -#define FUNC_TYPE_T(x) static const char* const x -#else -#define FUNC_TYPE_DECL_EXTERN_T(x) extern const char x[] -#define FUNC_TYPE_EXTERN_T(x) const char x[] -#define FUNC_TYPE_T(x) static const char x[] -#endif - -#if (__STDC_VERSION__ < 201112L) && !defined(static_assert) -#define static_assert(X) \ - extern int(*assertion(void))[!!sizeof(struct { int x : (X) ? 2 : -1; })]; -#endif - -#ifdef _MSC_VER -#define WEAK_FUNC_DECL(func, fallback) \ - __pragma(comment(linker, "/alternatename:" #func "=" #fallback)) \ - \ - void \ - fallback(void** instance_ptr, void* tail_call_stack, \ - wasm_rt_tailcallee_t* next) -#else -#define WEAK_FUNC_DECL(func, fallback) \ - __attribute__((weak)) void func(void** instance_ptr, void* tail_call_stack, \ - wasm_rt_tailcallee_t* next) -#endif -)w2c_template"; diff --git a/src/tools/wasm2c/prebuilt/wasm2c_source_includes.cpp b/src/tools/wasm2c/prebuilt/wasm2c_source_includes.cpp deleted file mode 100644 index 933e58ba8bf..00000000000 --- a/src/tools/wasm2c/prebuilt/wasm2c_source_includes.cpp +++ /dev/null @@ -1,17 +0,0 @@ -const char* SourceIncludes = R"w2c_template(#include -#include -#include -#include -#include -#if defined(__MINGW32__) -#include -#elif defined(_MSC_VER) -#include -#include -#define alloca _alloca -#elif defined(__FreeBSD__) || defined(__OpenBSD__) -#include -#else -#include -#endif -)w2c_template"; diff --git a/src/tools/wasm2c/prebuilt/wasm2c_spec_top.cpp b/src/tools/wasm2c/prebuilt/wasm2c_spec_top.cpp deleted file mode 100644 index 0096cddcb1c..00000000000 --- a/src/tools/wasm2c/prebuilt/wasm2c_spec_top.cpp +++ /dev/null @@ -1,504 +0,0 @@ -const char* SpecTop = R"w2c_template(#include -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wasm-rt.h" -#include "wasm-rt-impl.h" -#include "wasm-rt-exceptions.h" - -/* NOTE: function argument evaluation order is implementation-defined in C, - so it SHOULD NOT be relied on by tests. */ -#if WASM_RT_BIG_ENDIAN -#define v128_i8x16_make(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \ - simde_wasm_i8x16_make(p,o,n,m,l,k,j,i,h,g,f,e,d,c,b,a) -#define v128_u8x16_make(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \ - simde_wasm_u8x16_make(p,o,n,m,l,k,j,i,h,g,f,e,d,c,b,a) -#define v128_i16x8_make(a,b,c,d,e,f,g,h) simde_wasm_i16x8_make(h,g,f,e,d,c,b,a) -#define v128_u16x8_make(a,b,c,d,e,f,g,h) simde_wasm_u16x8_make(h,g,f,e,d,c,b,a) -#define v128_i32x4_make(a,b,c,d) simde_wasm_i32x4_make(d,c,b,a) -#define v128_u32x4_make(a,b,c,d) simde_wasm_u32x4_make(d,c,b,a) -#define v128_i64x2_make(a,b) simde_wasm_i64x2_make(b,a) -#define v128_u64x2_make(a,b) simde_wasm_u64x2_make(b,a) -#define v128_f32x4_make(a,b,c,d) simde_wasm_f32x4_make(d,c,b,a) -#define v128_f64x2_make(a,b) simde_wasm_f64x2_make(b,a) -#define v128_i8x16_extract_lane(a,n) simde_wasm_u8x16_extract_lane(a,15-(n)) -#define v128_u8x16_extract_lane(a,n) simde_wasm_u8x16_extract_lane(a,15-(n)) -#define v128_i16x8_extract_lane(a,n) simde_wasm_u16x8_extract_lane(a,7-(n)) -#define v128_u16x8_extract_lane(a,n) simde_wasm_u16x8_extract_lane(a,7-(n)) -#define v128_i32x4_extract_lane(a,n) simde_wasm_u32x4_extract_lane(a,3-(n)) -#define v128_u32x4_extract_lane(a,n) simde_wasm_u32x4_extract_lane(a,3-(n)) -#define v128_i64x2_extract_lane(a,n) simde_wasm_u64x2_extract_lane(a,1-(n)) -#define v128_u64x2_extract_lane(a,n) simde_wasm_u64x2_extract_lane(a,1-(n)) -#define v128_f32x4_extract_lane(a,n) simde_wasm_f32x4_extract_lane(a,3-(n)) -#define v128_f64x2_extract_lane(a,n) simde_wasm_f64x2_extract_lane(a,1-(n)) -#else -#define v128_i8x16_make simde_wasm_i8x16_make -#define v128_u8x16_make simde_wasm_u8x16_make -#define v128_i16x8_make simde_wasm_i16x8_make -#define v128_u16x8_make simde_wasm_u16x8_make -#define v128_i32x4_make simde_wasm_i32x4_make -#define v128_u32x4_make simde_wasm_u32x4_make -#define v128_i64x2_make simde_wasm_i64x2_make -#define v128_u64x2_make simde_wasm_u64x2_make -#define v128_f32x4_make simde_wasm_f32x4_make -#define v128_f64x2_make simde_wasm_f64x2_make -// like is_equal_TYPE below, always use unsigned for these -#define v128_i8x16_extract_lane simde_wasm_u8x16_extract_lane -#define v128_u8x16_extract_lane simde_wasm_u8x16_extract_lane -#define v128_i16x8_extract_lane simde_wasm_u16x8_extract_lane -#define v128_u16x8_extract_lane simde_wasm_u16x8_extract_lane -#define v128_i32x4_extract_lane simde_wasm_u32x4_extract_lane -#define v128_u32x4_extract_lane simde_wasm_u32x4_extract_lane -#define v128_i64x2_extract_lane simde_wasm_u64x2_extract_lane -#define v128_u64x2_extract_lane simde_wasm_u64x2_extract_lane -#define v128_f32x4_extract_lane simde_wasm_f32x4_extract_lane -#define v128_f64x2_extract_lane simde_wasm_f64x2_extract_lane -#endif - -static int g_tests_run; -static int g_tests_passed; - -static void run_spec_tests(void); - -static void error(const char* file, int line, const char* format, ...) { - va_list args; - va_start(args, format); - fprintf(stderr, "%s:%d: assertion failed: ", file, line); - vfprintf(stderr, format, args); - va_end(args); -} - -#define ASSERT_EXCEPTION(f) \ - do { \ - g_tests_run++; \ - if (wasm_rt_impl_try() == WASM_RT_TRAP_UNCAUGHT_EXCEPTION) { \ - g_tests_passed++; \ - } else { \ - (void)(f); \ - error(__FILE__, __LINE__, "expected " #f " to throw exception.\n"); \ - } \ - } while (0) - -#define ASSERT_TRAP(f) \ - do { \ - g_tests_run++; \ - if (wasm_rt_impl_try() != 0) { \ - g_tests_passed++; \ - } else { \ - (void)(f); \ - error(__FILE__, __LINE__, "expected " #f " to trap.\n"); \ - } \ - } while (0) - -#define ASSERT_EXHAUSTION(f) \ - do { \ - g_tests_run++; \ - wasm_rt_trap_t code = wasm_rt_impl_try(); \ - switch (code) { \ - case WASM_RT_TRAP_NONE: \ - (void)(f); \ - error(__FILE__, __LINE__, "expected " #f " to trap.\n"); \ - break; \ - case WASM_RT_TRAP_EXHAUSTION: \ - g_tests_passed++; \ - break; \ - default: \ - error(__FILE__, __LINE__, \ - "expected " #f \ - " to trap due to exhaustion, got trap code %d.\n", \ - code); \ - break; \ - } \ - } while (0) - -#define ASSERT_RETURN(f) \ - do { \ - g_tests_run++; \ - int trap_code = wasm_rt_impl_try(); \ - if (trap_code) { \ - error(__FILE__, __LINE__, #f " trapped (%s).\n", \ - wasm_rt_strerror(trap_code)); \ - } else { \ - f; \ - g_tests_passed++; \ - } \ - } while (0) - -#define ASSERT_RETURN_T(type, fmt, f, expected) \ - do { \ - g_tests_run++; \ - int trap_code = wasm_rt_impl_try(); \ - if (trap_code) { \ - error(__FILE__, __LINE__, #f " trapped (%s).\n", \ - wasm_rt_strerror(trap_code)); \ - } else { \ - type actual = f; \ - if (is_equal_##type(actual, expected)) { \ - g_tests_passed++; \ - } else { \ - error(__FILE__, __LINE__, \ - "in " #f ": expected %" fmt ", got %" fmt ".\n", expected, \ - actual); \ - } \ - } \ - } while (0) - -#define ASSERT_RETURN_FUNCREF(f, expected) \ - do { \ - g_tests_run++; \ - int trap_code = wasm_rt_impl_try(); \ - if (trap_code) { \ - error(__FILE__, __LINE__, #f " trapped (%s).\n", \ - wasm_rt_strerror(trap_code)); \ - } else { \ - wasm_rt_funcref_t actual = f; \ - if (is_equal_wasm_rt_funcref_t(actual, expected)) { \ - g_tests_passed++; \ - } else { \ - error(__FILE__, __LINE__, \ - "in " #f ": mismatch between expected and actual funcref"); \ - } \ - } \ - } while (0) - -#define ASSERT_RETURN_EXNREF(f, expected) \ - do { \ - g_tests_run++; \ - int trap_code = wasm_rt_impl_try(); \ - if (trap_code) { \ - error(__FILE__, __LINE__, #f " trapped (%s).\n", \ - wasm_rt_strerror(trap_code)); \ - } else { \ - wasm_rt_exnref_t actual = f; \ - if (is_equal_wasm_rt_exnref_t(actual, expected)) { \ - g_tests_passed++; \ - } else { \ - error(__FILE__, __LINE__, \ - "in " #f ": mismatch between expected and actual exnref"); \ - } \ - } \ - } while (0) - -#define ASSERT_RETURN_NAN_T(type, itype, fmt, f, kind) \ - do { \ - g_tests_run++; \ - int trap_code = wasm_rt_impl_try(); \ - if (trap_code) { \ - error(__FILE__, __LINE__, #f " trapped (%s).\n", \ - wasm_rt_strerror(trap_code)); \ - } else { \ - type actual = f; \ - itype iactual; \ - memcpy(&iactual, &actual, sizeof(iactual)); \ - if (is_##kind##_nan_##type(iactual)) { \ - g_tests_passed++; \ - } else { \ - error(__FILE__, __LINE__, \ - "in " #f ": expected result to be a " #kind " nan, got 0x%" fmt \ - ".\n", \ - iactual); \ - } \ - } \ - } while (0) - -#define MULTI_T_UNPACK_(...) __VA_ARGS__ -#define MULTI_T_UNPACK(arg) MULTI_T_UNPACK_ arg -#define MULTI_i8 "%" PRIu8 " " -#define MULTI_i16 "%" PRIu16 " " -#define MULTI_i32 "%u " -#define MULTI_i64 "%" PRIu64 " " -#define MULTI_f32 "%.9g " -#define MULTI_f64 "%.17g " -#define MULTI_str "%s " -#define ASSERT_RETURN_MULTI_T(type, fmt_expected, fmt_got, f, compare, \ - expected, found) \ - do { \ - g_tests_run++; \ - int trap_code = wasm_rt_impl_try(); \ - if (trap_code) { \ - error(__FILE__, __LINE__, #f " trapped (%s).\n", \ - wasm_rt_strerror(trap_code)); \ - } else { \ - type actual = f; \ - if (compare) { \ - g_tests_passed++; \ - } else { \ - error(__FILE__, __LINE__, \ - "in " #f ": expected <" fmt_expected ">, got <" fmt_got ">.\n", \ - MULTI_T_UNPACK(expected), MULTI_T_UNPACK(found)); \ - } \ - } \ - } while (0) - - -#define ASSERT_RETURN_I32(f, expected) ASSERT_RETURN_T(u32, "u", f, expected) -#define ASSERT_RETURN_I64(f, expected) ASSERT_RETURN_T(u64, PRIu64, f, expected) -#define ASSERT_RETURN_F32(f, expected) ASSERT_RETURN_T(f32, ".9g", f, expected) -#define ASSERT_RETURN_F64(f, expected) ASSERT_RETURN_T(f64, ".17g", f, expected) -#define ASSERT_RETURN_EXTERNREF(f, expected) \ - ASSERT_RETURN_T(wasm_rt_externref_t, "p", f, expected); - -#define ASSERT_RETURN_CANONICAL_NAN_F32(f) \ - ASSERT_RETURN_NAN_T(f32, u32, "08x", f, canonical) -#define ASSERT_RETURN_CANONICAL_NAN_F64(f) \ - ASSERT_RETURN_NAN_T(f64, u64, "016x", f, canonical) -#define ASSERT_RETURN_ARITHMETIC_NAN_F32(f) \ - ASSERT_RETURN_NAN_T(f32, u32, "08x", f, arithmetic) -#define ASSERT_RETURN_ARITHMETIC_NAN_F64(f) \ - ASSERT_RETURN_NAN_T(f64, u64, "016x", f, arithmetic) - -static bool is_equal_u8(u8 x, u8 y) { - return x == y; -} - -static bool is_equal_u16(u16 x, u16 y) { - return x == y; -} - -static bool is_equal_u32(u32 x, u32 y) { - return x == y; -} - -static bool is_equal_u64(u64 x, u64 y) { - return x == y; -} - -#define is_equal_i8 is_equal_u8 -#define is_equal_i16 is_equal_u16 -#define is_equal_i32 is_equal_u32 -#define is_equal_i64 is_equal_u64 - -static bool is_equal_wasm_rt_externref_t(wasm_rt_externref_t x, - wasm_rt_externref_t y) { - return x == y; -} - -static inline bool is_equal_wasm_rt_func_type_t(const wasm_rt_func_type_t a, - const wasm_rt_func_type_t b) { - return (a == b) || (a && b && !memcmp(a, b, 32)); -} - -static bool is_equal_wasm_rt_funcref_t(wasm_rt_funcref_t x, - wasm_rt_funcref_t y) { - return is_equal_wasm_rt_func_type_t(x.func_type, y.func_type) && - (x.func == y.func) && (x.module_instance == y.module_instance); -} - -#ifdef WASM_EXN_MAX_SIZE -static bool is_equal_wasm_rt_exnref_t(wasm_rt_exnref_t x, wasm_rt_exnref_t y) { - return x.tag == y.tag && x.size == y.size && !memcmp(x.data, y.data, x.size); -} -#endif - -wasm_rt_externref_t spectest_make_externref(uintptr_t x) { - return (wasm_rt_externref_t)(x + 1); // externref(0) is not null -} - -static u32 f32_bits(f32 x) { - u32 ux; - memcpy(&ux, &x, sizeof(ux)); - return ux; -} - -static u64 f64_bits(f64 x) { - u64 ux; - memcpy(&ux, &x, sizeof(ux)); - return ux; -} - -static bool is_equal_f32(f32 x, f32 y) { - return f32_bits(x) == f32_bits(y); -} - -static bool is_equal_f64(f64 x, f64 y) { - return f64_bits(x) == f64_bits(y); -} - -static f32 make_nan_f32(u32 x) { - x |= 0x7f800000; - f32 res; - memcpy(&res, &x, sizeof(res)); - return res; -} -)w2c_template" - R"w2c_template( -static f64 make_nan_f64(u64 x) { - x |= 0x7ff0000000000000; - f64 res; - memcpy(&res, &x, sizeof(res)); - return res; -} - -static bool is_canonical_nan_f32(u32 x) { - return (x & 0x7fffffff) == 0x7fc00000; -} - -static bool is_canonical_nan_f64(u64 x) { - return (x & 0x7fffffffffffffff) == 0x7ff8000000000000; -} - -static bool is_arithmetic_nan_f32(u32 x) { - return (x & 0x7fc00000) == 0x7fc00000; -} - -static bool is_arithmetic_nan_f64(u64 x) { - return (x & 0x7ff8000000000000) == 0x7ff8000000000000; -} - -typedef struct w2c_spectest { - wasm_rt_funcref_table_t spectest_table; - wasm_rt_funcref_table_t spectest_table64; - wasm_rt_memory_t spectest_memory; - uint32_t spectest_global_i32; - uint64_t spectest_global_i64; - float spectest_global_f32; - double spectest_global_f64; -} w2c_spectest; - -static w2c_spectest spectest_instance; - -/* - * spectest implementations - */ -void w2c_spectest_print(w2c_spectest* instance) { - printf("spectest.print()\n"); -} - -void w2c_spectest_print_i32(w2c_spectest* instance, uint32_t i) { - printf("spectest.print_i32(%d)\n", i); -} - -void w2c_spectest_print_i64(w2c_spectest* instance, uint64_t i) { - printf("spectest.print_i64(%" PRIu64 ")\n", i); -} - -void w2c_spectest_print_f32(w2c_spectest* instance, float f) { - printf("spectest.print_f32(%g)\n", f); -} - -void w2c_spectest_print_i32_f32(w2c_spectest* instance, uint32_t i, float f) { - printf("spectest.print_i32_f32(%d %g)\n", i, f); -} - -void w2c_spectest_print_f64(w2c_spectest* instance, double d) { - printf("spectest.print_f64(%g)\n", d); -} - -void w2c_spectest_print_f64_f64(w2c_spectest* instance, double d1, double d2) { - printf("spectest.print_f64_f64(%g %g)\n", d1, d2); -} - -wasm_rt_funcref_table_t* w2c_spectest_table(w2c_spectest* instance) { - return &instance->spectest_table; -} - -wasm_rt_funcref_table_t* w2c_spectest_table64(w2c_spectest* instance) { - return &instance->spectest_table64; -} - -wasm_rt_memory_t* w2c_spectest_memory(w2c_spectest* instance) { - return &instance->spectest_memory; -} - -uint32_t* w2c_spectest_global_i32(w2c_spectest* instance) { - return &instance->spectest_global_i32; -} - -uint64_t* w2c_spectest_global_i64(w2c_spectest* instance) { - return &instance->spectest_global_i64; -} - -float* w2c_spectest_global_f32(w2c_spectest* instance) { - return &instance->spectest_global_f32; -} - -double* w2c_spectest_global_f64(w2c_spectest* instance) { - return &instance->spectest_global_f64; -} - -static void init_spectest_module(w2c_spectest* instance) { - instance->spectest_global_i32 = 666; - instance->spectest_global_i64 = 666l; - instance->spectest_global_f32 = 666.6; - instance->spectest_global_f64 = 666.6; - wasm_rt_allocate_memory(&instance->spectest_memory, 1, 2, false, - WASM_DEFAULT_PAGE_SIZE); - wasm_rt_allocate_funcref_table(&instance->spectest_table, 10, 20); - wasm_rt_allocate_funcref_table(&instance->spectest_table64, 10, 20); -} - -// POSIX-only test config where embedder handles signals instead of w2c runtime -#ifdef WASM2C_TEST_EMBEDDER_SIGNAL_HANDLING -#include - -static void posix_signal_handler(int sig, siginfo_t* si, void* unused) { - wasm_rt_trap((si->si_code == SEGV_ACCERR) ? WASM_RT_TRAP_OOB - : WASM_RT_TRAP_EXHAUSTION); -} - -static void posix_install_signal_handler(void) { - /* install altstack */ - stack_t ss; - ss.ss_sp = malloc(SIGSTKSZ); - ss.ss_flags = 0; - ss.ss_size = SIGSTKSZ; - if (sigaltstack(&ss, NULL) != 0) { - perror("sigaltstack failed"); - abort(); - } - - /* install signal handler */ - struct sigaction sa; - memset(&sa, '\0', sizeof(sa)); - sa.sa_flags = SA_SIGINFO | SA_ONSTACK; - sigemptyset(&sa.sa_mask); - sa.sa_sigaction = posix_signal_handler; - if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL) != 0) { - perror("sigaction failed"); - abort(); - } -} - -static void posix_cleanup_signal_handler(void) { - /* remove signal handler */ - struct sigaction sa; - memset(&sa, '\0', sizeof(sa)); - sa.sa_handler = SIG_DFL; - if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL)) { - perror("sigaction failed"); - abort(); - } - - /* disable and free altstack */ - stack_t ss; - ss.ss_flags = SS_DISABLE; - if (sigaltstack(&ss, NULL) != 0) { - perror("sigaltstack failed"); - abort(); - } - free(ss.ss_sp); -} -#endif - -int main(int argc, char** argv) { -#ifdef WASM2C_TEST_EMBEDDER_SIGNAL_HANDLING - posix_install_signal_handler(); -#endif - wasm_rt_init(); - init_spectest_module(&spectest_instance); - run_spec_tests(); - printf("%u/%u tests passed.\n", g_tests_passed, g_tests_run); - wasm_rt_free(); -#ifdef WASM2C_TEST_EMBEDDER_SIGNAL_HANDLING - posix_cleanup_signal_handler(); -#endif - return g_tests_passed != g_tests_run; -} -)w2c_template"; diff --git a/src/tools/wasm2c/wasm-rt/wasm-rt-exceptions-impl.c b/src/tools/wasm2c/wasm-rt/wasm-rt-exceptions-impl.c deleted file mode 100644 index 02fdb1cffb0..00000000000 --- a/src/tools/wasm2c/wasm-rt/wasm-rt-exceptions-impl.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "wasm-rt.h" - -#include "wasm-rt-exceptions.h" - -#include - -#define MAX_EXCEPTION_SIZE 256 - -static WASM_RT_THREAD_LOCAL wasm_rt_tag_t g_active_exception_tag; -static WASM_RT_THREAD_LOCAL uint8_t g_active_exception[MAX_EXCEPTION_SIZE]; -static WASM_RT_THREAD_LOCAL uint32_t g_active_exception_size; - -static WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf* g_unwind_target; - -void wasm_rt_load_exception(const wasm_rt_tag_t tag, - uint32_t size, - const void* values) { - if (size > MAX_EXCEPTION_SIZE) { - wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION); - } - - g_active_exception_tag = tag; - g_active_exception_size = size; - - if (size) { - memcpy(g_active_exception, values, size); - } -} - -WASM_RT_NO_RETURN void wasm_rt_throw(void) { - WASM_RT_LONGJMP(*g_unwind_target, WASM_RT_TRAP_UNCAUGHT_EXCEPTION); -} - -WASM_RT_UNWIND_TARGET* wasm_rt_get_unwind_target(void) { - return g_unwind_target; -} - -void wasm_rt_set_unwind_target(WASM_RT_UNWIND_TARGET* target) { - g_unwind_target = target; -} - -wasm_rt_tag_t wasm_rt_exception_tag(void) { return g_active_exception_tag; } - -uint32_t wasm_rt_exception_size(void) { return g_active_exception_size; } - -void* wasm_rt_exception(void) { return g_active_exception; } - -// Include table operations for exnref -#define WASM_RT_TABLE_OPS_EXNREF -#include "wasm-rt-impl-tableops.inc" -#undef WASM_RT_TABLE_OPS_EXNREF diff --git a/src/tools/wasm2c/wasm-rt/wasm-rt-exceptions.h b/src/tools/wasm2c/wasm-rt/wasm-rt-exceptions.h deleted file mode 100644 index 9e95c196e74..00000000000 --- a/src/tools/wasm2c/wasm-rt/wasm-rt-exceptions.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2018 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef WASM_RT_EXCEPTIONS_H_ -#define WASM_RT_EXCEPTIONS_H_ - -#include "wasm-rt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * A tag is represented as an arbitrary pointer. - */ -typedef const void* wasm_rt_tag_t; - -/** - * Set the active exception to given tag, size, and contents. - */ -void wasm_rt_load_exception(const wasm_rt_tag_t tag, - uint32_t size, - const void* values); - -/** - * Throw the active exception. - */ -WASM_RT_NO_RETURN void wasm_rt_throw(void); - -/** - * The type of an unwind target if an exception is thrown and caught. - */ -#define WASM_RT_UNWIND_TARGET wasm_rt_jmp_buf - -/** - * Get the current unwind target if an exception is thrown. - */ -WASM_RT_UNWIND_TARGET* wasm_rt_get_unwind_target(void); - -/** - * Set the unwind target if an exception is thrown. - */ -void wasm_rt_set_unwind_target(WASM_RT_UNWIND_TARGET* target); - -/** - * Tag of the active exception. - */ -wasm_rt_tag_t wasm_rt_exception_tag(void); - -/** - * Size of the active exception. - */ -uint32_t wasm_rt_exception_size(void); - -/** - * Contents of the active exception. - */ -void* wasm_rt_exception(void); - -/** - * The maximum size of an exception. - */ -#define WASM_EXN_MAX_SIZE 256 - -/** - * An exception instance (the runtime representation of a function). - * These can be stored in tables of type exnref, or used as values. - */ -typedef struct { - /** The exceptions's tag. */ - wasm_rt_tag_t tag; - /** The size of the exception. */ - uint32_t size; - /** - * The actual contents of the exception are stored inline. - */ - char data[WASM_EXN_MAX_SIZE]; -} wasm_rt_exnref_t; - -/** Default (null) value of an exnref */ -#define wasm_rt_exnref_null_value ((wasm_rt_exnref_t){NULL, 0, {0}}) - -/** A Table of type exnref. */ -typedef struct { - /** The table element data, with an element count of `size`. */ - wasm_rt_exnref_t* data; - /** - * The maximum element count of this Table object. If there is no maximum, - * `max_size` is 0xffffffffu (i.e. UINT32_MAX). - */ - uint32_t max_size; - /** The current element count of the table. */ - uint32_t size; -} wasm_rt_exnref_table_t; - -/** - * Initialize an exnref Table object with an element count of `elements` and a - * maximum size of `max_elements`. - * - * ``` - * wasm_rt_exnref_table_t my_table; - * // 5 elements and a maximum of 10 elements. - * wasm_rt_allocate_exnref_table(&my_table, 5, 10); - * ``` - */ -void wasm_rt_allocate_exnref_table(wasm_rt_exnref_table_t*, - uint32_t elements, - uint32_t max_elements); - -/** Free an exnref Table object. */ -void wasm_rt_free_exnref_table(wasm_rt_exnref_table_t*); - -/** - * Grow a Table object by `delta` elements (giving the new elements the value - * `init`), and return the previous element count. If this new element count is - * greater than the maximum element count, the grow fails and 0xffffffffu - * (UINT32_MAX) is returned instead. - */ -uint32_t wasm_rt_grow_exnref_table(wasm_rt_exnref_table_t*, - uint32_t delta, - wasm_rt_exnref_t init); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/tools/wasm2c/wasm-rt/wasm-rt-impl-tableops.inc b/src/tools/wasm2c/wasm-rt/wasm-rt-impl-tableops.inc deleted file mode 100644 index f9e9a8fb089..00000000000 --- a/src/tools/wasm2c/wasm-rt/wasm-rt-impl-tableops.inc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2018 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This file is used as a template to generate code for table operations for -// funcref or externref. For this, the file must be included after defining -// either WASM_RT_TABLE_OPS_FUNCREF or WASM_RT_TABLE_OPS_EXTERNREF - -#if defined(WASM_RT_TABLE_OPS_FUNCREF) + \ - defined(WASM_RT_TABLE_OPS_EXTERNREF) + defined(WASM_RT_TABLE_OPS_EXNREF) > \ - 1 -#error \ - "Expected only one of { WASM_RT_TABLE_OPS_FUNCREF, WASM_RT_TABLE_OPS_EXTERNREF, WASM_RT_TABLE_OPS_EXNREF } to be defined" -#elif defined(WASM_RT_TABLE_OPS_FUNCREF) + \ - defined(WASM_RT_TABLE_OPS_EXTERNREF) + defined(WASM_RT_TABLE_OPS_EXNREF) < \ - 1 -#error \ - "Expected one of { WASM_RT_TABLE_OPS_FUNCREF, WASM_RT_TABLE_OPS_EXTERNREF, WASM_RT_TABLE_OPS_EXNREF } to be defined" -#endif - -#if defined(WASM_RT_TABLE_OPS_FUNCREF) -#define WASM_RT_TABLE_TYPE wasm_rt_funcref_table_t -#define WASM_RT_TABLE_ELEMENT_TYPE wasm_rt_funcref_t -#define WASM_RT_TABLE_APINAME(name) name##_funcref_table -#elif defined(WASM_RT_TABLE_OPS_EXTERNREF) -#define WASM_RT_TABLE_TYPE wasm_rt_externref_table_t -#define WASM_RT_TABLE_ELEMENT_TYPE wasm_rt_externref_t -#define WASM_RT_TABLE_APINAME(name) name##_externref_table -#elif defined(WASM_RT_TABLE_OPS_EXNREF) -#define WASM_RT_TABLE_TYPE wasm_rt_exnref_table_t -#define WASM_RT_TABLE_ELEMENT_TYPE wasm_rt_exnref_t -#define WASM_RT_TABLE_APINAME(name) name##_exnref_table -#endif - -void WASM_RT_TABLE_APINAME(wasm_rt_allocate)(WASM_RT_TABLE_TYPE* table, - uint32_t elements, - uint32_t max_elements) { - table->size = elements; - table->max_size = max_elements; - table->data = calloc(table->size, sizeof(WASM_RT_TABLE_ELEMENT_TYPE)); -} - -void WASM_RT_TABLE_APINAME(wasm_rt_free)(WASM_RT_TABLE_TYPE* table) { - free(table->data); -} - -uint32_t WASM_RT_TABLE_APINAME(wasm_rt_grow)(WASM_RT_TABLE_TYPE* table, - uint32_t delta, - WASM_RT_TABLE_ELEMENT_TYPE init) { - uint32_t old_elems = table->size; - uint64_t new_elems = (uint64_t)table->size + delta; - if (new_elems == 0) { - return 0; - } - if ((new_elems < old_elems) || (new_elems > table->max_size)) { - return (uint32_t)-1; - } - void* new_data = - realloc(table->data, new_elems * sizeof(WASM_RT_TABLE_ELEMENT_TYPE)); - if (!new_data) { - return (uint32_t)-1; - } - table->data = new_data; - table->size = new_elems; - for (uint32_t i = old_elems; i < new_elems; i++) { - table->data[i] = init; - } - return old_elems; -} - -#undef WASM_RT_TABLE_APINAME -#undef WASM_RT_TABLE_ELEMENT_TYPE -#undef WASM_RT_TABLE_TYPE diff --git a/src/tools/wasm2c/wasm-rt/wasm-rt-impl.c b/src/tools/wasm2c/wasm-rt/wasm-rt-impl.c deleted file mode 100644 index 1624ff348d3..00000000000 --- a/src/tools/wasm2c/wasm-rt/wasm-rt-impl.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright 2018 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "wasm-rt-impl.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) -#include -#include -#endif - -#ifdef _WIN32 -#include -#else -#include -#endif - -#ifndef NDEBUG -#define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__); -#else -#define DEBUG_PRINTF(...) -#endif - -#if WASM_RT_INSTALL_SIGNAL_HANDLER -static bool g_signal_handler_installed = false; -#ifdef _WIN32 -static void* g_sig_handler_handle = 0; -#endif -#endif - -#if WASM_RT_USE_SEGUE -bool wasm_rt_fsgsbase_inst_supported = false; -#ifdef __linux__ -#include -#ifdef __GLIBC__ -#include -#endif -#include // For ARCH_SET_GS -#include // For SYS_arch_prctl -#include // For syscall -#ifndef HWCAP2_FSGSBASE -#define HWCAP2_FSGSBASE (1 << 1) -#endif -#elif defined(__FreeBSD__) -#include // For amd64_set_gsbase etc. -#endif -#endif - -#if WASM_RT_SEGUE_FREE_SEGMENT -WASM_RT_THREAD_LOCAL void* wasm_rt_last_segment_val = NULL; -#endif - -#if WASM_RT_STACK_DEPTH_COUNT -WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth; -WASM_RT_THREAD_LOCAL uint32_t wasm_rt_saved_call_stack_depth; -#elif WASM_RT_STACK_EXHAUSTION_HANDLER -static WASM_RT_THREAD_LOCAL void* g_alt_stack = NULL; -#endif - -#ifndef WASM_RT_TRAP_HANDLER -WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf g_wasm_rt_jmp_buf; -#endif - -#ifdef WASM_RT_TRAP_HANDLER -extern void WASM_RT_TRAP_HANDLER(wasm_rt_trap_t code); -#endif - -void wasm_rt_trap(wasm_rt_trap_t code) { - assert(code != WASM_RT_TRAP_NONE); -#if WASM_RT_STACK_DEPTH_COUNT - wasm_rt_call_stack_depth = wasm_rt_saved_call_stack_depth; -#endif - -#ifdef WASM_RT_TRAP_HANDLER - WASM_RT_TRAP_HANDLER(code); - wasm_rt_unreachable(); -#else - WASM_RT_LONGJMP(g_wasm_rt_jmp_buf, code); -#endif -} - -#ifdef _WIN32 - -#if WASM_RT_INSTALL_SIGNAL_HANDLER - -static LONG os_signal_handler(PEXCEPTION_POINTERS info) { - if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { - wasm_rt_trap(WASM_RT_TRAP_OOB); - } else if (info->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { - wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION); - } - return EXCEPTION_CONTINUE_SEARCH; -} - -static void os_install_signal_handler(void) { - g_sig_handler_handle = - AddVectoredExceptionHandler(1 /* CALL_FIRST */, os_signal_handler); -} - -static void os_cleanup_signal_handler(void) { - RemoveVectoredExceptionHandler(g_sig_handler_handle); -} - -#endif - -#else - -#if WASM_RT_INSTALL_SIGNAL_HANDLER -static void os_signal_handler(int sig, siginfo_t* si, void* unused) { - if (si->si_code == SEGV_ACCERR) { - wasm_rt_trap(WASM_RT_TRAP_OOB); - } else { - wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION); - } -} - -static void os_install_signal_handler(void) { - struct sigaction sa; - memset(&sa, '\0', sizeof(sa)); - sa.sa_flags = SA_SIGINFO; -#if WASM_RT_STACK_EXHAUSTION_HANDLER - sa.sa_flags |= SA_ONSTACK; -#endif - sigemptyset(&sa.sa_mask); - sa.sa_sigaction = os_signal_handler; - - /* Install SIGSEGV and SIGBUS handlers, since macOS seems to use SIGBUS. */ - if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL) != 0) { - perror("sigaction failed"); - abort(); - } -} - -static void os_cleanup_signal_handler(void) { - /* Undo what was done in os_install_signal_handler */ - struct sigaction sa; - memset(&sa, '\0', sizeof(sa)); - sa.sa_handler = SIG_DFL; - if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL)) { - perror("sigaction failed"); - abort(); - } -} -#endif - -#if WASM_RT_STACK_EXHAUSTION_HANDLER -static bool os_has_altstack_installed() { - /* check for altstack already in place */ - stack_t ss; - if (sigaltstack(NULL, &ss) != 0) { - perror("os_has_altstack_installed: sigaltstack failed"); - abort(); - } - - return !(ss.ss_flags & SS_DISABLE); -} - -/* These routines set up an altstack to handle SIGSEGV from stack overflow. */ -static void os_allocate_and_install_altstack(void) { - /* verify altstack not already allocated */ - assert(!g_alt_stack && - "wasm-rt error: tried to re-allocate thread-local alternate stack"); - - /* We could check and warn if an altstack is already installed, but some - * sanitizers install their own altstack, so this warning would fire - * spuriously and break the test outputs. */ - - /* allocate altstack */ - g_alt_stack = malloc(SIGSTKSZ); - if (g_alt_stack == NULL) { - perror("malloc failed"); - abort(); - } - - /* install altstack */ - stack_t ss; - ss.ss_sp = g_alt_stack; - ss.ss_flags = 0; - ss.ss_size = SIGSTKSZ; - if (sigaltstack(&ss, NULL) != 0) { - perror("os_allocate_and_install_altstack: sigaltstack failed"); - abort(); - } -} - -static void os_disable_and_deallocate_altstack(void) { - /* in debug build, verify altstack allocated */ - assert(g_alt_stack && - "wasm-rt error: thread-local alternate stack not allocated"); - - /* verify altstack was still in place */ - stack_t ss; - if (sigaltstack(NULL, &ss) != 0) { - perror("os_disable_and_deallocate_altstack: sigaltstack failed"); - abort(); - } - - if ((!g_alt_stack) || (ss.ss_flags & SS_DISABLE) || - (ss.ss_sp != g_alt_stack) || (ss.ss_size != SIGSTKSZ)) { - DEBUG_PRINTF( - "wasm-rt warning: alternate stack was modified unexpectedly\n"); - return; - } - - assert(!(ss.ss_flags & SS_ONSTACK) && - "attempt to deallocate altstack while in use"); - - /* disable and free */ - ss.ss_flags = SS_DISABLE; - if (sigaltstack(&ss, NULL) != 0) { - perror("sigaltstack disable failed"); - abort(); - } - assert(!os_has_altstack_installed()); - free(g_alt_stack); - g_alt_stack = NULL; -} -#endif - -#endif - -#if WASM_RT_USE_SEGUE && defined(__FreeBSD__) -static void -call_cpuid(uint64_t* rax, uint64_t* rbx, uint64_t* rcx, uint64_t* rdx) { - __asm__ volatile( - "cpuid" - : "=a"(*rax), "=b"(*rbx), "=c"(*rcx), "=d"(*rdx) // output operands - : "a"(*rax), "c"(*rcx) // input operands - ); -} -#endif - -void wasm_rt_init(void) { - wasm_rt_init_thread(); -#if WASM_RT_INSTALL_SIGNAL_HANDLER - if (!g_signal_handler_installed) { - g_signal_handler_installed = true; - os_install_signal_handler(); - } -#endif - -#if WASM_RT_USE_SEGUE -#if defined(__linux__) && defined(__GLIBC__) && __GLIBC__ >= 2 && \ - __GLIBC_MINOR__ >= 18 - // Check for support for userspace wrgsbase instructions - unsigned long val = getauxval(AT_HWCAP2); - wasm_rt_fsgsbase_inst_supported = val & HWCAP2_FSGSBASE; -#elif defined(__FreeBSD__) - // FreeBSD enables fsgsbase on the newer kernels if the hardware supports it. - // We just need to check if the hardware supports it by querying the correct - // cpuid leaf. - uint64_t rax, rbx, rcx, rdx; - rax = 0; - call_cpuid(&rax, &rbx, &rcx, &rdx); - - if (rax > 7) { - rax = 7; - rcx = 0; - call_cpuid(&rax, &rbx, &rcx, &rdx); - if (rbx & 0x1) { - wasm_rt_fsgsbase_inst_supported = true; - } - } -#endif -#endif - - assert(wasm_rt_is_initialized()); -} - -bool wasm_rt_is_initialized(void) { -#if WASM_RT_STACK_EXHAUSTION_HANDLER - if (!os_has_altstack_installed()) { - return false; - } -#endif -#if WASM_RT_INSTALL_SIGNAL_HANDLER - return g_signal_handler_installed; -#else - return true; -#endif -} - -void wasm_rt_free(void) { - assert(wasm_rt_is_initialized()); -#if WASM_RT_INSTALL_SIGNAL_HANDLER - os_cleanup_signal_handler(); - g_signal_handler_installed = false; -#endif - wasm_rt_free_thread(); -} - -void wasm_rt_init_thread(void) { -#if WASM_RT_STACK_EXHAUSTION_HANDLER - os_allocate_and_install_altstack(); -#endif -} - -void wasm_rt_free_thread(void) { -#if WASM_RT_STACK_EXHAUSTION_HANDLER - os_disable_and_deallocate_altstack(); -#endif -} - -#if WASM_RT_USE_SEGUE -void wasm_rt_syscall_set_segue_base(void* base) { - int error_code = 0; -#ifdef __linux__ - error_code = syscall(SYS_arch_prctl, ARCH_SET_GS, base); -#elif defined(__FreeBSD__) - error_code = amd64_set_gsbase(base); -#else -#error "Unknown platform" -#endif - if (error_code != 0) { - perror("wasm_rt_syscall_set_segue_base error"); - abort(); - } -} -void* wasm_rt_syscall_get_segue_base() { - void* base; - int error_code = 0; -#ifdef __linux__ - error_code = syscall(SYS_arch_prctl, ARCH_GET_GS, &base); -#elif defined(__FreeBSD__) - error_code = amd64_get_gsbase(&base); -#else -#error "Unknown platform" -#endif - if (error_code != 0) { - perror("wasm_rt_syscall_get_segue_base error"); - abort(); - } - return base; -} -#endif - -// Include table operations for funcref -#define WASM_RT_TABLE_OPS_FUNCREF -#include "wasm-rt-impl-tableops.inc" -#undef WASM_RT_TABLE_OPS_FUNCREF - -// Include table operations for externref -#define WASM_RT_TABLE_OPS_EXTERNREF -#include "wasm-rt-impl-tableops.inc" -#undef WASM_RT_TABLE_OPS_EXTERNREF - -const char* wasm_rt_strerror(wasm_rt_trap_t trap) { - switch (trap) { - case WASM_RT_TRAP_NONE: - return "No error"; - case WASM_RT_TRAP_OOB: -#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS - return "Out-of-bounds access in linear memory or a table, or call stack " - "exhausted"; -#else - return "Out-of-bounds access in linear memory or a table"; - case WASM_RT_TRAP_EXHAUSTION: - return "Call stack exhausted"; -#endif - case WASM_RT_TRAP_INT_OVERFLOW: - return "Integer overflow on divide or truncation"; - case WASM_RT_TRAP_DIV_BY_ZERO: - return "Integer divide by zero"; - case WASM_RT_TRAP_INVALID_CONVERSION: - return "Conversion from NaN to integer"; - case WASM_RT_TRAP_UNREACHABLE: - return "Unreachable instruction executed"; - case WASM_RT_TRAP_CALL_INDIRECT: - return "Invalid call_indirect or return_call_indirect"; - case WASM_RT_TRAP_UNCAUGHT_EXCEPTION: - return "Uncaught exception"; - case WASM_RT_TRAP_UNALIGNED: - return "Unaligned atomic memory access"; - case WASM_RT_TRAP_NULL_REF: - return "Null reference"; - } - return "invalid trap code"; -} diff --git a/src/tools/wasm2c/wasm-rt/wasm-rt-impl.h b/src/tools/wasm2c/wasm-rt/wasm-rt-impl.h deleted file mode 100644 index b70f6a3a5bb..00000000000 --- a/src/tools/wasm2c/wasm-rt/wasm-rt-impl.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2018 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef WASM_RT_IMPL_H_ -#define WASM_RT_IMPL_H_ - -#include "wasm-rt.h" - -#ifdef _WIN32 -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WASM_RT_TRAP_HANDLER -/** A setjmp buffer used for handling traps. */ -extern WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf g_wasm_rt_jmp_buf; -#endif - -#if WASM_RT_STACK_DEPTH_COUNT -/** Saved call stack depth that will be restored in case a trap occurs. */ -extern WASM_RT_THREAD_LOCAL uint32_t wasm_rt_saved_call_stack_depth; -#define WASM_RT_SAVE_STACK_DEPTH() \ - wasm_rt_saved_call_stack_depth = wasm_rt_call_stack_depth -#else -#define WASM_RT_SAVE_STACK_DEPTH() (void)0 -#endif - -/** - * Convenience macro to use before calling a wasm function. On first execution - * it will return `WASM_RT_TRAP_NONE` (i.e. 0). If the function traps, it will - * jump back and return the trap that occurred. - * - * ``` - * wasm_rt_trap_t code = wasm_rt_impl_try(); - * if (code != 0) { - * printf("A trap occurred with code: %d\n", code); - * ... - * } - * - * // Call the potentially-trapping function. - * my_wasm_func(); - * ``` - */ -#define wasm_rt_impl_try() \ - (WASM_RT_SAVE_STACK_DEPTH(), \ - wasm_rt_set_unwind_target(&g_wasm_rt_jmp_buf), \ - WASM_RT_SETJMP(g_wasm_rt_jmp_buf)) - -#ifdef __cplusplus -} -#endif - -#endif /* WASM_RT_IMPL_H_ */ diff --git a/src/tools/wasm2c/wasm-rt/wasm-rt-mem-impl-helper.inc b/src/tools/wasm2c/wasm-rt/wasm-rt-mem-impl-helper.inc deleted file mode 100644 index ffd4f42a077..00000000000 --- a/src/tools/wasm2c/wasm-rt/wasm-rt-mem-impl-helper.inc +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2018 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This file is used as a template to generate code for regular memories or for -// shared memories. For this, the file must be included after defining either -// WASM_RT_MEM_OPS or WASM_RT_MEM_OPS_SHARED. - -#if defined(WASM_RT_MEM_OPS) && defined(WASM_RT_MEM_OPS_SHARED) -#error \ - "Expected only one of { WASM_RT_MEM_OPS, WASM_RT_MEM_OPS_SHARED } to be defined" -#elif !defined(WASM_RT_MEM_OPS) && !defined(WASM_RT_MEM_OPS_SHARED) -#error \ - "Expected one of { WASM_RT_MEM_OPS, WASM_RT_MEM_OPS_SHARED } to be defined" -#endif - -// Shared memory operations are defined only if we have C11 -#if defined(WASM_RT_MEM_OPS) || \ - (defined(WASM_RT_MEM_OPS_SHARED) && defined(WASM_RT_C11_AVAILABLE)) - -#ifdef WASM_RT_MEM_OPS - -// Memory operations on wasm_rt_memory_t -#define MEMORY_TYPE wasm_rt_memory_t -#define MEMORY_API_NAME(name) name -#define MEMORY_CELL_TYPE uint8_t* -#define MEMORY_LOCK_VAR_INIT(name) -#define MEMORY_LOCK_AQUIRE(name) -#define MEMORY_LOCK_RELEASE(name) - -#else - -// Memory operations on wasm_rt_shared_memory_t -#define MEMORY_TYPE wasm_rt_shared_memory_t -#define MEMORY_API_NAME(name) name##_shared -#define MEMORY_CELL_TYPE _Atomic volatile uint8_t* - -#if WASM_RT_USE_CRITICALSECTION -#define MEMORY_LOCK_VAR_INIT(name) WIN_MEMORY_LOCK_VAR_INIT(name) -#define MEMORY_LOCK_AQUIRE(name) WIN_MEMORY_LOCK_AQUIRE(name) -#define MEMORY_LOCK_RELEASE(name) WIN_MEMORY_LOCK_RELEASE(name) -#elif WASM_RT_USE_PTHREADS -#define MEMORY_LOCK_VAR_INIT(name) PTHREAD_MEMORY_LOCK_VAR_INIT(name) -#define MEMORY_LOCK_AQUIRE(name) PTHREAD_MEMORY_LOCK_AQUIRE(name) -#define MEMORY_LOCK_RELEASE(name) PTHREAD_MEMORY_LOCK_RELEASE(name) -#endif - -#endif - -bool MEMORY_API_NAME(wasm_rt_memory_is_default32)(const MEMORY_TYPE* memory) { - return memory->page_size == WASM_DEFAULT_PAGE_SIZE && !memory->is64; -} - -void MEMORY_API_NAME(wasm_rt_allocate_memory)(MEMORY_TYPE* memory, - uint64_t initial_pages, - uint64_t max_pages, - bool is64, - uint32_t page_size) { - uint64_t byte_length = initial_pages * page_size; - memory->size = byte_length; - memory->pages = initial_pages; - memory->max_pages = max_pages; - memory->is64 = is64; - memory->page_size = page_size; - MEMORY_LOCK_VAR_INIT(memory->mem_lock); - -#if WASM_RT_USE_MMAP - if (MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) { - const uint64_t mmap_size = - get_alloc_size_for_mmap_default32(memory->max_pages); - uint8_t* addr = os_mmap(mmap_size); - if (!addr) { - os_print_last_error("os_mmap failed."); - abort(); - } - uint8_t* data_end = addr + mmap_size; -#if !WASM_RT_BIG_ENDIAN - int ret = os_mprotect(addr, byte_length); -#else - int ret = os_mprotect(data_end - byte_length, byte_length); -#endif - if (ret != 0) { - os_print_last_error("os_mprotect failed."); - abort(); - } - memory->data = (MEMORY_CELL_TYPE)addr; - memory->data_end = (MEMORY_CELL_TYPE)data_end; - return; - } -#endif - - memory->data = (MEMORY_CELL_TYPE)calloc(byte_length, 1); - memory->data_end = memory->data + byte_length; -} - -// Returns 0 on success -static int MEMORY_API_NAME(expand_data_allocation)(MEMORY_TYPE* memory, - uint64_t old_size, - uint64_t new_size, - uint64_t delta_size) { -#if WASM_RT_USE_MMAP - if (MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) { -#if !WASM_RT_BIG_ENDIAN - return os_mprotect((void*)(memory->data + old_size), delta_size); -#else - return os_mprotect((void*)(memory->data_end - old_size - delta_size), - delta_size); -#endif - } -#endif - - uint8_t* new_data = realloc((void*)memory->data, new_size); - if (new_data == NULL) { - return -1; - } -#if !WASM_RT_BIG_ENDIAN - memset((void*)(new_data + old_size), 0, delta_size); -#else - memmove((void*)(new_data + new_size - old_size), (void*)new_data, old_size); - memset((void*)new_data, 0, delta_size); -#endif - - memory->data = (MEMORY_CELL_TYPE)new_data; - memory->data_end = memory->data + new_size; - return 0; -} - -static uint64_t MEMORY_API_NAME(grow_memory_impl)(MEMORY_TYPE* memory, - uint64_t delta) { - uint64_t old_pages = memory->pages; - uint64_t new_pages = memory->pages + delta; - if (new_pages == 0) { - return 0; - } - if (new_pages < old_pages || new_pages > memory->max_pages) { - return (uint64_t)-1; - } - uint64_t old_size = old_pages * memory->page_size; - uint64_t new_size = new_pages * memory->page_size; - uint64_t delta_size = delta * memory->page_size; - - int err = MEMORY_API_NAME(expand_data_allocation)( - memory, old_size, new_size, delta_size); - if (err != 0) { - return (uint64_t)-1; - } - - memory->pages = new_pages; - memory->size = new_size; - return old_pages; -} - -uint64_t MEMORY_API_NAME(wasm_rt_grow_memory)(MEMORY_TYPE* memory, - uint64_t delta) { - MEMORY_LOCK_AQUIRE(memory->mem_lock); - uint64_t ret = MEMORY_API_NAME(grow_memory_impl)(memory, delta); - MEMORY_LOCK_RELEASE(memory->mem_lock); -#ifdef WASM_RT_GROW_FAILED_HANDLER - if (ret == (uint64_t)-1) { - WASM_RT_GROW_FAILED_HANDLER(); - } -#endif - return ret; -} - -void MEMORY_API_NAME(wasm_rt_free_memory)(MEMORY_TYPE* memory) { -#if WASM_RT_USE_MMAP - if (MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) { - const uint64_t mmap_size = - get_alloc_size_for_mmap_default32(memory->max_pages); - os_munmap((void*)memory->data, mmap_size); // ignore error - return; - } -#endif - free((void*)memory->data); -} - -#undef MEMORY_LOCK_RELEASE -#undef MEMORY_LOCK_AQUIRE -#undef MEMORY_LOCK_VAR_INIT -#undef MEMORY_CELL_TYPE -#undef MEMORY_API_NAME -#undef MEMORY_TYPE - -#endif diff --git a/src/tools/wasm2c/wasm-rt/wasm-rt-mem-impl.c b/src/tools/wasm2c/wasm-rt/wasm-rt-mem-impl.c deleted file mode 100644 index 5e9addcb8d8..00000000000 --- a/src/tools/wasm2c/wasm-rt/wasm-rt-mem-impl.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2018 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "wasm-rt-impl.h" - -#include -#include - -#ifdef _WIN32 -#include -#else -#include -#endif - -#ifdef WASM_RT_GROW_FAILED_HANDLER -extern void WASM_RT_GROW_FAILED_HANDLER(); -#endif - -#define PTHREAD_MEMORY_LOCK_VAR_INIT(name) \ - if (pthread_mutex_init(&(name), NULL) != 0) { \ - fprintf(stderr, "Lock init failed\n"); \ - abort(); \ - } -#define PTHREAD_MEMORY_LOCK_AQUIRE(name) \ - if (pthread_mutex_lock(&(name)) != 0) { \ - fprintf(stderr, "Lock acquire failed\n"); \ - abort(); \ - } -#define PTHREAD_MEMORY_LOCK_RELEASE(name) \ - if (pthread_mutex_unlock(&(name)) != 0) { \ - fprintf(stderr, "Lock release failed\n"); \ - abort(); \ - } - -#define WIN_MEMORY_LOCK_VAR_INIT(name) InitializeCriticalSection(&(name)) -#define WIN_MEMORY_LOCK_AQUIRE(name) EnterCriticalSection(&(name)) -#define WIN_MEMORY_LOCK_RELEASE(name) LeaveCriticalSection(&(name)) - -#if WASM_RT_USE_MMAP - -#ifdef _WIN32 -static void* os_mmap(size_t size) { - void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); - return ret; -} - -static int os_munmap(void* addr, size_t size) { - // Windows can only unmap the whole mapping - (void)size; /* unused */ - BOOL succeeded = VirtualFree(addr, 0, MEM_RELEASE); - return succeeded ? 0 : -1; -} - -static int os_mprotect(void* addr, size_t size) { - if (size == 0) { - return 0; - } - void* ret = VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE); - if (ret == addr) { - return 0; - } - VirtualFree(addr, 0, MEM_RELEASE); - return -1; -} - -static void os_print_last_error(const char* msg) { - DWORD errorMessageID = GetLastError(); - if (errorMessageID != 0) { - LPSTR messageBuffer = 0; - // The api creates the buffer that holds the message - size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - errorMessageID, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&messageBuffer, - 0, - NULL); - (void)size; - printf("%s. %s\n", msg, messageBuffer); - LocalFree(messageBuffer); - } else { - printf("%s. No error code.\n", msg); - } -} - -#else /* !_WIN32 */ -static void* os_mmap(size_t size) { - int map_prot = PROT_NONE; - int map_flags = MAP_ANONYMOUS | MAP_PRIVATE; - uint8_t* addr = mmap(NULL, size, map_prot, map_flags, -1, 0); - if (addr == MAP_FAILED) { - return NULL; - } - return addr; -} - -static int os_munmap(void* addr, size_t size) { return munmap(addr, size); } - -static int os_mprotect(void* addr, size_t size) { - if (size == 0) { - return 0; - } - return mprotect(addr, size, PROT_READ | PROT_WRITE); -} - -static void os_print_last_error(const char* msg) { perror(msg); } - -#endif /* _WIN32 */ - -static uint64_t get_alloc_size_for_mmap_default32(uint64_t max_pages) { -#if WASM_RT_MEMCHECK_GUARD_PAGES - /* Reserve 8GiB. */ - const uint64_t max_size = 0x200000000ul; - return max_size; -#else - if (max_pages != 0) { - const uint64_t max_size = max_pages * WASM_DEFAULT_PAGE_SIZE; - return max_size; - } - - /* Reserve 4GiB. */ - const uint64_t max_size = 0x100000000ul; - return max_size; -#endif -} - -#endif /* WASM_RT_USE_MMAP */ - -// Include operations for memory -#define WASM_RT_MEM_OPS -#include "wasm-rt-mem-impl-helper.inc" -#undef WASM_RT_MEM_OPS - -// Include operations for shared memory -#define WASM_RT_MEM_OPS_SHARED -#include "wasm-rt-mem-impl-helper.inc" -#undef WASM_RT_MEM_OPS_SHARED - -#undef C11_MEMORY_LOCK_VAR_INIT -#undef C11_MEMORY_LOCK_AQUIRE -#undef C11_MEMORY_LOCK_RELEASE -#undef PTHREAD_MEMORY_LOCK_VAR_INIT -#undef PTHREAD_MEMORY_LOCK_AQUIRE -#undef PTHREAD_MEMORY_LOCK_RELEASE -#undef WIN_MEMORY_LOCK_VAR_INIT -#undef WIN_MEMORY_LOCK_AQUIRE -#undef WIN_MEMORY_LOCK_RELEASE diff --git a/src/tools/wasm2c/wasm-rt/wasm-rt.h b/src/tools/wasm2c/wasm-rt/wasm-rt.h deleted file mode 100644 index 726c5d575a2..00000000000 --- a/src/tools/wasm2c/wasm-rt/wasm-rt.h +++ /dev/null @@ -1,728 +0,0 @@ -/* - * Copyright 2018 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef WASM_RT_H_ -#define WASM_RT_H_ - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 /** Compatibility with non-clang compilers. */ -#endif - -#if __has_builtin(__builtin_expect) -#define UNLIKELY(x) __builtin_expect(!!(x), 0) -#define LIKELY(x) __builtin_expect(!!(x), 1) -#else -#define UNLIKELY(x) (x) -#define LIKELY(x) (x) -#endif - -#if __has_builtin(__builtin_memcpy) -#define wasm_rt_memcpy __builtin_memcpy -#else -#define wasm_rt_memcpy memcpy -#endif - -#if __has_builtin(__builtin_unreachable) -#define wasm_rt_unreachable __builtin_unreachable -#else -#define wasm_rt_unreachable abort -#endif - -#ifdef __STDC_VERSION__ -#if __STDC_VERSION__ >= 201112L -#define WASM_RT_C11_AVAILABLE -#endif -#endif - -/** - * Many devices don't implement the C11 threads.h. We use CriticalSection APIs - * for Windows and pthreads on other platforms where threads are not available. - */ -#ifdef WASM_RT_C11_AVAILABLE - -#if defined(_WIN32) -#include -#define WASM_RT_MUTEX CRITICAL_SECTION -#define WASM_RT_USE_CRITICALSECTION 1 -#else -#include -#define WASM_RT_MUTEX pthread_mutex_t -#define WASM_RT_USE_PTHREADS 1 -#endif - -#endif - -#ifdef WASM_RT_C11_AVAILABLE -#define WASM_RT_THREAD_LOCAL _Thread_local -#elif defined(_MSC_VER) -#define WASM_RT_THREAD_LOCAL __declspec(thread) -#elif (defined(__GNUC__) || defined(__clang__)) && !defined(__APPLE__) -// Disabled on Apple systems due to sporadic test failures. -#define WASM_RT_THREAD_LOCAL __thread -#else -#define WASM_RT_THREAD_LOCAL -#endif - -/** - * If enabled, perform additional sanity checks in the generated wasm2c code and - * wasm2c runtime. This is useful to enable on debug builds. - */ -#ifndef WASM_RT_SANITY_CHECKS -#define WASM_RT_SANITY_CHECKS 0 -#endif - -#ifndef WASM_RT_BIG_ENDIAN -#define WASM_RT_BIG_ENDIAN 0 -#endif - -/** - * Backward compatibility: Convert the previously exposed - * WASM_RT_MEMCHECK_SIGNAL_HANDLER macro to the ALLOCATION and CHECK macros that - * are now used. - */ -#if defined(WASM_RT_MEMCHECK_SIGNAL_HANDLER) - -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER -#define WASM_RT_USE_MMAP 1 -#define WASM_RT_MEMCHECK_GUARD_PAGES 1 -#else -#define WASM_RT_USE_MMAP 0 -#define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 -#endif - -#warning \ - "WASM_RT_MEMCHECK_SIGNAL_HANDLER has been deprecated in favor of WASM_RT_USE_MMAP and WASM_RT_MEMORY_CHECK_* macros" -#endif - -/** - * Specify if we use OR mmap/mprotect (+ Windows equivalents) OR malloc/realloc - * for the Wasm memory allocation and growth. mmap/mprotect guarantees memory - * will grow without being moved, while malloc ensures the virtual memory is - * consumed only as needed, but may relocate the memory to handle memory - * fragmentation. - * - * This defaults to malloc on 32-bit platforms or if memory64 support is needed. - * It defaults to mmap on 64-bit platforms assuming memory64 support is not - * needed (so we can use the guard based range checks below). - */ -#ifndef WASM_RT_USE_MMAP -#if UINTPTR_MAX > 0xffffffff -#define WASM_RT_USE_MMAP 1 -#else -#define WASM_RT_USE_MMAP 0 -#endif -#endif - -/** - * Set the range checking strategy for Wasm memories. - * - * GUARD_PAGES: memory accesses rely on unmapped pages/guard pages to trap - * out-of-bound accesses. - * - * BOUNDS_CHECK: memory accesses are checked with explicit bounds checks. - * - * This defaults to GUARD_PAGES as this is the fastest option, iff the - * requirements of GUARD_PAGES --- 64-bit platforms, MMAP allocation strategy, - * no 64-bit memories --- are met. This falls back to BOUNDS otherwise. - */ - -/** Check if Guard checks are supported */ -#if UINTPTR_MAX > 0xffffffff && WASM_RT_USE_MMAP -#define WASM_RT_GUARD_PAGES_SUPPORTED 1 -#else -#define WASM_RT_GUARD_PAGES_SUPPORTED 0 -#endif - -/** Specify defaults for memory checks if unspecified */ -#if !defined(WASM_RT_MEMCHECK_GUARD_PAGES) && \ - !defined(WASM_RT_MEMCHECK_BOUNDS_CHECK) -#if WASM_RT_GUARD_PAGES_SUPPORTED -#define WASM_RT_MEMCHECK_GUARD_PAGES 1 -#else -#define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 -#endif -#endif - -/** Ensure the macros are defined */ -#ifndef WASM_RT_MEMCHECK_GUARD_PAGES -#define WASM_RT_MEMCHECK_GUARD_PAGES 0 -#endif -#ifndef WASM_RT_MEMCHECK_BOUNDS_CHECK -#define WASM_RT_MEMCHECK_BOUNDS_CHECK 0 -#endif - -/** Sanity check the use of guard pages */ -#if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_GUARD_PAGES_SUPPORTED -#error \ - "WASM_RT_MEMCHECK_GUARD_PAGES not supported on this platform/configuration" -#endif - -#if WASM_RT_MEMCHECK_GUARD_PAGES && WASM_RT_MEMCHECK_BOUNDS_CHECK -#error \ - "Cannot use both WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" - -#elif !WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_MEMCHECK_BOUNDS_CHECK -#error \ - "Must choose at least one from WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" -#endif - -/** - * Some configurations above require the Wasm runtime to install a signal - * handler. However, this can be explicitly disallowed by the host using - * WASM_RT_SKIP_SIGNAL_RECOVERY. In this case, when the wasm code encounters an - * OOB access, it may either trap or abort. - */ -#ifndef WASM_RT_SKIP_SIGNAL_RECOVERY -#define WASM_RT_SKIP_SIGNAL_RECOVERY 0 -#endif - -#if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_SKIP_SIGNAL_RECOVERY -#define WASM_RT_INSTALL_SIGNAL_HANDLER 1 -#else -#define WASM_RT_INSTALL_SIGNAL_HANDLER 0 -#endif - -/** - * This macro, if defined to 1 (i.e., allows the "segue" optimization), allows - * Wasm2c to use segment registers to speedup access to the linear heap. Note - * that even if allowed in this way, the segment registers would only be used if - * Wasm2c output is compiled for a suitable architecture and OS and the produces - * C file is compiled by supported compilers. The extact restrictions are listed - * in detail in src/template/wasm2c.declarations.c - */ -#ifndef WASM_RT_ALLOW_SEGUE -#define WASM_RT_ALLOW_SEGUE 0 -#endif - -/** - * The segue optimization restores x86 segments to their old values when exiting - * wasm2c code. If WASM_RT_SEGUE_FREE_SEGMENT is defined, wasm2c assumes it has - * exclusive use of the segment and optimizes performance in two ways. First, it - * does not restore the "old" value of the segment during exits. Second, wasm2c - * only sets the segment register if the value has changed since the last time - * it was set. - */ -#ifndef WASM_RT_SEGUE_FREE_SEGMENT -#define WASM_RT_SEGUE_FREE_SEGMENT 0 -#endif - -#ifndef WASM_RT_USE_SEGUE -// Memory functions can use the segue optimization if allowed. The segue -// optimization uses x86 segments to point to a linear memory. We use this -// optimization when: -// -// (1) Segue is allowed using WASM_RT_ALLOW_SEGUE -// (2) on x86_64 without WASM_RT_BIG_ENDIAN enabled -// (3) the compiler supports: intrinsics for (rd|wr)gsbase, "address namespaces" -// for accessing pointers, and supports memcpy on pointers with custom -// "address namespaces". GCC does not support the memcpy requirement, so -// this leaves only clang (version 9 or later) for now. -// (4) The OS provides a way to query if (rd|wr)gsbase is allowed by the kernel -// or the implementation has to use a syscall for this. -// (5) The OS doesn't replace the segment register on context switch which -// eliminates windows for now -// -// While more OS can be supported in the future, we only support linux for now -#if WASM_RT_ALLOW_SEGUE && !WASM_RT_BIG_ENDIAN && \ - (defined(__x86_64__) || defined(_M_X64)) && __clang__ && \ - (__clang_major__ >= 9) && __has_builtin(__builtin_ia32_wrgsbase64) && \ - !defined(_WIN32) && !defined(__ANDROID__) && \ - (defined(__linux__) || defined(__FreeBSD__)) -#define WASM_RT_USE_SEGUE 1 -#else -#define WASM_RT_USE_SEGUE 0 -#endif -#endif - -/** - * This macro, if defined, allows the embedder to disable all stack exhaustion - * checks. This a non conformant configuration, i.e., this does not respect - * Wasm's specification, and may compromise security. Use with caution. - */ -#ifndef WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION -#define WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION 0 -#endif - -/** - * We need to detect and trap stack overflows. If we use a signal handler on - * POSIX systems, this can detect call stack overflows. On windows, or platforms - * without a signal handler, we use stack depth counting. The s390x big endian - * platform additionally seems to have issues with stack guard pages, so we play - * it safe and use stack counting on big endian platforms. - */ -#if !defined(WASM_RT_STACK_DEPTH_COUNT) && \ - !defined(WASM_RT_STACK_EXHAUSTION_HANDLER) && \ - !WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION - -#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) && !WASM_RT_BIG_ENDIAN -#define WASM_RT_STACK_EXHAUSTION_HANDLER 1 -#else -#define WASM_RT_STACK_DEPTH_COUNT 1 -#endif - -#endif - -/** Ensure the stack macros are defined */ -#ifndef WASM_RT_STACK_DEPTH_COUNT -#define WASM_RT_STACK_DEPTH_COUNT 0 -#endif -#ifndef WASM_RT_STACK_EXHAUSTION_HANDLER -#define WASM_RT_STACK_EXHAUSTION_HANDLER 0 -#endif - -#if WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION - -#if (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) != 0 -#error \ - "Cannot specify WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION along with WASM_RT_STACK_EXHAUSTION_HANDLER or WASM_RT_STACK_DEPTH_COUNT" -#endif - -#else - -#if (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) > 1 -#error \ - "Cannot specify multiple options from WASM_RT_STACK_EXHAUSTION_HANDLER , WASM_RT_STACK_DEPTH_COUNT" -#elif (WASM_RT_STACK_EXHAUSTION_HANDLER + WASM_RT_STACK_DEPTH_COUNT) == 0 -#error \ - "Must specify one of WASM_RT_STACK_EXHAUSTION_HANDLER , WASM_RT_STACK_DEPTH_COUNT" -#endif - -#endif - -#if WASM_RT_STACK_EXHAUSTION_HANDLER && !WASM_RT_INSTALL_SIGNAL_HANDLER -#error \ - "WASM_RT_STACK_EXHAUSTION_HANDLER can only be used if WASM_RT_INSTALL_SIGNAL_HANDLER is enabled" -#endif - -#if WASM_RT_STACK_DEPTH_COUNT -/** - * When the signal handler cannot be used to detect stack overflows, stack depth - * is limited explicitly. The maximum stack depth before trapping can be - * configured by defining this symbol before including wasm-rt when building the - * generated c files, for example: - * - * ``` - * cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o - * ``` - */ -#ifndef WASM_RT_MAX_CALL_STACK_DEPTH -#define WASM_RT_MAX_CALL_STACK_DEPTH 500 -#endif - -/** Current call stack depth. */ -extern WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth; - -#endif - -#if WASM_RT_USE_SEGUE -/** - * The segue optimization uses x86 segments to point to a linear memory. If - * used, the runtime must query whether it can use the fast userspace wrgsbase - * instructions or whether it must invoke syscalls to set the segment base, - * depending on the supported CPU features. The result of this query is saved in - * this variable. - */ -extern bool wasm_rt_fsgsbase_inst_supported; -/** - * If fast userspace wrgsbase instructions don't exist, the runtime most provide - * a function that invokes the OS' underlying syscall to set the segment base. - */ -void wasm_rt_syscall_set_segue_base(void* base); -/** - * If fast userspace rdgsbase instructions don't exist, the runtime most provide - * a function that invokes the OS' underlying syscall to get the segment base. - */ -void* wasm_rt_syscall_get_segue_base(); -/** - * If WASM_RT_SEGUE_FREE_SEGMENT is defined, we must only set the segment - * register if it was changed since the last time it was set. The last value set - * on the segment register is stored in this variable. - */ -#if WASM_RT_SEGUE_FREE_SEGMENT -extern WASM_RT_THREAD_LOCAL void* wasm_rt_last_segment_val; -#endif -#endif - -#if defined(_MSC_VER) -#define WASM_RT_NO_RETURN __declspec(noreturn) -#else -#define WASM_RT_NO_RETURN __attribute__((noreturn)) -#endif - -#if defined(__APPLE__) && WASM_RT_STACK_EXHAUSTION_HANDLER -#define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 1 -#else -#define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 0 -#endif - -/** Reason a trap occurred. Provide this to `wasm_rt_trap`. */ -typedef enum { - WASM_RT_TRAP_NONE, /** No error. */ - WASM_RT_TRAP_OOB, /** Out-of-bounds access in linear memory or a table. */ - WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */ - WASM_RT_TRAP_DIV_BY_ZERO, /** Integer divide by zero. */ - WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */ - WASM_RT_TRAP_UNREACHABLE, /** Unreachable instruction executed. */ - WASM_RT_TRAP_CALL_INDIRECT, /** Invalid call_indirect, for any reason. */ - WASM_RT_TRAP_NULL_REF, /** Null reference. */ - WASM_RT_TRAP_UNCAUGHT_EXCEPTION, /** Exception thrown and not caught. */ - WASM_RT_TRAP_UNALIGNED, /** Unaligned atomic instruction executed. */ -#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS - WASM_RT_TRAP_EXHAUSTION = WASM_RT_TRAP_OOB, -#else - WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */ -#endif -} wasm_rt_trap_t; - -/** Value types. Used to define function signatures. */ -typedef enum { - WASM_RT_I32, - WASM_RT_I64, - WASM_RT_F32, - WASM_RT_F64, - WASM_RT_V128, - WASM_RT_FUNCREF, - WASM_RT_EXTERNREF, - WASM_RT_EXNREF, -} wasm_rt_type_t; - -/** - * A generic function pointer type, both for Wasm functions (`code`) - * and host functions (`hostcode`). All function pointers are stored - * in this canonical form, but must be cast to their proper signature - * to call. - */ -typedef void (*wasm_rt_function_ptr_t)(void); - -/** - * A pointer to a "tail-callee" function, called by a tail-call - * trampoline or by another tail-callee function. (The definition uses a - * single-member struct to allow a recursive definition.) - */ -typedef struct wasm_rt_tailcallee_t { - void (*fn)(void** instance_ptr, - void* tail_call_stack, - struct wasm_rt_tailcallee_t* next); -} wasm_rt_tailcallee_t; - -/** - * The type of a function (an arbitrary number of param and result types). - * This is represented as an opaque 256-bit ID. - */ -typedef const char* wasm_rt_func_type_t; - -/** - * A function instance (the runtime representation of a function). - * These can be stored in tables of type funcref, or used as values. - */ -typedef struct { - /** The function's type. */ - wasm_rt_func_type_t func_type; - /** - * The function. The embedder must know the actual C signature of the function - * and cast to it before calling. - */ - wasm_rt_function_ptr_t func; - /** An alternate version of the function to be used when tail-called. */ - wasm_rt_tailcallee_t func_tailcallee; - /** - * A function instance is a closure of the function over an instance - * of the originating module. The module_instance element will be passed into - * the function at runtime. - */ - void* module_instance; -} wasm_rt_funcref_t; - -/** Default (null) value of a funcref */ -#define wasm_rt_funcref_null_value \ - ((wasm_rt_funcref_t){NULL, NULL, {NULL}, NULL}) - -/** The type of an external reference (opaque to WebAssembly). */ -typedef void* wasm_rt_externref_t; - -/** Default (null) value of an externref */ -#define wasm_rt_externref_null_value ((wasm_rt_externref_t){NULL}) - -/** A Memory object. */ -typedef struct { - /** The linear memory data, with a byte length of `size`. */ - uint8_t* data; - /** The location after the the reserved space for the linear memory data. */ - uint8_t* data_end; - /** The page size for this Memory object - (always 64 KiB without the custom-page-sizes feature) */ - uint32_t page_size; - /** The current page count for this Memory object. */ - uint64_t pages; - /** The maximum page count for this Memory object. */ - uint64_t max_pages; - /** The current size of the linear memory, in bytes. */ - uint64_t size; - /** Is this memory indexed by u64 (as opposed to default u32) */ - bool is64; -} wasm_rt_memory_t; - -#ifdef WASM_RT_C11_AVAILABLE -/** A shared Memory object. */ -typedef struct { - /** - * The linear memory data, with a byte length of `size`. The memory is marked - * atomic as it is shared and may have to be accessed with different memory - * orders --- sequential when being accessed atomically, relaxed otherwise. - * Unfortunately, the C standard does not state what happens if there are - * overlaps in two memory accesses which have a memory order, e.g., an - * atomic32 being read from the same location an atomic64 is read. One way to - * prevent optimizations from assuming non-overlapping behavior as typically - * done in C is to mark the memory as volatile. Thus the memory is atomic and - * volatile. - */ - _Atomic volatile uint8_t* data; - /** The location one byte after the reserved space for the linear memory data. - * This includes any reserved pages that are not yet allocated. */ - _Atomic volatile uint8_t* data_end; - /** The page size for this Memory object - (always 64 KiB without the custom-page-sizes feature) */ - uint32_t page_size; - /** The current page count for this Memory object. */ - uint64_t pages; - /* The maximum page count for this Memory object. */ - uint64_t max_pages; - /** The current size of the linear memory, in bytes. */ - uint64_t size; - /** Is this memory indexed by u64 (as opposed to default u32) */ - bool is64; - /** Lock used to ensure operations such as memory grow are threadsafe */ - WASM_RT_MUTEX mem_lock; -} wasm_rt_shared_memory_t; -#endif - -/** A Table of type funcref. */ -typedef struct { - /** The table element data, with an element count of `size`. */ - wasm_rt_funcref_t* data; - /** - * The maximum element count of this Table object. If there is no maximum, - * `max_size` is 0xffffffffu (i.e. UINT32_MAX). - */ - uint32_t max_size; - /** The current element count of the table. */ - uint32_t size; -} wasm_rt_funcref_table_t; - -/** A Table of type externref. */ -typedef struct { - /** The table element data, with an element count of `size`. */ - wasm_rt_externref_t* data; - /** - * The maximum element count of this Table object. If there is no maximum, - * `max_size` is 0xffffffffu (i.e. UINT32_MAX). - */ - uint32_t max_size; - /** The current element count of the table. */ - uint32_t size; -} wasm_rt_externref_table_t; - -/** Initialize the runtime. */ -void wasm_rt_init(void); - -/** Is the runtime initialized? */ -bool wasm_rt_is_initialized(void); - -/** Free the runtime's state. */ -void wasm_rt_free(void); - -/* - * Initialize the multithreaded runtime for a given thread. Must be - * called by each thread (other than the one that called wasm_rt_init) - * before initializing a Wasm module or calling an exported - * function. - */ -void wasm_rt_init_thread(void); - -/* - * Free the individual thread's state. - */ -void wasm_rt_free_thread(void); - -/** A hardened jmp_buf that allows checking for initialization before use */ -typedef struct { - /** Is the jmp buf intialized? */ - bool initialized; - /** jmp_buf contents */ - jmp_buf buffer; -} wasm_rt_jmp_buf; - -#ifndef _WIN32 -#define WASM_RT_SETJMP_TRAP_SETBUF(buf) sigsetjmp(buf, 1) - -/** - * On macOS XNU, there is a bug where nested `sigsetjmp` and `siglongjmp` - * across threads that have an allocated alternate signal stack (`SS_ONSTACK`) - * will erroneously cause the kernel to preserve the `SS_ONSTACK` flag in the - * thread state - * - * See: https://github.com/WebAssembly/wabt/issues/2654 - * See: https://github.com/golang/go/issues/44501 - */ -#define WASM_RT_SETJMP_EXN_SETBUF(buf) sigsetjmp(buf, 0) -#else -#define WASM_RT_SETJMP_TRAP_SETBUF(buf) setjmp(buf) -#define WASM_RT_SETJMP_EXN_SETBUF(buf) setjmp(buf) -#endif - -#define WASM_RT_SETJMP(buf) \ - ((buf).initialized = true, WASM_RT_SETJMP_TRAP_SETBUF((buf).buffer)) -#define WASM_RT_SETJMP_EXN(buf) \ - ((buf).initialized = true, WASM_RT_SETJMP_EXN_SETBUF((buf).buffer)) - -#ifndef _WIN32 -#define WASM_RT_LONGJMP_UNCHECKED(buf, val) siglongjmp(buf, val) -#else -#define WASM_RT_LONGJMP_UNCHECKED(buf, val) longjmp(buf, val) -#endif - -#define WASM_RT_LONGJMP(buf, val) \ - /** Abort on failure as this may be called in the trap handler */ \ - if (!((buf).initialized)) \ - abort(); \ - (buf).initialized = false; \ - WASM_RT_LONGJMP_UNCHECKED((buf).buffer, val) - -/** - * Stop execution immediately and jump back to the call to `wasm_rt_impl_try`. - * The result of `wasm_rt_impl_try` will be the provided trap reason. - * - * This is typically called by the generated code, and not the embedder. - */ -WASM_RT_NO_RETURN void wasm_rt_trap(wasm_rt_trap_t); - -/** Return a human readable error string based on a trap type. */ -const char* wasm_rt_strerror(wasm_rt_trap_t trap); - -#define wasm_rt_try(target) WASM_RT_SETJMP_EXN(target) - -/** WebAssembly's default page size (64 KiB) */ -#define WASM_DEFAULT_PAGE_SIZE 65536 - -/** - * Initialize a Memory object with an initial page size of `initial_pages` and - * a maximum page size of `max_pages`, indexed with an i32 or i64. - * - * ``` - * wasm_rt_memory_t my_memory; - * // 1 initial page (65536 bytes), and a maximum of 2 pages, - * // indexed with an i32 - * wasm_rt_allocate_memory(&my_memory, 1, 2, false, WASM_DEFAULT_PAGE_SIZE); - * ``` - */ -void wasm_rt_allocate_memory(wasm_rt_memory_t*, - uint64_t initial_pages, - uint64_t max_pages, - bool is64, - uint32_t page_size); - -/** - * Grow a Memory object by `pages`, and return the previous page count. If - * this new page count is greater than the maximum page count, the grow fails - * and 0xffffffffu (UINT32_MAX) is returned instead. - * - * ``` - * wasm_rt_memory_t my_memory; - * ... - * // Grow memory by 10 pages. - * uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10); - * if (old_page_size == UINT32_MAX) { - * // Failed to grow memory. - * } - * ``` - */ -uint64_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint64_t pages); - -/** Free a Memory object. */ -void wasm_rt_free_memory(wasm_rt_memory_t*); - -#ifdef WASM_RT_C11_AVAILABLE -/** Shared memory version of wasm_rt_allocate_memory */ -void wasm_rt_allocate_memory_shared(wasm_rt_shared_memory_t*, - uint64_t initial_pages, - uint64_t max_pages, - bool is64, - uint32_t page_size); - -/** Shared memory version of wasm_rt_grow_memory */ -uint64_t wasm_rt_grow_memory_shared(wasm_rt_shared_memory_t*, uint64_t pages); - -/** Shared memory version of wasm_rt_free_memory */ -void wasm_rt_free_memory_shared(wasm_rt_shared_memory_t*); -#endif - -/** - * Initialize a funcref Table object with an element count of `elements` and a - * maximum size of `max_elements`. - * - * ``` - * wasm_rt_funcref_table_t my_table; - * // 5 elements and a maximum of 10 elements. - * wasm_rt_allocate_funcref_table(&my_table, 5, 10); - * ``` - */ -void wasm_rt_allocate_funcref_table(wasm_rt_funcref_table_t*, - uint32_t elements, - uint32_t max_elements); - -/** Free a funcref Table object. */ -void wasm_rt_free_funcref_table(wasm_rt_funcref_table_t*); - -/** - * Initialize an externref Table object with an element count - * of `elements` and a maximum size of `max_elements`. - * Usage as per wasm_rt_allocate_funcref_table. - */ -void wasm_rt_allocate_externref_table(wasm_rt_externref_table_t*, - uint32_t elements, - uint32_t max_elements); - -/** Free an externref Table object. */ -void wasm_rt_free_externref_table(wasm_rt_externref_table_t*); - -/** - * Grow a Table object by `delta` elements (giving the new elements the value - * `init`), and return the previous element count. If this new element count is - * greater than the maximum element count, the grow fails and 0xffffffffu - * (UINT32_MAX) is returned instead. - */ -uint32_t wasm_rt_grow_funcref_table(wasm_rt_funcref_table_t*, - uint32_t delta, - wasm_rt_funcref_t init); -uint32_t wasm_rt_grow_externref_table(wasm_rt_externref_table_t*, - uint32_t delta, - wasm_rt_externref_t init); - -#ifdef __cplusplus -} -#endif - -#endif /* WASM_RT_H_ */ diff --git a/src/tools/wasm2c/wasm2c-builder.cpp b/src/tools/wasm2c/wasm2c-builder.cpp deleted file mode 100644 index 9b6b2180bc5..00000000000 --- a/src/tools/wasm2c/wasm2c-builder.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2026 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "tools/wasm2c/c-printer.h" -#include "tools/wasm2c/wasm2c-builder.h" -#include "wasm.h" - -// code to be inserted into the generated output -extern const char* HeaderTop; -extern const char* HeaderBottom; -extern const char* SourceIncludes; -extern const char* SourceDeclarations; - -namespace wasm { - -namespace { - -std::string mangleName(const std::string& name) { - if (name.empty()) { - return ""; - } - std::string result; - bool isFirst = true; - for (char c : name) { - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9')) { - result += c; - isFirst = false; - } else if (c == '_') { - if (isFirst) { - result += "0x5F"; - isFirst = false; - } else { - result += '_'; - } - } else { - char buf[8]; - snprintf(buf, sizeof(buf), "0x%02X", (unsigned char)c); - result += buf; - isFirst = false; - } - } - return result; -} - -} // anonymous namespace - -void Wasm2CBuilder::processWasm(Module* wasm, - std::ostream& cOut, - std::ostream& hOut) { - this->module = wasm; - std::string moduleName = - flags.moduleName.empty() ? "test" : mangleName(flags.moduleName); - std::string guardName = "WASM_H_GENERATED_" + moduleName; - std::transform( - guardName.begin(), guardName.end(), guardName.begin(), ::toupper); - - CPrinter h(hOut); - CPrinter c(cOut); - - // Header file prefix - h << "/* Automatically generated by wasm2c */" << endl; - h << "#ifndef " << guardName << endl; - h << "#define " << guardName << endl << endl; - h << "#include \"wasm-rt.h\"" << endl << endl; - h << HeaderTop << endl; - - // Source file prefix - c << "/* Automatically generated by wasm2c */" << endl; - c << SourceIncludes << endl; - if (!flags.headerName.empty()) { - c << "#include \"" << flags.headerName << "\"" << endl; - } else { - c << "#include \"wasm.h\"" << endl; - } - c << SourceDeclarations << endl; - - // Structure context definition - h << "typedef struct w2c_" << moduleName << " {" << endl; - h.indent(); - h << "char dummy_member;" << endl; - h.outdent(); - h << "} w2c_" << moduleName << ";" << endl << endl; - - // Lifecycle signatures in header - h << "void wasm2c_" << moduleName << "_instantiate(w2c_" << moduleName << "*"; - h << ");" << endl; - h << "void wasm2c_" << moduleName << "_free(w2c_" << moduleName << "*);" - << endl; - h << "wasm_rt_func_type_t wasm2c_" << moduleName - << "_get_func_type(uint32_t param_count, uint32_t result_count, ...);" - << endl; - - // Instantiate hooks - c << "void wasm2c_" << moduleName << "_instantiate(w2c_" << moduleName - << "* instance"; - c << ") {" << endl; - c.indent(); - c << "assert(wasm_rt_is_initialized());" << endl; - c.outdent(); - c << "}" << endl << endl; - - // Free hooks - c << "void wasm2c_" << moduleName << "_free(w2c_" << moduleName - << "* instance) {" << endl; - c << "}" << endl << endl; - - // Signature match ladders - c << "wasm_rt_func_type_t wasm2c_" << moduleName - << "_get_func_type(uint32_t param_count, uint32_t result_count, ...) {" - << endl; - c.indent(); - c << "va_list args;" << endl << endl; - - c << "return NULL;" << endl; - c.outdent(); - c << "}" << endl << endl; - - // Header file suffix - h << endl; - h << HeaderBottom << endl; - h << "#endif /* " << guardName << " */" << endl; -} - -} // namespace wasm diff --git a/src/tools/wasm2c/wasm2c-builder.h b/src/tools/wasm2c/wasm2c-builder.h deleted file mode 100644 index 8f90466630c..00000000000 --- a/src/tools/wasm2c/wasm2c-builder.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2026 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef wasm_tools_wasm2c_wasm2c_builder_h -#define wasm_tools_wasm2c_wasm2c_builder_h - -#include -#include - -#include "wasm.h" - -namespace wasm { - -class Wasm2CBuilder { -public: - struct Flags { - bool debug = false; - std::string moduleName = ""; - std::string headerName = ""; - }; - - Wasm2CBuilder(Flags f) : flags(f) {} - - void processWasm(Module* wasm, std::ostream& cOut, std::ostream& hOut); - -private: - Flags flags; - Module* module = nullptr; -}; - -} // namespace wasm - -#endif // wasm_tools_wasm2c_wasm2c_builder_h diff --git a/src/tools/wasm2c/wasm2c.cpp b/src/tools/wasm2c/wasm2c.cpp deleted file mode 100644 index ba5e5c70d7d..00000000000 --- a/src/tools/wasm2c/wasm2c.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2026 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// wasm2c console tool -// - -#include "parser/wat-parser.h" -#include "parsing.h" -#include "support/colors.h" -#include "support/command-line.h" -#include "support/file.h" -#include "support/path.h" -#include "tools/tool-options.h" -#include "tools/wasm2c/assertion-emitter.h" -#include "tools/wasm2c/wasm2c-builder.h" -#include "wasm-io.h" - -using namespace wasm; - -struct Wasm2COptions : public ToolOptions { - constexpr static const char* Wasm2COptionsCategory = "wasm2c options"; - - std::string output; - bool asserts = false; - std::string prefix; - std::string infile; - - Wasm2COptions() - : ToolOptions( - "wasm2c", - "Transform .wasm/.wat files to standard C source and headers") { - (*this) - .add("--output", - "-o", - "Output file path (derives .h by changing extension, writes both to " - "stdout if not specified)", - Wasm2COptionsCategory, - Arguments::One, - [this](Options*, const std::string& argument) { - output = argument; - Colors::setEnabled(false); - }) - .add("--allow-asserts", - "", - "Allow compilation of .wast testing asserts", - Wasm2COptionsCategory, - Arguments::Zero, - [this](Options*, const std::string&) { asserts = true; }) - .add("--prefix", - "-n", - "Set the name prefix for the generated C symbols", - Wasm2COptionsCategory, - Arguments::One, - [this](Options*, const std::string& argument) { prefix = argument; }) - .add_positional( - "INFILE", - Arguments::One, - [this](Options*, const std::string& argument) { infile = argument; }); - } -}; - -int main(int argc, const char* argv[]) { - Wasm2COptions options; - options.parse(argc, argv); - - Wasm2CBuilder::Flags flags; - flags.moduleName = options.prefix; - - if (options.asserts) { - // When `--allow-asserts` is passed (i.e. when running spec tests), we need - // to parse the extra s-expressions that come at the end of the `*.wast` - // file after the module is defined. Therefore, in this case, we can't use - // ModuleReader. - - auto input = read_file(options.infile, Flags::Text); - - auto script = WATParser::parseScript(input); - if (auto* err = script.getErr()) { - Fatal() << err->msg; - } - - Output cOut(options.output, Flags::Text); - AssertionEmitter emitter(*script, flags); - emitter.emit(cOut.getStream(), options.output); - } else { - Module wasm; - options.applyOptionsBeforeParse(wasm); - try { - ModuleReader reader; - reader.read(options.infile, wasm, ""); - } catch (ParseException& p) { - p.dump(std::cerr); - Fatal() << "error in parsing input"; - } - options.applyOptionsAfterParse(wasm); - - if (!options.output.empty()) { - // Derive output header file path (.h instead of .c) - std::string outputHPath = options.output; - size_t lastDot = outputHPath.find_last_of('.'); - if (lastDot != std::string::npos) { - outputHPath.replace(lastDot, std::string::npos, ".h"); - } else { - outputHPath += ".h"; - } - flags.headerName = Path::getBaseName(outputHPath); - - Output cOut(options.output, Flags::Text); - Output hOut(outputHPath, Flags::Text); - Wasm2CBuilder builder(flags); - builder.processWasm(&wasm, cOut.getStream(), hOut.getStream()); - } else { - // Write both to stdout sequentially - std::cout << "/* === HEADER FILE === */\n"; - std::stringstream hStream; - std::stringstream cStream; - - flags.headerName = "wasm.h"; // Default fallback - Wasm2CBuilder builder(flags); - builder.processWasm(&wasm, cStream, hStream); - - std::cout << hStream.str(); - std::cout << "\n/* === SOURCE FILE === */\n"; - std::cout << cStream.str(); - } - } - - flush_and_quick_exit(0); -} diff --git a/test/lit/wasm2c/minimal.wast b/test/lit/wasm2c/minimal.wast deleted file mode 100644 index 99668920705..00000000000 --- a/test/lit/wasm2c/minimal.wast +++ /dev/null @@ -1,802 +0,0 @@ -;; RUN: wasm2c %s -o %t.c -;; RUN: cat %t.h | filecheck %s --match-full-lines --check-prefix=CHECK-HEADER -;; RUN: cat %t.c | filecheck %s --match-full-lines --check-prefix=CHECK-SOURCE -(module) - -;; CHECK-HEADER: /* Automatically generated by wasm2c */ -;; CHECK-HEADER-NEXT: #ifndef WASM_H_GENERATED_TEST -;; CHECK-HEADER-NEXT: #define WASM_H_GENERATED_TEST -;; CHECK-HEADER-EMPTY: -;; CHECK-HEADER-NEXT: #include "wasm-rt.h" -;; CHECK-HEADER-EMPTY: -;; CHECK-HEADER-NEXT: #include -;; CHECK-HEADER-EMPTY: -;; CHECK-HEADER-NEXT: #ifndef WASM_RT_CORE_TYPES_DEFINED -;; CHECK-HEADER-NEXT: #define WASM_RT_CORE_TYPES_DEFINED -;; CHECK-HEADER-NEXT: typedef uint8_t u8; -;; CHECK-HEADER-NEXT: typedef int8_t s8; -;; CHECK-HEADER-NEXT: typedef uint16_t u16; -;; CHECK-HEADER-NEXT: typedef int16_t s16; -;; CHECK-HEADER-NEXT: typedef uint32_t u32; -;; CHECK-HEADER-NEXT: typedef int32_t s32; -;; CHECK-HEADER-NEXT: typedef uint64_t u64; -;; CHECK-HEADER-NEXT: typedef int64_t s64; -;; CHECK-HEADER-NEXT: typedef float f32; -;; CHECK-HEADER-NEXT: typedef double f64; -;; CHECK-HEADER-NEXT: #endif -;; CHECK-HEADER-EMPTY: -;; CHECK-HEADER-NEXT: #ifdef __cplusplus -;; CHECK-HEADER-NEXT: extern "C" { -;; CHECK-HEADER-NEXT: #endif -;; CHECK-HEADER-EMPTY: -;; CHECK-HEADER-NEXT: typedef struct w2c_test { -;; CHECK-HEADER-NEXT: char dummy_member; -;; CHECK-HEADER-NEXT: } w2c_test; -;; CHECK-HEADER-EMPTY: -;; CHECK-HEADER-NEXT: void wasm2c_test_instantiate(w2c_test*); -;; CHECK-HEADER-NEXT: void wasm2c_test_free(w2c_test*); -;; CHECK-HEADER-NEXT: wasm_rt_func_type_t wasm2c_test_get_func_type(uint32_t param_count, uint32_t result_count, ...); -;; CHECK-HEADER-EMPTY: -;; CHECK-HEADER-NEXT: #ifdef __cplusplus -;; CHECK-HEADER-NEXT: } -;; CHECK-HEADER-NEXT: #endif -;; CHECK-HEADER-EMPTY: -;; CHECK-HEADER-NEXT: #endif /* WASM_H_GENERATED_TEST */ - -;; CHECK-SOURCE: /* Automatically generated by wasm2c */ -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #if defined(__MINGW32__) -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #elif defined(_MSC_VER) -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #define alloca _alloca -;; CHECK-SOURCE-NEXT: #elif defined(__FreeBSD__) || defined(__OpenBSD__) -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #include "minimal.wast.tmp.h" -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: // Computes a pointer to an object of the given size in a little-endian memory. -;; CHECK-SOURCE-NEXT: // -;; CHECK-SOURCE-NEXT: // On a little-endian host, this is just &mem->data[addr] - the object's size is -;; CHECK-SOURCE-NEXT: // unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -;; CHECK-SOURCE-NEXT: // is the object's size. -;; CHECK-SOURCE-NEXT: // -;; CHECK-SOURCE-NEXT: // Note that mem may be evaluated multiple times. -;; CHECK-SOURCE-NEXT: // -;; CHECK-SOURCE-NEXT: // Parameters: -;; CHECK-SOURCE-NEXT: // mem - The memory. -;; CHECK-SOURCE-NEXT: // addr - The address. -;; CHECK-SOURCE-NEXT: // n - The size of the object. -;; CHECK-SOURCE-NEXT: // -;; CHECK-SOURCE-NEXT: // Result: -;; CHECK-SOURCE-NEXT: // A pointer for an object of size n. -;; CHECK-SOURCE-NEXT: #if WASM_RT_BIG_ENDIAN -;; CHECK-SOURCE-NEXT: #define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: // We can only use Segue for this module if it uses a single unshared imported -;; CHECK-SOURCE-NEXT: // or exported memory -;; CHECK-SOURCE-NEXT: #if WASM_RT_USE_SEGUE && IS_SINGLE_UNSHARED_MEMORY -;; CHECK-SOURCE-NEXT: #define WASM_RT_USE_SEGUE_FOR_THIS_MODULE 1 -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define WASM_RT_USE_SEGUE_FOR_THIS_MODULE 0 -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #if WASM_RT_USE_SEGUE_FOR_THIS_MODULE -;; CHECK-SOURCE-NEXT: // POSIX uses FS for TLS, GS is free -;; CHECK-SOURCE-NEXT: static inline void* wasm_rt_segue_read_base() { -;; CHECK-SOURCE-NEXT: if (wasm_rt_fsgsbase_inst_supported) { -;; CHECK-SOURCE-NEXT: return (void*)__builtin_ia32_rdgsbase64(); -;; CHECK-SOURCE-NEXT: } else { -;; CHECK-SOURCE-NEXT: return wasm_rt_syscall_get_segue_base(); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: static inline void wasm_rt_segue_write_base(void* base) { -;; CHECK-SOURCE-NEXT: #if WASM_RT_SEGUE_FREE_SEGMENT -;; CHECK-SOURCE-NEXT: if (wasm_rt_last_segment_val == base) { -;; CHECK-SOURCE-NEXT: return; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: wasm_rt_last_segment_val = base; -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: if (wasm_rt_fsgsbase_inst_supported) { -;; CHECK-SOURCE-NEXT: __builtin_ia32_wrgsbase64((uintptr_t)base); -;; CHECK-SOURCE-NEXT: } else { -;; CHECK-SOURCE-NEXT: wasm_rt_syscall_set_segue_base(base); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: #define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #if WASM_RT_STACK_DEPTH_COUNT -;; CHECK-SOURCE-NEXT: #define FUNC_PROLOGUE \ -;; CHECK-SOURCE-NEXT: if (++wasm_rt_call_stack_depth > WASM_RT_MAX_CALL_STACK_DEPTH) \ -;; CHECK-SOURCE-NEXT: TRAP(EXHAUSTION); -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define FUNC_EPILOGUE --wasm_rt_call_stack_depth -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define FUNC_PROLOGUE -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define FUNC_EPILOGUE -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define UNREACHABLE TRAP(UNREACHABLE) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline bool func_types_eq(const wasm_rt_func_type_t a, -;; CHECK-SOURCE-NEXT: const wasm_rt_func_type_t b) { -;; CHECK-SOURCE-NEXT: return (a == b) || LIKELY(a && b && !memcmp(a, b, 32)); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define CHECK_CALL_INDIRECT(table, ft, x) \ -;; CHECK-SOURCE-NEXT: (LIKELY((x) < table.size && table.data[x].func && \ -;; CHECK-SOURCE-NEXT: func_types_eq(ft, table.data[x].func_type)) || \ -;; CHECK-SOURCE-NEXT: TRAP(CALL_INDIRECT)) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DO_CALL_INDIRECT(table, t, x, ...) ((t)table.data[x].func)(__VA_ARGS__) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define CALL_INDIRECT(table, t, ft, x, ...) \ -;; CHECK-SOURCE-NEXT: (CHECK_CALL_INDIRECT(table, ft, x), \ -;; CHECK-SOURCE-NEXT: DO_CALL_INDIRECT(table, t, x, __VA_ARGS__)) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) { -;; CHECK-SOURCE-NEXT: #if __has_builtin(__builtin_add_overflow) -;; CHECK-SOURCE-NEXT: return __builtin_add_overflow(a, b, resptr); -;; CHECK-SOURCE-NEXT: #elif defined(_MSC_VER) -;; CHECK-SOURCE-NEXT: return _addcarry_u64(0, a, b, resptr); -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #error "Missing implementation of __builtin_add_overflow or _addcarry_u64" -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define RANGE_CHECK(mem, offset, len) \ -;; CHECK-SOURCE-NEXT: do { \ -;; CHECK-SOURCE-NEXT: uint64_t res; \ -;; CHECK-SOURCE-NEXT: if (UNLIKELY(add_overflow(offset, len, &res))) \ -;; CHECK-SOURCE-NEXT: TRAP(OOB); \ -;; CHECK-SOURCE-NEXT: if (UNLIKELY(res > (mem)->size)) \ -;; CHECK-SOURCE-NEXT: TRAP(OOB); \ -;; CHECK-SOURCE-NEXT: } while (0); -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #if WASM_RT_USE_SEGUE_FOR_THIS_MODULE && WASM_RT_SANITY_CHECKS -;; CHECK-SOURCE-NEXT: #include -;; CHECK-SOURCE-NEXT: #define WASM_RT_CHECK_BASE(mem) \ -;; CHECK-SOURCE-NEXT: if (((uintptr_t)((mem)->data)) != ((uintptr_t)wasm_rt_segue_read_base())) { \ -;; CHECK-SOURCE-NEXT: puts("Segment register mismatch\n"); \ -;; CHECK-SOURCE-NEXT: abort(); \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define WASM_RT_CHECK_BASE(mem) -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: // MEMCHECK_DEFAULT32 is an "accelerated" MEMCHECK used only for -;; CHECK-SOURCE-NEXT: // default-page-size, 32-bit memories. It may do nothing at all -;; CHECK-SOURCE-NEXT: // (if hardware bounds-checking is enabled via guard pages) -;; CHECK-SOURCE-NEXT: // or it may do a slightly faster RANGE_CHECK. -;; CHECK-SOURCE-NEXT: #if WASM_RT_MEMCHECK_GUARD_PAGES -;; CHECK-SOURCE-NEXT: #define MEMCHECK_DEFAULT32(mem, a, t) WASM_RT_CHECK_BASE(mem); -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define MEMCHECK_DEFAULT32(mem, a, t) \ -;; CHECK-SOURCE-NEXT: WASM_RT_CHECK_BASE(mem); \ -;; CHECK-SOURCE-NEXT: if (UNLIKELY(a + (uint64_t)sizeof(t) > mem->size)) \ -;; CHECK-SOURCE-NEXT: TRAP(OOB); -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: // MEMCHECK_GENERAL can be used for any memory -;; CHECK-SOURCE-NEXT: #define MEMCHECK_GENERAL(mem, a, t) \ -;; CHECK-SOURCE-NEXT: WASM_RT_CHECK_BASE(mem); \ -;; CHECK-SOURCE-NEXT: RANGE_CHECK(mem, a, sizeof(t)); -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #ifdef __GNUC__ -;; CHECK-SOURCE-NEXT: #define FORCE_READ_INT(var) __asm__("" ::"r"(var)); -;; CHECK-SOURCE-NEXT: // Clang on Mips requires "f" constraints on floats -;; CHECK-SOURCE-NEXT: // See https://github.com/llvm/llvm-project/issues/64241 -;; CHECK-SOURCE-NEXT: #if defined(__clang__) && \ -;; CHECK-SOURCE-NEXT: (defined(mips) || defined(__mips__) || defined(__mips)) -;; CHECK-SOURCE-NEXT: #define FORCE_READ_FLOAT(var) __asm__("" ::"f"(var)); -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define FORCE_READ_FLOAT(var) __asm__("" ::"r"(var)); -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define FORCE_READ_INT(var) -;; CHECK-SOURCE-NEXT: #define FORCE_READ_FLOAT(var) -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline void load_data(u8* dest, const u8* src, size_t n) { -;; CHECK-SOURCE-NEXT: if (!n) { -;; CHECK-SOURCE-NEXT: return; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: #if WASM_RT_BIG_ENDIAN -;; CHECK-SOURCE-NEXT: for (size_t i = 0; i < n; i++) { -;; CHECK-SOURCE-NEXT: dest[i] = src[n - i - 1]; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(dest, src, n); -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define LOAD_DATA(m, o, i, s) \ -;; CHECK-SOURCE-NEXT: do { \ -;; CHECK-SOURCE-NEXT: RANGE_CHECK((&m), o, s); \ -;; CHECK-SOURCE-NEXT: load_data(MEM_ADDR(&m, o, s), i, s); \ -;; CHECK-SOURCE-NEXT: } while (0) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEF_MEM_CHECKS0(name, shared, mem_type, ret_kw, return_type) \ -;; CHECK-SOURCE-NEXT: static inline return_type name##_default32(wasm_rt##shared##memory_t* mem, \ -;; CHECK-SOURCE-NEXT: u64 addr) { \ -;; CHECK-SOURCE-NEXT: MEMCHECK_DEFAULT32(mem, addr, mem_type); \ -;; CHECK-SOURCE-NEXT: ret_kw name##_unchecked(mem, addr); \ -;; CHECK-SOURCE-NEXT: } \ -;; CHECK-SOURCE-NEXT: static inline return_type name(wasm_rt##shared##memory_t* mem, u64 addr) { \ -;; CHECK-SOURCE-NEXT: MEMCHECK_GENERAL(mem, addr, mem_type); \ -;; CHECK-SOURCE-NEXT: ret_kw name##_unchecked(mem, addr); \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEF_MEM_CHECKS1(name, shared, mem_type, ret_kw, return_type, \ -;; CHECK-SOURCE-NEXT: val_type1) \ -;; CHECK-SOURCE-NEXT: static inline return_type name##_default32(wasm_rt##shared##memory_t* mem, \ -;; CHECK-SOURCE-NEXT: u64 addr, val_type1 val1) { \ -;; CHECK-SOURCE-NEXT: MEMCHECK_DEFAULT32(mem, addr, mem_type); \ -;; CHECK-SOURCE-NEXT: ret_kw name##_unchecked(mem, addr, val1); \ -;; CHECK-SOURCE-NEXT: } \ -;; CHECK-SOURCE-NEXT: static inline return_type name(wasm_rt##shared##memory_t* mem, u64 addr, \ -;; CHECK-SOURCE-NEXT: val_type1 val1) { \ -;; CHECK-SOURCE-NEXT: MEMCHECK_GENERAL(mem, addr, mem_type); \ -;; CHECK-SOURCE-NEXT: ret_kw name##_unchecked(mem, addr, val1); \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEF_MEM_CHECKS2(name, shared, mem_type, ret_kw, return_type, \ -;; CHECK-SOURCE-NEXT: val_type1, val_type2) \ -;; CHECK-SOURCE-NEXT: static inline return_type name##_default32(wasm_rt##shared##memory_t* mem, \ -;; CHECK-SOURCE-NEXT: u64 addr, val_type1 val1, \ -;; CHECK-SOURCE-NEXT: val_type2 val2) { \ -;; CHECK-SOURCE-NEXT: MEMCHECK_DEFAULT32(mem, addr, mem_type); \ -;; CHECK-SOURCE-NEXT: ret_kw name##_unchecked(mem, addr, val1, val2); \ -;; CHECK-SOURCE-NEXT: } \ -;; CHECK-SOURCE-NEXT: static inline return_type name(wasm_rt##shared##memory_t* mem, u64 addr, \ -;; CHECK-SOURCE-NEXT: val_type1 val1, val_type2 val2) { \ -;; CHECK-SOURCE-NEXT: MEMCHECK_GENERAL(mem, addr, mem_type); \ -;; CHECK-SOURCE-NEXT: ret_kw name##_unchecked(mem, addr, val1, val2); \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEFINE_LOAD(name, t1, t2, t3, force_read) \ -;; CHECK-SOURCE-NEXT: static inline t3 name##_unchecked(wasm_rt_memory_t* mem, u64 addr) { \ -;; CHECK-SOURCE-NEXT: t1 result; \ -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ -;; CHECK-SOURCE-NEXT: sizeof(t1)); \ -;; CHECK-SOURCE-NEXT: force_read(result); \ -;; CHECK-SOURCE-NEXT: return (t3)(t2)result; \ -;; CHECK-SOURCE-NEXT: } \ -;; CHECK-SOURCE-NEXT: DEF_MEM_CHECKS0(name, _, t1, return, t3) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEFINE_STORE(name, t1, t2) \ -;; CHECK-SOURCE-NEXT: static inline void name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \ -;; CHECK-SOURCE-NEXT: t2 value) { \ -;; CHECK-SOURCE-NEXT: t1 wrapped = (t1)value; \ -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ -;; CHECK-SOURCE-NEXT: sizeof(t1)); \ -;; CHECK-SOURCE-NEXT: } \ -;; CHECK-SOURCE-NEXT: DEF_MEM_CHECKS1(name, _, t1, , void, t2) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i32_load, u32, u32, u32, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i64_load, u64, u64, u64, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(f32_load, f32, f32, f32, FORCE_READ_FLOAT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(f64_load, f64, f64, f64, FORCE_READ_FLOAT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i32_load8_s, s8, s32, u32, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i64_load8_s, s8, s64, u64, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i32_load8_u, u8, u32, u32, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i64_load8_u, u8, u64, u64, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i32_load16_s, s16, s32, u32, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i64_load16_s, s16, s64, u64, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i32_load16_u, u16, u32, u32, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i64_load16_u, u16, u64, u64, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i64_load32_s, s32, s64, u64, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_LOAD(i64_load32_u, u32, u64, u64, FORCE_READ_INT) -;; CHECK-SOURCE-NEXT: DEFINE_STORE(i32_store, u32, u32) -;; CHECK-SOURCE-NEXT: DEFINE_STORE(i64_store, u64, u64) -;; CHECK-SOURCE-NEXT: DEFINE_STORE(f32_store, f32, f32) -;; CHECK-SOURCE-NEXT: DEFINE_STORE(f64_store, f64, f64) -;; CHECK-SOURCE-NEXT: DEFINE_STORE(i32_store8, u8, u32) -;; CHECK-SOURCE-NEXT: DEFINE_STORE(i32_store16, u16, u32) -;; CHECK-SOURCE-NEXT: DEFINE_STORE(i64_store8, u8, u64) -;; CHECK-SOURCE-NEXT: DEFINE_STORE(i64_store16, u16, u64) -;; CHECK-SOURCE-NEXT: DEFINE_STORE(i64_store32, u32, u64) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #if defined(_MSC_VER) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: // Adapted from -;; CHECK-SOURCE-NEXT: // https://github.com/nemequ/portable-snippets/blob/master/builtin/builtin.h -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline int I64_CLZ(unsigned long long v) { -;; CHECK-SOURCE-NEXT: unsigned long r = 0; -;; CHECK-SOURCE-NEXT: #if defined(_M_AMD64) || defined(_M_ARM) -;; CHECK-SOURCE-NEXT: if (_BitScanReverse64(&r, v)) { -;; CHECK-SOURCE-NEXT: return 63 - r; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: if (_BitScanReverse(&r, (unsigned long)(v >> 32))) { -;; CHECK-SOURCE-NEXT: return 31 - r; -;; CHECK-SOURCE-NEXT: } else if (_BitScanReverse(&r, (unsigned long)v)) { -;; CHECK-SOURCE-NEXT: return 63 - r; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-NEXT: return 64; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline int I32_CLZ(unsigned long v) { -;; CHECK-SOURCE-NEXT: unsigned long r = 0; -;; CHECK-SOURCE-NEXT: if (_BitScanReverse(&r, v)) { -;; CHECK-SOURCE-NEXT: return 31 - r; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return 32; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline int I64_CTZ(unsigned long long v) { -;; CHECK-SOURCE-NEXT: if (!v) { -;; CHECK-SOURCE-NEXT: return 64; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: unsigned long r = 0; -;; CHECK-SOURCE-NEXT: #if defined(_M_AMD64) || defined(_M_ARM) -;; CHECK-SOURCE-NEXT: _BitScanForward64(&r, v); -;; CHECK-SOURCE-NEXT: return (int)r; -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: if (_BitScanForward(&r, (unsigned int)(v))) { -;; CHECK-SOURCE-NEXT: return (int)(r); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: _BitScanForward(&r, (unsigned int)(v >> 32)); -;; CHECK-SOURCE-NEXT: return (int)(r + 32); -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline int I32_CTZ(unsigned long v) { -;; CHECK-SOURCE-NEXT: if (!v) { -;; CHECK-SOURCE-NEXT: return 32; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: unsigned long r = 0; -;; CHECK-SOURCE-NEXT: _BitScanForward(&r, v); -;; CHECK-SOURCE-NEXT: return (int)r; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define POPCOUNT_DEFINE_PORTABLE(f_n, T) \ -;; CHECK-SOURCE-NEXT: static inline u32 f_n(T x) { \ -;; CHECK-SOURCE-NEXT: x = x - ((x >> 1) & (T) ~(T)0 / 3); \ -;; CHECK-SOURCE-NEXT: x = (x & (T) ~(T)0 / 15 * 3) + ((x >> 2) & (T) ~(T)0 / 15 * 3); \ -;; CHECK-SOURCE-NEXT: x = (x + (x >> 4)) & (T) ~(T)0 / 255 * 15; \ -;; CHECK-SOURCE-NEXT: return (T)(x * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8; \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: POPCOUNT_DEFINE_PORTABLE(I32_POPCNT, u32) -;; CHECK-SOURCE-NEXT: POPCOUNT_DEFINE_PORTABLE(I64_POPCNT, u64) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #undef POPCOUNT_DEFINE_PORTABLE -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32) -;; CHECK-SOURCE-NEXT: #define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64) -;; CHECK-SOURCE-NEXT: #define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32) -;; CHECK-SOURCE-NEXT: #define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64) -;; CHECK-SOURCE-NEXT: #define I32_POPCNT(x) (__builtin_popcount(x)) -;; CHECK-SOURCE-NEXT: #define I64_POPCNT(x) (__builtin_popcountll(x)) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DIV_S(ut, min, x, y) \ -;; CHECK-SOURCE-NEXT: ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \ -;; CHECK-SOURCE-NEXT: : (ut)((x) / (y))) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define REM_S(ut, min, x, y) \ -;; CHECK-SOURCE-NEXT: ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY((x) == min && (y) == -1)) ? 0 \ -;; CHECK-SOURCE-NEXT: : (ut)((x) % (y))) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y) -;; CHECK-SOURCE-NEXT: #define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y) -;; CHECK-SOURCE-NEXT: #define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y) -;; CHECK-SOURCE-NEXT: #define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DIVREM_U(op, x, y) \ -;; CHECK-SOURCE-NEXT: ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x)op(y))) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DIV_U(x, y) DIVREM_U(/, x, y) -;; CHECK-SOURCE-NEXT: #define REM_U(x, y) DIVREM_U(%, x, y) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define ROTL(x, y, mask) \ -;; CHECK-SOURCE-NEXT: (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask)))) -;; CHECK-SOURCE-NEXT: #define ROTR(x, y, mask) \ -;; CHECK-SOURCE-NEXT: (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask)))) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define I32_ROTL(x, y) ROTL(x, y, 31) -;; CHECK-SOURCE-NEXT: #define I64_ROTL(x, y) ROTL(x, y, 63) -;; CHECK-SOURCE-NEXT: #define I32_ROTR(x, y) ROTR(x, y, 31) -;; CHECK-SOURCE-NEXT: #define I64_ROTR(x, y) ROTR(x, y, 63) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define FMIN(x, y) \ -;; CHECK-SOURCE-NEXT: ((UNLIKELY((x) != (x))) ? NAN \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY((y) != (y))) ? NAN \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \ -;; CHECK-SOURCE-NEXT: : (x < y) ? x \ -;; CHECK-SOURCE-NEXT: : y) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define FMAX(x, y) \ -;; CHECK-SOURCE-NEXT: ((UNLIKELY((x) != (x))) ? NAN \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY((y) != (y))) ? NAN \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \ -;; CHECK-SOURCE-NEXT: : (x > y) ? x \ -;; CHECK-SOURCE-NEXT: : y) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define TRUNC_S(ut, st, ft, min, minop, max, x) \ -;; CHECK-SOURCE-NEXT: ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY(!((x)minop(min) && (x) < (max)))) ? TRAP(INT_OVERFLOW) \ -;; CHECK-SOURCE-NEXT: : (ut)(st)(x)) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define I32_TRUNC_S_F32(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_S(u32, s32, f32, (f32)INT32_MIN, >=, 2147483648.f, x) -;; CHECK-SOURCE-NEXT: #define I64_TRUNC_S_F32(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_S(u64, s64, f32, (f32)INT64_MIN, >=, (f32)INT64_MAX, x) -;; CHECK-SOURCE-NEXT: #define I32_TRUNC_S_F64(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_S(u32, s32, f64, -2147483649., >, 2147483648., x) -;; CHECK-SOURCE-NEXT: #define I64_TRUNC_S_F64(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_S(u64, s64, f64, (f64)INT64_MIN, >=, (f64)INT64_MAX, x) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define TRUNC_U(ut, ft, max, x) \ -;; CHECK-SOURCE-NEXT: ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY(!((x) > (ft) - 1 && (x) < (max)))) ? TRAP(INT_OVERFLOW) \ -;; CHECK-SOURCE-NEXT: : (ut)(x)) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, 4294967296.f, x) -;; CHECK-SOURCE-NEXT: #define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, (f32)UINT64_MAX, x) -;; CHECK-SOURCE-NEXT: #define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, 4294967296., x) -;; CHECK-SOURCE-NEXT: #define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, (f64)UINT64_MAX, x) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define TRUNC_SAT_S(ut, st, ft, min, smin, minop, max, smax, x) \ -;; CHECK-SOURCE-NEXT: ((UNLIKELY((x) != (x))) ? 0 \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY(!((x)minop(min)))) ? smin \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY(!((x) < (max)))) ? smax \ -;; CHECK-SOURCE-NEXT: : (ut)(st)(x)) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define I32_TRUNC_SAT_S_F32(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_SAT_S(u32, s32, f32, (f32)INT32_MIN, INT32_MIN, >=, 2147483648.f, \ -;; CHECK-SOURCE-NEXT: INT32_MAX, x) -;; CHECK-SOURCE-NEXT: #define I64_TRUNC_SAT_S_F32(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_SAT_S(u64, s64, f32, (f32)INT64_MIN, INT64_MIN, >=, (f32)INT64_MAX, \ -;; CHECK-SOURCE-NEXT: INT64_MAX, x) -;; CHECK-SOURCE-NEXT: #define I32_TRUNC_SAT_S_F64(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_SAT_S(u32, s32, f64, -2147483649., INT32_MIN, >, 2147483648., \ -;; CHECK-SOURCE-NEXT: INT32_MAX, x) -;; CHECK-SOURCE-NEXT: #define I64_TRUNC_SAT_S_F64(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_SAT_S(u64, s64, f64, (f64)INT64_MIN, INT64_MIN, >=, (f64)INT64_MAX, \ -;; CHECK-SOURCE-NEXT: INT64_MAX, x) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define TRUNC_SAT_U(ut, ft, max, smax, x) \ -;; CHECK-SOURCE-NEXT: ((UNLIKELY((x) != (x))) ? 0 \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY(!((x) > (ft) - 1))) ? 0 \ -;; CHECK-SOURCE-NEXT: : (UNLIKELY(!((x) < (max)))) ? smax \ -;; CHECK-SOURCE-NEXT: : (ut)(x)) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define I32_TRUNC_SAT_U_F32(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_SAT_U(u32, f32, 4294967296.f, UINT32_MAX, x) -;; CHECK-SOURCE-NEXT: #define I64_TRUNC_SAT_U_F32(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_SAT_U(u64, f32, (f32)UINT64_MAX, UINT64_MAX, x) -;; CHECK-SOURCE-NEXT: #define I32_TRUNC_SAT_U_F64(x) TRUNC_SAT_U(u32, f64, 4294967296., UINT32_MAX, x) -;; CHECK-SOURCE-NEXT: #define I64_TRUNC_SAT_U_F64(x) \ -;; CHECK-SOURCE-NEXT: TRUNC_SAT_U(u64, f64, (f64)UINT64_MAX, UINT64_MAX, x) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEFINE_REINTERPRET(name, t1, t2) \ -;; CHECK-SOURCE-NEXT: static inline t2 name(t1 x) { \ -;; CHECK-SOURCE-NEXT: t2 result; \ -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&result, &x, sizeof(result)); \ -;; CHECK-SOURCE-NEXT: return result; \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32) -;; CHECK-SOURCE-NEXT: DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32) -;; CHECK-SOURCE-NEXT: DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64) -;; CHECK-SOURCE-NEXT: DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static float quiet_nanf(float x) { -;; CHECK-SOURCE-NEXT: uint32_t tmp; -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&tmp, &x, 4); -;; CHECK-SOURCE-NEXT: tmp |= 0x7fc00000lu; -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&x, &tmp, 4); -;; CHECK-SOURCE-NEXT: return x; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static double quiet_nan(double x) { -;; CHECK-SOURCE-NEXT: uint64_t tmp; -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&tmp, &x, 8); -;; CHECK-SOURCE-NEXT: tmp |= 0x7ff8000000000000llu; -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&x, &tmp, 8); -;; CHECK-SOURCE-NEXT: return x; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static double wasm_quiet(double x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nan(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return x; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static float wasm_quietf(float x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nanf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return x; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static double wasm_floor(double x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nan(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return floor(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static float wasm_floorf(float x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nanf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return floorf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static double wasm_ceil(double x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nan(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return ceil(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static float wasm_ceilf(float x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nanf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return ceilf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static double wasm_trunc(double x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nan(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return trunc(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static float wasm_truncf(float x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nanf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return truncf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static float wasm_nearbyintf(float x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nanf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return nearbyintf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static double wasm_nearbyint(double x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nan(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return nearbyint(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static float wasm_fabsf(float x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: uint32_t tmp; -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&tmp, &x, 4); -;; CHECK-SOURCE-NEXT: tmp = tmp & ~(1UL << 31); -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&x, &tmp, 4); -;; CHECK-SOURCE-NEXT: return x; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return fabsf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static double wasm_fabs(double x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: uint64_t tmp; -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&tmp, &x, 8); -;; CHECK-SOURCE-NEXT: tmp = tmp & ~(1ULL << 63); -;; CHECK-SOURCE-NEXT: wasm_rt_memcpy(&x, &tmp, 8); -;; CHECK-SOURCE-NEXT: return x; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return fabs(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static double wasm_sqrt(double x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nan(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return sqrt(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static float wasm_sqrtf(float x) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(isnan(x))) { -;; CHECK-SOURCE-NEXT: return quiet_nanf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: return sqrtf(x); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { -;; CHECK-SOURCE-NEXT: RANGE_CHECK(mem, d, n); -;; CHECK-SOURCE-NEXT: memset(MEM_ADDR(mem, d, n), val, n); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline void memory_copy(wasm_rt_memory_t* dest, -;; CHECK-SOURCE-NEXT: const wasm_rt_memory_t* src, -;; CHECK-SOURCE-NEXT: u64 dest_addr, -;; CHECK-SOURCE-NEXT: u64 src_addr, -;; CHECK-SOURCE-NEXT: u64 n) { -;; CHECK-SOURCE-NEXT: RANGE_CHECK(dest, dest_addr, n); -;; CHECK-SOURCE-NEXT: RANGE_CHECK(src, src_addr, n); -;; CHECK-SOURCE-NEXT: memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline void memory_init(wasm_rt_memory_t* dest, -;; CHECK-SOURCE-NEXT: const u8* src, -;; CHECK-SOURCE-NEXT: u32 src_size, -;; CHECK-SOURCE-NEXT: u64 dest_addr, -;; CHECK-SOURCE-NEXT: u32 src_addr, -;; CHECK-SOURCE-NEXT: u32 n) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(src_addr + (uint64_t)n > src_size)) -;; CHECK-SOURCE-NEXT: TRAP(OOB); -;; CHECK-SOURCE-NEXT: LOAD_DATA((*dest), dest_addr, src + src_addr, n); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: typedef enum { RefFunc, RefNull, GlobalGet } wasm_elem_segment_expr_type_t; -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: typedef struct { -;; CHECK-SOURCE-NEXT: wasm_elem_segment_expr_type_t expr_type; -;; CHECK-SOURCE-NEXT: wasm_rt_func_type_t type; -;; CHECK-SOURCE-NEXT: wasm_rt_function_ptr_t func; -;; CHECK-SOURCE-NEXT: wasm_rt_tailcallee_t func_tailcallee; -;; CHECK-SOURCE-NEXT: size_t module_offset; -;; CHECK-SOURCE-NEXT: } wasm_elem_segment_expr_t; -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: static inline void funcref_table_init(wasm_rt_funcref_table_t* dest, -;; CHECK-SOURCE-NEXT: const wasm_elem_segment_expr_t* src, -;; CHECK-SOURCE-NEXT: u32 src_size, -;; CHECK-SOURCE-NEXT: u64 dest_addr, -;; CHECK-SOURCE-NEXT: u32 src_addr, -;; CHECK-SOURCE-NEXT: u32 n, -;; CHECK-SOURCE-NEXT: void* module_instance) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(src_addr + (uint64_t)n > src_size)) -;; CHECK-SOURCE-NEXT: TRAP(OOB); -;; CHECK-SOURCE-NEXT: RANGE_CHECK(dest, dest_addr, n); -;; CHECK-SOURCE-NEXT: for (u32 i = 0; i < n; i++) { -;; CHECK-SOURCE-NEXT: const wasm_elem_segment_expr_t* const src_expr = &src[src_addr + i]; -;; CHECK-SOURCE-NEXT: wasm_rt_funcref_t* const dest_val = &(dest->data[dest_addr + i]); -;; CHECK-SOURCE-NEXT: switch (src_expr->expr_type) { -;; CHECK-SOURCE-NEXT: case RefFunc: -;; CHECK-SOURCE-NEXT: *dest_val = (wasm_rt_funcref_t){ -;; CHECK-SOURCE-NEXT: src_expr->type, src_expr->func, src_expr->func_tailcallee, -;; CHECK-SOURCE-NEXT: (char*)module_instance + src_expr->module_offset}; -;; CHECK-SOURCE-NEXT: break; -;; CHECK-SOURCE-NEXT: case RefNull: -;; CHECK-SOURCE-NEXT: *dest_val = wasm_rt_funcref_null_value; -;; CHECK-SOURCE-NEXT: break; -;; CHECK-SOURCE-NEXT: case GlobalGet: -;; CHECK-SOURCE-NEXT: *dest_val = **(wasm_rt_funcref_t**)((char*)module_instance + -;; CHECK-SOURCE-NEXT: src_expr->module_offset); -;; CHECK-SOURCE-NEXT: break; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: // Currently wasm2c only supports initializing externref tables with ref.null. -;; CHECK-SOURCE-NEXT: static inline void externref_table_init(wasm_rt_externref_table_t* dest, -;; CHECK-SOURCE-NEXT: u32 src_size, -;; CHECK-SOURCE-NEXT: u64 dest_addr, -;; CHECK-SOURCE-NEXT: u32 src_addr, -;; CHECK-SOURCE-NEXT: u32 n) { -;; CHECK-SOURCE-NEXT: if (UNLIKELY(src_addr + (uint64_t)n > src_size)) -;; CHECK-SOURCE-NEXT: TRAP(OOB); -;; CHECK-SOURCE-NEXT: RANGE_CHECK(dest, dest_addr, n); -;; CHECK-SOURCE-NEXT: for (u32 i = 0; i < n; i++) { -;; CHECK-SOURCE-NEXT: dest->data[dest_addr + i] = wasm_rt_externref_null_value; -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEFINE_TABLE_COPY(type) \ -;; CHECK-SOURCE-NEXT: static inline void type##_table_copy(wasm_rt_##type##_table_t* dest, \ -;; CHECK-SOURCE-NEXT: const wasm_rt_##type##_table_t* src, \ -;; CHECK-SOURCE-NEXT: u64 dest_addr, u64 src_addr, u64 n) { \ -;; CHECK-SOURCE-NEXT: RANGE_CHECK(dest, dest_addr, n); \ -;; CHECK-SOURCE-NEXT: RANGE_CHECK(src, src_addr, n); \ -;; CHECK-SOURCE-NEXT: memmove(dest->data + dest_addr, src->data + src_addr, \ -;; CHECK-SOURCE-NEXT: n * sizeof(wasm_rt_##type##_t)); \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: DEFINE_TABLE_COPY(funcref) -;; CHECK-SOURCE-NEXT: DEFINE_TABLE_COPY(externref) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEFINE_TABLE_GET(type) \ -;; CHECK-SOURCE-NEXT: static inline wasm_rt_##type##_t type##_table_get( \ -;; CHECK-SOURCE-NEXT: const wasm_rt_##type##_table_t* table, u64 i) { \ -;; CHECK-SOURCE-NEXT: if (UNLIKELY(i >= table->size)) \ -;; CHECK-SOURCE-NEXT: TRAP(OOB); \ -;; CHECK-SOURCE-NEXT: return table->data[i]; \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: DEFINE_TABLE_GET(funcref) -;; CHECK-SOURCE-NEXT: DEFINE_TABLE_GET(externref) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEFINE_TABLE_SET(type) \ -;; CHECK-SOURCE-NEXT: static inline void type##_table_set(const wasm_rt_##type##_table_t* table, \ -;; CHECK-SOURCE-NEXT: u64 i, const wasm_rt_##type##_t val) { \ -;; CHECK-SOURCE-NEXT: if (UNLIKELY(i >= table->size)) \ -;; CHECK-SOURCE-NEXT: TRAP(OOB); \ -;; CHECK-SOURCE-NEXT: table->data[i] = val; \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: DEFINE_TABLE_SET(funcref) -;; CHECK-SOURCE-NEXT: DEFINE_TABLE_SET(externref) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #define DEFINE_TABLE_FILL(type) \ -;; CHECK-SOURCE-NEXT: static inline void type##_table_fill(const wasm_rt_##type##_table_t* table, \ -;; CHECK-SOURCE-NEXT: u64 d, const wasm_rt_##type##_t val, \ -;; CHECK-SOURCE-NEXT: u64 n) { \ -;; CHECK-SOURCE-NEXT: RANGE_CHECK(table, d, n); \ -;; CHECK-SOURCE-NEXT: for (uint32_t i = d; i < d + n; i++) { \ -;; CHECK-SOURCE-NEXT: table->data[i] = val; \ -;; CHECK-SOURCE-NEXT: } \ -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: DEFINE_TABLE_FILL(funcref) -;; CHECK-SOURCE-NEXT: DEFINE_TABLE_FILL(externref) -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #if defined(__GNUC__) || defined(__clang__) -;; CHECK-SOURCE-NEXT: #define FUNC_TYPE_DECL_EXTERN_T(x) extern const char* const x -;; CHECK-SOURCE-NEXT: #define FUNC_TYPE_EXTERN_T(x) const char* const x -;; CHECK-SOURCE-NEXT: #define FUNC_TYPE_T(x) static const char* const x -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define FUNC_TYPE_DECL_EXTERN_T(x) extern const char x[] -;; CHECK-SOURCE-NEXT: #define FUNC_TYPE_EXTERN_T(x) const char x[] -;; CHECK-SOURCE-NEXT: #define FUNC_TYPE_T(x) static const char x[] -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #if (__STDC_VERSION__ < 201112L) && !defined(static_assert) -;; CHECK-SOURCE-NEXT: #define static_assert(X) \ -;; CHECK-SOURCE-NEXT: extern int(*assertion(void))[!!sizeof(struct { int x : (X) ? 2 : -1; })]; -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: #ifdef _MSC_VER -;; CHECK-SOURCE-NEXT: #define WEAK_FUNC_DECL(func, fallback) \ -;; CHECK-SOURCE-NEXT: __pragma(comment(linker, "/alternatename:" #func "=" #fallback)) \ -;; CHECK-SOURCE-NEXT: \ -;; CHECK-SOURCE-NEXT: void \ -;; CHECK-SOURCE-NEXT: fallback(void** instance_ptr, void* tail_call_stack, \ -;; CHECK-SOURCE-NEXT: wasm_rt_tailcallee_t* next) -;; CHECK-SOURCE-NEXT: #else -;; CHECK-SOURCE-NEXT: #define WEAK_FUNC_DECL(func, fallback) \ -;; CHECK-SOURCE-NEXT: __attribute__((weak)) void func(void** instance_ptr, void* tail_call_stack, \ -;; CHECK-SOURCE-NEXT: wasm_rt_tailcallee_t* next) -;; CHECK-SOURCE-NEXT: #endif -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: void wasm2c_test_instantiate(w2c_test* instance) { -;; CHECK-SOURCE-NEXT: assert(wasm_rt_is_initialized()); -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: void wasm2c_test_free(w2c_test* instance) { -;; CHECK-SOURCE-NEXT: } -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: wasm_rt_func_type_t wasm2c_test_get_func_type(uint32_t param_count, uint32_t result_count, ...) { -;; CHECK-SOURCE-NEXT: va_list args; -;; CHECK-SOURCE-EMPTY: -;; CHECK-SOURCE-NEXT: return NULL; -;; CHECK-SOURCE-NEXT: } diff --git a/third_party/picosha2 b/third_party/picosha2 deleted file mode 160000 index 161cb3fc417..00000000000 --- a/third_party/picosha2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 161cb3fc4170fa7a3eca9e582cebd27cc4d1fe29 diff --git a/third_party/simde b/third_party/simde deleted file mode 160000 index f3e8262173b..00000000000 --- a/third_party/simde +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f3e8262173b7089db9a9d57a9ecef8dd07ad9c97