diff options
Diffstat (limited to 'third_party/wabt/wasm2c')
-rw-r--r-- | third_party/wabt/wasm2c/README.md | 5 | ||||
-rw-r--r-- | third_party/wabt/wasm2c/wasm-rt-impl.c | 182 | ||||
-rw-r--r-- | third_party/wabt/wasm2c/wasm-rt-impl.h | 65 | ||||
-rw-r--r-- | third_party/wabt/wasm2c/wasm-rt.h | 201 |
4 files changed, 453 insertions, 0 deletions
diff --git a/third_party/wabt/wasm2c/README.md b/third_party/wabt/wasm2c/README.md new file mode 100644 index 000000000..16ab3fc6c --- /dev/null +++ b/third_party/wabt/wasm2c/README.md @@ -0,0 +1,5 @@ +These files are part of WABT, but are currently not present in releases, so the +directory is included as a fallback in Binaryen in a way that the files will be +overwritten in case WABT contains them in the future. + +Original README: https://github.com/WebAssembly/wabt/blob/master/wasm2c/README.md diff --git a/third_party/wabt/wasm2c/wasm-rt-impl.c b/third_party/wabt/wasm2c/wasm-rt-impl.c new file mode 100644 index 000000000..c52063ab3 --- /dev/null +++ b/third_party/wabt/wasm2c/wasm-rt-impl.c @@ -0,0 +1,182 @@ +/* + * 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 <assert.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX +#include <signal.h> +#include <sys/mman.h> +#include <unistd.h> +#endif + +#define PAGE_SIZE 65536 + +typedef struct FuncType { + wasm_rt_type_t* params; + wasm_rt_type_t* results; + uint32_t param_count; + uint32_t result_count; +} FuncType; + +uint32_t wasm_rt_call_stack_depth; +uint32_t g_saved_call_stack_depth; + +#if WASM_RT_MEMCHECK_SIGNAL_HANDLER +bool g_signal_handler_installed = false; +#endif + +jmp_buf g_jmp_buf; +FuncType* g_func_types; +uint32_t g_func_type_count; + +void wasm_rt_trap(wasm_rt_trap_t code) { + assert(code != WASM_RT_TRAP_NONE); + wasm_rt_call_stack_depth = g_saved_call_stack_depth; + WASM_RT_LONGJMP(g_jmp_buf, code); +} + +static bool func_types_are_equal(FuncType* a, FuncType* b) { + if (a->param_count != b->param_count || a->result_count != b->result_count) + return 0; + int i; + for (i = 0; i < a->param_count; ++i) + if (a->params[i] != b->params[i]) + return 0; + for (i = 0; i < a->result_count; ++i) + if (a->results[i] != b->results[i]) + return 0; + return 1; +} + +uint32_t wasm_rt_register_func_type(uint32_t param_count, + uint32_t result_count, + ...) { + FuncType func_type; + func_type.param_count = param_count; + func_type.params = malloc(param_count * sizeof(wasm_rt_type_t)); + func_type.result_count = result_count; + func_type.results = malloc(result_count * sizeof(wasm_rt_type_t)); + + va_list args; + va_start(args, result_count); + + uint32_t i; + for (i = 0; i < param_count; ++i) + func_type.params[i] = va_arg(args, wasm_rt_type_t); + for (i = 0; i < result_count; ++i) + func_type.results[i] = va_arg(args, wasm_rt_type_t); + va_end(args); + + for (i = 0; i < g_func_type_count; ++i) { + if (func_types_are_equal(&g_func_types[i], &func_type)) { + free(func_type.params); + free(func_type.results); + return i + 1; + } + } + + uint32_t idx = g_func_type_count++; + g_func_types = realloc(g_func_types, g_func_type_count * sizeof(FuncType)); + g_func_types[idx] = func_type; + return idx + 1; +} + +#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX +static void signal_handler(int sig, siginfo_t* si, void* unused) { + wasm_rt_trap(WASM_RT_TRAP_OOB); +} +#endif + +void wasm_rt_allocate_memory(wasm_rt_memory_t* memory, + uint32_t initial_pages, + uint32_t max_pages) { + uint32_t byte_length = initial_pages * PAGE_SIZE; +#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX + if (!g_signal_handler_installed) { + g_signal_handler_installed = true; + struct sigaction sa; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = 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(); + } + } + + /* Reserve 8GiB. */ + void* addr = + mmap(NULL, 0x200000000ul, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (addr == (void*)-1) { + perror("mmap failed"); + abort(); + } + mprotect(addr, byte_length, PROT_READ | PROT_WRITE); + memory->data = addr; +#else + memory->data = calloc(byte_length, 1); +#endif + memory->size = byte_length; + memory->pages = initial_pages; + memory->max_pages = max_pages; +} + +uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) { + uint32_t old_pages = memory->pages; + uint32_t new_pages = memory->pages + delta; + if (new_pages == 0) { + return 0; + } + if (new_pages < old_pages || new_pages > memory->max_pages) { + return (uint32_t)-1; + } + uint32_t old_size = old_pages * PAGE_SIZE; + uint32_t new_size = new_pages * PAGE_SIZE; + uint32_t delta_size = delta * PAGE_SIZE; +#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX + uint8_t* new_data = memory->data; + mprotect(new_data + old_size, delta_size, PROT_READ | PROT_WRITE); +#else + uint8_t* new_data = realloc(memory->data, new_size); + if (new_data == NULL) { + return (uint32_t)-1; + } + memset(new_data + old_size, 0, delta_size); +#endif + memory->pages = new_pages; + memory->size = new_size; + memory->data = new_data; + return old_pages; +} + +void wasm_rt_allocate_table(wasm_rt_table_t* table, + uint32_t elements, + uint32_t max_elements) { + table->size = elements; + table->max_size = max_elements; + table->data = calloc(table->size, sizeof(wasm_rt_elem_t)); +} diff --git a/third_party/wabt/wasm2c/wasm-rt-impl.h b/third_party/wabt/wasm2c/wasm-rt-impl.h new file mode 100644 index 000000000..39d5ed930 --- /dev/null +++ b/third_party/wabt/wasm2c/wasm-rt-impl.h @@ -0,0 +1,65 @@ +/* + * 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 <setjmp.h> + +#include "wasm-rt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** A setjmp buffer used for handling traps. */ +extern jmp_buf g_jmp_buf; + +/** Saved call stack depth that will be restored in case a trap occurs. */ +extern uint32_t g_saved_call_stack_depth; + +#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX +#define WASM_RT_SETJMP(buf) sigsetjmp(buf, 1) +#define WASM_RT_LONGJMP(buf, val) siglongjmp(buf, val) +#else +#define WASM_RT_SETJMP(buf) setjmp(buf) +#define WASM_RT_LONGJMP(buf, val) longjmp(buf, val) +#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() \ + (g_saved_call_stack_depth = wasm_rt_call_stack_depth, \ + WASM_RT_SETJMP(g_jmp_buf)) + +#ifdef __cplusplus +} +#endif + +#endif // WASM_RT_IMPL_H_ diff --git a/third_party/wabt/wasm2c/wasm-rt.h b/third_party/wabt/wasm2c/wasm-rt.h new file mode 100644 index 000000000..2797e8f71 --- /dev/null +++ b/third_party/wabt/wasm2c/wasm-rt.h @@ -0,0 +1,201 @@ +/* + * 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 <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** Maximum stack depth before trapping. This 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 + +/** Enable memory checking via a signal handler via the following definition: + * + * #define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1 + * + * This is usually 10%-25% faster, but requires OS-specific support. + * */ + +/** Check whether the signal handler is supported at all. */ +#if (defined(__linux__) || defined(__unix__) || defined(__APPLE__)) && \ + defined(__WORDSIZE) && __WORDSIZE == 64 + +/* If the signal handler is supported, then use it by default. */ +#ifndef WASM_RT_MEMCHECK_SIGNAL_HANDLER +#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1 +#endif + +#if WASM_RT_MEMCHECK_SIGNAL_HANDLER +#define WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX 1 +#endif + +#else + +/* The signal handler is not supported, error out if the user was trying to + * enable it. */ +#if WASM_RT_MEMCHECK_SIGNAL_HANDLER +#error "Signal handler is not supported for this OS/Architecture!" +#endif + +#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 0 +#define WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX 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. */ + 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_EXHAUSTION, /** Call stack exhausted. */ +} 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_type_t; + +/** A function type for all `anyfunc` functions in a Table. All functions are + * stored in this canonical form, but must be cast to their proper signature to + * call. */ +typedef void (*wasm_rt_anyfunc_t)(void); + +/** A single element of a Table. */ +typedef struct { + /** The index as returned from `wasm_rt_register_func_type`. */ + uint32_t func_type; + /** The function. The embedder must know the actual C signature of the + * function and cast to it before calling. */ + wasm_rt_anyfunc_t func; +} wasm_rt_elem_t; + +/** A Memory object. */ +typedef struct { + /** The linear memory data, with a byte length of `size`. */ + uint8_t* data; + /** The current and maximum page count for this Memory object. If there is no + * maximum, `max_pages` is 0xffffffffu (i.e. UINT32_MAX). */ + uint32_t pages, max_pages; + /** The current size of the linear memory, in bytes. */ + uint32_t size; +} wasm_rt_memory_t; + +/** A Table object. */ +typedef struct { + /** The table element data, with an element count of `size`. */ + wasm_rt_elem_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_table_t; + +/** Stop execution immediately and jump back to the call to `wasm_rt_try`. + * The result of `wasm_rt_try` will be the provided trap reason. + * + * This is typically called by the generated code, and not the embedder. */ +extern void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn)); + +/** Register a function type with the given signature. The returned function + * index is guaranteed to be the same for all calls with the same signature. + * The following varargs must all be of type `wasm_rt_type_t`, first the + * params` and then the `results`. + * + * ``` + * // Register (func (param i32 f32) (result i64)). + * wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64); + * => returns 1 + * + * // Register (func (result i64)). + * wasm_rt_register_func_type(0, 1, WASM_RT_I32); + * => returns 2 + * + * // Register (func (param i32 f32) (result i64)) again. + * wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64); + * => returns 1 + * ``` */ +extern uint32_t wasm_rt_register_func_type(uint32_t params, + uint32_t results, + ...); + +/** Initialize a Memory object with an initial page size of `initial_pages` and + * a maximum page size of `max_pages`. + * + * ``` + * wasm_rt_memory_t my_memory; + * // 1 initial page (65536 bytes), and a maximum of 2 pages. + * wasm_rt_allocate_memory(&my_memory, 1, 2); + * ``` */ +extern void wasm_rt_allocate_memory(wasm_rt_memory_t*, + uint32_t initial_pages, + uint32_t max_pages); + +/** 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. + * } + * ``` */ +extern uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages); + +/** Initialize a Table object with an element count of `elements` and a maximum + * page size of `max_elements`. + * + * ``` + * wasm_rt_table_t my_table; + * // 5 elemnets and a maximum of 10 elements. + * wasm_rt_allocate_table(&my_table, 5, 10); + * ``` */ +extern void wasm_rt_allocate_table(wasm_rt_table_t*, + uint32_t elements, + uint32_t max_elements); + +/** Current call stack depth. */ +extern uint32_t wasm_rt_call_stack_depth; + +#ifdef __cplusplus +} +#endif + +#endif /* WASM_RT_H_ */ |