diff options
Diffstat (limited to 'wasm2c')
-rw-r--r-- | wasm2c/README.md | 37 | ||||
-rw-r--r-- | wasm2c/wasm-rt-impl.c | 176 | ||||
-rw-r--r-- | wasm2c/wasm-rt-mem-impl-helper.inc | 164 | ||||
-rw-r--r-- | wasm2c/wasm-rt-mem-impl.c | 178 | ||||
-rw-r--r-- | wasm2c/wasm-rt.h | 77 |
5 files changed, 453 insertions, 179 deletions
diff --git a/wasm2c/README.md b/wasm2c/README.md index e0739bfb..9cdbdc27 100644 --- a/wasm2c/README.md +++ b/wasm2c/README.md @@ -11,6 +11,9 @@ $ wasm2c test.wasm -o test.c $ 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. @@ -255,11 +258,28 @@ specified by the module, or `0xffffffff` if there is no limit. ```c typedef struct { uint8_t* data; - uint32_t pages, max_pages; - uint32_t 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 @@ -290,6 +310,9 @@ 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 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 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*); @@ -329,6 +352,16 @@ arguments and returning `void` . e.g. `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. It's 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 diff --git a/wasm2c/wasm-rt-impl.c b/wasm2c/wasm-rt-impl.c index 57bd74cf..7c88499d 100644 --- a/wasm2c/wasm-rt-impl.c +++ b/wasm2c/wasm-rt-impl.c @@ -36,8 +36,6 @@ #include <sys/mman.h> #endif -#define PAGE_SIZE 65536 - #ifndef NDEBUG #define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__); #else @@ -64,10 +62,6 @@ WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf g_wasm_rt_jmp_buf; extern void WASM_RT_TRAP_HANDLER(wasm_rt_trap_t code); #endif -#ifdef WASM_RT_GROW_FAILED_HANDLER -extern void WASM_RT_GROW_FAILED_HANDLER(); -#endif - void wasm_rt_trap(wasm_rt_trap_t code) { assert(code != WASM_RT_TRAP_NONE); #if WASM_RT_STACK_DEPTH_COUNT @@ -83,47 +77,6 @@ void wasm_rt_trap(wasm_rt_trap_t code) { } #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); - } -} #if WASM_RT_INSTALL_SIGNAL_HANDLER @@ -148,28 +101,6 @@ static void os_cleanup_signal_handler(void) { #endif #else -#if WASM_RT_USE_MMAP -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) { - return mprotect(addr, size, PROT_READ | PROT_WRITE); -} - -static void os_print_last_error(const char* msg) { - perror(msg); -} -#endif #if WASM_RT_INSTALL_SIGNAL_HANDLER static void os_signal_handler(int sig, siginfo_t* si, void* unused) { @@ -326,113 +257,6 @@ void wasm_rt_free_thread(void) { #endif } -#if WASM_RT_USE_MMAP - -static uint64_t get_allocation_size_for_mmap(wasm_rt_memory_t* memory) { - assert(!memory->is64 && - "memory64 is not yet compatible with WASM_RT_USE_MMAP"); -#if WASM_RT_MEMCHECK_GUARD_PAGES - /* Reserve 8GiB. */ - const uint64_t max_size = 0x200000000ul; - return max_size; -#else - if (memory->max_pages != 0) { - const uint64_t max_size = memory->max_pages * PAGE_SIZE; - return max_size; - } - - /* Reserve 4GiB. */ - const uint64_t max_size = 0x100000000ul; - return max_size; -#endif -} - -#endif - -void wasm_rt_allocate_memory(wasm_rt_memory_t* memory, - uint64_t initial_pages, - uint64_t max_pages, - bool is64) { - uint64_t byte_length = initial_pages * PAGE_SIZE; - memory->size = byte_length; - memory->pages = initial_pages; - memory->max_pages = max_pages; - memory->is64 = is64; - -#if WASM_RT_USE_MMAP - const uint64_t mmap_size = get_allocation_size_for_mmap(memory); - void* addr = os_mmap(mmap_size); - if (!addr) { - os_print_last_error("os_mmap failed."); - abort(); - } - int ret = os_mprotect(addr, byte_length); - if (ret != 0) { - os_print_last_error("os_mprotect failed."); - abort(); - } - memory->data = addr; -#else - memory->data = calloc(byte_length, 1); -#endif -} - -static uint64_t grow_memory_impl(wasm_rt_memory_t* 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 * PAGE_SIZE; - uint64_t new_size = new_pages * PAGE_SIZE; - uint64_t delta_size = delta * PAGE_SIZE; -#if WASM_RT_USE_MMAP - uint8_t* new_data = memory->data; - int ret = os_mprotect(new_data + old_size, delta_size); - if (ret != 0) { - return (uint64_t)-1; - } -#else - uint8_t* new_data = realloc(memory->data, new_size); - if (new_data == NULL) { - return (uint64_t)-1; - } -#if !WABT_BIG_ENDIAN - memset(new_data + old_size, 0, delta_size); -#endif -#endif -#if WABT_BIG_ENDIAN - memmove(new_data + new_size - old_size, new_data, old_size); - memset(new_data, 0, delta_size); -#endif - memory->pages = new_pages; - memory->size = new_size; - memory->data = new_data; - return old_pages; -} - -uint64_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint64_t delta) { - uint64_t ret = grow_memory_impl(memory, delta); -#ifdef WASM_RT_GROW_FAILED_HANDLER - if (ret == -1) { - WASM_RT_GROW_FAILED_HANDLER(); - } -#endif - return ret; -} - -void wasm_rt_free_memory(wasm_rt_memory_t* memory) { -#if WASM_RT_USE_MMAP - const uint64_t mmap_size = get_allocation_size_for_mmap(memory); - os_munmap(memory->data, mmap_size); // ignore error -#else - free(memory->data); -#endif -} - #define DEFINE_TABLE_OPS(type) \ void wasm_rt_allocate_##type##_table(wasm_rt_##type##_table_t* table, \ uint32_t elements, \ diff --git a/wasm2c/wasm-rt-mem-impl-helper.inc b/wasm2c/wasm-rt-mem-impl-helper.inc new file mode 100644 index 00000000..5cd503c7 --- /dev/null +++ b/wasm2c/wasm-rt-mem-impl-helper.inc @@ -0,0 +1,164 @@ +/* + * 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_C11THREADS +#define MEMORY_LOCK_VAR_INIT(name) C11_MEMORY_LOCK_VAR_INIT(name) +#define MEMORY_LOCK_AQUIRE(name) C11_MEMORY_LOCK_AQUIRE(name) +#define MEMORY_LOCK_RELEASE(name) C11_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) +#elif 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) +#endif + +#endif + +void MEMORY_API_NAME(wasm_rt_allocate_memory)(MEMORY_TYPE* memory, + uint64_t initial_pages, + uint64_t max_pages, + bool is64) { + 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_LOCK_VAR_INIT(memory->mem_lock); + +#if WASM_RT_USE_MMAP + const uint64_t mmap_size = + get_alloc_size_for_mmap(memory->max_pages, memory->is64); + void* addr = os_mmap(mmap_size); + if (!addr) { + os_print_last_error("os_mmap failed."); + abort(); + } + int ret = os_mprotect(addr, byte_length); + if (ret != 0) { + os_print_last_error("os_mprotect failed."); + abort(); + } + memory->data = addr; +#else + memory->data = calloc(byte_length, 1); +#endif +} + +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 * PAGE_SIZE; + uint64_t new_size = new_pages * PAGE_SIZE; + uint64_t delta_size = delta * PAGE_SIZE; +#if WASM_RT_USE_MMAP + MEMORY_CELL_TYPE new_data = memory->data; + int ret = os_mprotect((void*)(new_data + old_size), delta_size); + if (ret != 0) { + return (uint64_t)-1; + } +#else + MEMORY_CELL_TYPE new_data = realloc((void*)memory->data, new_size); + if (new_data == NULL) { + return (uint64_t)-1; + } +#if !WABT_BIG_ENDIAN + memset((void*)(new_data + old_size), 0, delta_size); +#endif +#endif +#if WABT_BIG_ENDIAN + memmove(new_data + new_size - old_size, new_data, old_size); + memset(new_data, 0, delta_size); +#endif + memory->pages = new_pages; + memory->size = new_size; + memory->data = new_data; + 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 == -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 + const uint64_t mmap_size = + get_alloc_size_for_mmap(memory->max_pages, memory->is64); + os_munmap((void*)memory->data, mmap_size); // ignore error +#else + free((void*)memory->data); +#endif +} + +#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/wasm2c/wasm-rt-mem-impl.c b/wasm2c/wasm-rt-mem-impl.c new file mode 100644 index 00000000..d29aadad --- /dev/null +++ b/wasm2c/wasm-rt-mem-impl.c @@ -0,0 +1,178 @@ +/* + * 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 <stdio.h> + +#ifdef _WIN32 +#include <windows.h> +#else +#include <sys/mman.h> +#endif + +#define PAGE_SIZE 65536 + +#ifdef WASM_RT_GROW_FAILED_HANDLER +extern void WASM_RT_GROW_FAILED_HANDLER(); +#endif + +#define C11_MEMORY_LOCK_VAR_INIT(name) \ + if (mtx_init(&(name), mtx_plain) != thrd_success) { \ + fprintf(stderr, "Lock init failed\n"); \ + abort(); \ + } +#define C11_MEMORY_LOCK_AQUIRE(name) \ + if (mtx_lock(&(name)) != thrd_success) { \ + fprintf(stderr, "Lock acquire failed\n"); \ + abort(); \ + } +#define C11_MEMORY_LOCK_RELEASE(name) \ + if (mtx_unlock(&(name)) != thrd_success) { \ + fprintf(stderr, "Lock release failed\n"); \ + abort(); \ + } + +#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 +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) { + return mprotect(addr, size, PROT_READ | PROT_WRITE); +} + +static void os_print_last_error(const char* msg) { + perror(msg); +} + +#endif + +static uint64_t get_alloc_size_for_mmap(uint64_t max_pages, bool is64) { + assert(!is64 && "memory64 is not yet compatible with WASM_RT_USE_MMAP"); +#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 * PAGE_SIZE; + return max_size; + } + + /* Reserve 4GiB. */ + const uint64_t max_size = 0x100000000ul; + return max_size; +#endif +} + +#endif + +// 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 +#undef PAGE_SIZE diff --git a/wasm2c/wasm-rt.h b/wasm2c/wasm-rt.h index bd0cd61d..cbd09a31 100644 --- a/wasm2c/wasm-rt.h +++ b/wasm2c/wasm-rt.h @@ -51,9 +51,37 @@ extern "C" { #define wasm_rt_unreachable abort #endif +#ifdef __STDC_VERSION__ +#if __STDC_VERSION__ >= 201112L +#define WASM_RT_C11_AVAILABLE +#endif +#endif + +/** + * Apple and Windows devices don't implement the C11 threads.h. We use pthreads + * on Apple devices, and CriticalSection APIs for Windows. + */ +#ifdef WASM_RT_C11_AVAILABLE + +#ifdef __APPLE__ +#include <pthread.h> +#define WASM_RT_MUTEX pthread_mutex_t +#define WASM_RT_USE_PTHREADS 1 +#elif defined(_WIN32) +#include <windows.h> +#define WASM_RT_MUTEX CRITICAL_SECTION +#define WASM_RT_USE_CRITICALSECTION 1 +#else +#include <threads.h> +#define WASM_RT_MUTEX mtx_t +#define WASM_RT_USE_C11THREADS 1 +#endif + +#endif + #ifdef _MSC_VER #define WASM_RT_THREAD_LOCAL __declspec(thread) -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +#elif defined(WASM_RT_C11_AVAILABLE) #define WASM_RT_THREAD_LOCAL _Thread_local #else #define WASM_RT_THREAD_LOCAL @@ -346,6 +374,33 @@ typedef struct { 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 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; + /** 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`. */ @@ -475,6 +530,26 @@ uint64_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint64_t pages); */ 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); + +/** + * 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`. |