diff options
Diffstat (limited to 'third_party/wasm2c/wasm2c/wasm-rt.h')
-rw-r--r-- | third_party/wasm2c/wasm2c/wasm-rt.h | 455 |
1 files changed, 455 insertions, 0 deletions
diff --git a/third_party/wasm2c/wasm2c/wasm-rt.h b/third_party/wasm2c/wasm2c/wasm-rt.h new file mode 100644 index 0000000000..9fd12dee03 --- /dev/null +++ b/third_party/wasm2c/wasm2c/wasm-rt.h @@ -0,0 +1,455 @@ +/* + * 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 <setjmp.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#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 _MSC_VER +#define WASM_RT_THREAD_LOCAL __declspec(thread) +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +#define WASM_RT_THREAD_LOCAL _Thread_local +#else +#define WASM_RT_THREAD_LOCAL +#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 && !SUPPORT_MEMORY64 +#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 fasest 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 && !SUPPORT_MEMORY64 +#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 + +#ifndef WASM_RT_USE_STACK_DEPTH_COUNT +/* The signal handler on POSIX can detect call stack overflows. On windows, or + * platforms without a signal handler, we use stack depth counting. */ +#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) +#define WASM_RT_USE_STACK_DEPTH_COUNT 0 +#else +#define WASM_RT_USE_STACK_DEPTH_COUNT 1 +#endif +#endif + +#if WASM_RT_USE_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 defined(_MSC_VER) +#define WASM_RT_NO_RETURN __declspec(noreturn) +#else +#define WASM_RT_NO_RETURN __attribute__((noreturn)) +#endif + +#if defined(__APPLE__) && WASM_RT_INSTALL_SIGNAL_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_UNCAUGHT_EXCEPTION, /* Exception thrown and not caught */ +#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_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); + +/** + * 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; + /** 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 */ +static const wasm_rt_funcref_t wasm_rt_funcref_null_value = {NULL, NULL, NULL}; + +/** The type of an external reference (opaque to WebAssembly). */ +typedef void* wasm_rt_externref_t; + +/** Default (null) value of an externref */ +static const wasm_rt_externref_t wasm_rt_externref_null_value = NULL; + +/** 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). */ + uint64_t pages, 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; + +/** 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); + +/** + * 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; + +#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) +#define WASM_RT_SETJMP_SETBUF(buf) sigsetjmp(buf, 1) +#else +#define WASM_RT_SETJMP_SETBUF(buf) setjmp(buf) +#endif + +#define WASM_RT_SETJMP(buf) \ + ((buf).initialized = true, WASM_RT_SETJMP_SETBUF((buf).buffer)) + +#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_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(target) + +/** + * 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); + * ``` + */ +void wasm_rt_allocate_memory(wasm_rt_memory_t*, + uint64_t initial_pages, + uint64_t max_pages, + bool is64); + +/** + * 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*); + +/** + * 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_ */ |