summaryrefslogtreecommitdiff
path: root/wasm2c
diff options
context:
space:
mode:
Diffstat (limited to 'wasm2c')
-rw-r--r--wasm2c/README.md37
-rw-r--r--wasm2c/wasm-rt-impl.c176
-rw-r--r--wasm2c/wasm-rt-mem-impl-helper.inc164
-rw-r--r--wasm2c/wasm-rt-mem-impl.c178
-rw-r--r--wasm2c/wasm-rt.h77
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`.