From 3cf4580b5d503c564a9ecb134115afdd830d0b94 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Fri, 10 Dec 2021 19:33:19 +0000 Subject: [PATCH] refactor: wasm_memory --- runtime/compiletime/memory_instructions.c | 86 ++++++--- runtime/include/current_sandbox.h | 28 +-- .../include/current_wasm_module_instance.h | 7 + runtime/include/sandbox_functions.h | 2 +- runtime/include/sandbox_setup_arguments.h | 7 +- runtime/include/wasm_memory.h | 181 ++++++++++++------ runtime/include/wasm_module_instance.h | 6 +- runtime/src/current_sandbox.c | 5 - runtime/src/current_wasm_module_instance.c | 28 +++ runtime/src/libc/syscall.c | 14 +- runtime/src/sandbox.c | 2 +- 11 files changed, 245 insertions(+), 121 deletions(-) create mode 100644 runtime/include/current_wasm_module_instance.h create mode 100644 runtime/src/current_wasm_module_instance.c diff --git a/runtime/compiletime/memory_instructions.c b/runtime/compiletime/memory_instructions.c index 5e67a7691..1a498c3fc 100644 --- a/runtime/compiletime/memory_instructions.c +++ b/runtime/compiletime/memory_instructions.c @@ -1,48 +1,60 @@ #include -#include "wasm_module_instance.h" +#include "current_wasm_module_instance.h" INLINE uint32_t instruction_memory_size() { - return wasm_memory_get_page_count(current_wasm_module_instance.memory); + return (uint32_t)(current_wasm_module_instance.memory.size / WASM_PAGE_SIZE); } -// All of these are pretty generic +// These functions are equivalent to those in wasm_memory.h, but they minimize pointer dereferencing INLINE float get_f32(uint32_t offset) { - return wasm_memory_get_f32(current_wasm_module_instance.memory, offset); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(float) <= current_wasm_module_instance.memory.size); + return *(float *)¤t_wasm_module_instance.memory.buffer[offset]; } INLINE double get_f64(uint32_t offset) { - return wasm_memory_get_f64(current_wasm_module_instance.memory, offset); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(double) <= current_wasm_module_instance.memory.size); + return *(double *)¤t_wasm_module_instance.memory.buffer[offset]; } INLINE int8_t get_i8(uint32_t offset) { - return wasm_memory_get_i8(current_wasm_module_instance.memory, offset); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(int8_t) <= current_wasm_module_instance.memory.size); + return *(int8_t *)¤t_wasm_module_instance.memory.buffer[offset]; } INLINE int16_t get_i16(uint32_t offset) { - return wasm_memory_get_i16(current_wasm_module_instance.memory, offset); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(int16_t) <= current_wasm_module_instance.memory.size); + return *(int16_t *)¤t_wasm_module_instance.memory.buffer[offset]; } INLINE int32_t get_i32(uint32_t offset) { - return wasm_memory_get_i32(current_wasm_module_instance.memory, offset); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(int32_t) <= current_wasm_module_instance.memory.size); + return *(int32_t *)¤t_wasm_module_instance.memory.buffer[offset]; } INLINE int64_t get_i64(uint32_t offset) { - return wasm_memory_get_i64(current_wasm_module_instance.memory, offset); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(int64_t) <= current_wasm_module_instance.memory.size); + return *(int64_t *)¤t_wasm_module_instance.memory.buffer[offset]; } INLINE int32_t @@ -59,51 +71,65 @@ get_global_i64(uint32_t offset) // Now setting routines INLINE void -set_f32(uint32_t offset, float v) +set_f32(uint32_t offset, float value) { - wasm_memory_set_f32(current_wasm_module_instance.memory, offset, v); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(float) <= current_wasm_module_instance.memory.size); + *(float *)¤t_wasm_module_instance.memory.buffer[offset] = value; } INLINE void -set_f64(uint32_t offset, double v) +set_f64(uint32_t offset, double value) { - wasm_memory_set_f64(current_wasm_module_instance.memory, offset, v); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(double) <= current_wasm_module_instance.memory.size); + *(double *)¤t_wasm_module_instance.memory.buffer[offset] = value; } INLINE void -set_i8(uint32_t offset, int8_t v) +set_i8(uint32_t offset, int8_t value) { - wasm_memory_set_i8(current_wasm_module_instance.memory, offset, v); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(int8_t) <= current_wasm_module_instance.memory.size); + *(int8_t *)¤t_wasm_module_instance.memory.buffer[offset] = value; } INLINE void -set_i16(uint32_t offset, int16_t v) +set_i16(uint32_t offset, int16_t value) { - wasm_memory_set_i16(current_wasm_module_instance.memory, offset, v); + assert(current_wasm_module_instance.memory.buffer != NULL); + + assert(offset + sizeof(int16_t) <= current_wasm_module_instance.memory.size); + *(int16_t *)¤t_wasm_module_instance.memory.buffer[offset] = value; } INLINE void -set_i32(uint32_t offset, int32_t v) +set_i32(uint32_t offset, int32_t value) { - wasm_memory_set_i32(current_wasm_module_instance.memory, offset, v); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(int32_t) <= current_wasm_module_instance.memory.size); + *(int32_t *)¤t_wasm_module_instance.memory.buffer[offset] = value; } INLINE void -set_i64(uint32_t offset, int64_t v) +set_i64(uint32_t offset, int64_t value) { - wasm_memory_set_i64(current_wasm_module_instance.memory, offset, v); + assert(current_wasm_module_instance.memory.buffer != NULL); + assert(offset + sizeof(int64_t) <= current_wasm_module_instance.memory.size); + *(int64_t *)¤t_wasm_module_instance.memory.buffer[offset] = value; } INLINE void -set_global_i32(uint32_t offset, int32_t v) +set_global_i32(uint32_t offset, int32_t value) { - set_i32(offset, v); + set_i32(offset, value); } INLINE void -set_global_i64(uint32_t offset, int64_t v) +set_global_i64(uint32_t offset, int64_t value) { - set_i64(offset, v); + set_i64(offset, value); } /** @@ -115,12 +141,15 @@ set_global_i64(uint32_t offset, int64_t v) INLINE int32_t instruction_memory_grow(uint32_t count) { - int old_page_count = current_wasm_module_instance.memory->size / WASM_PAGE_SIZE; + int old_page_count = current_wasm_module_instance.memory.size / WASM_PAGE_SIZE; /* Return -1 if we've hit the linear memory max */ - int rc = wasm_memory_expand(current_wasm_module_instance.memory, WASM_PAGE_SIZE * count); + int rc = wasm_memory_expand(¤t_wasm_module_instance.memory, WASM_PAGE_SIZE * count); if (unlikely(rc == -1)) return -1; + /* We updated "forked state" in current_wasm_module_instance.memory. We need to write this back to persist */ + current_wasm_module_instance_memory_writeback(); + #ifdef LOG_SANDBOX_MEMORY_PROFILE // Cache the runtime of the first N page allocations for (int i = 0; i < count; i++) { @@ -131,7 +160,6 @@ instruction_memory_grow(uint32_t count) } } #endif - return rc; } @@ -139,5 +167,5 @@ instruction_memory_grow(uint32_t count) INLINE void initialize_region(uint32_t offset, uint32_t region_size, uint8_t region[region_size]) { - wasm_memory_initialize_region(current_wasm_module_instance.memory, offset, region_size, region); + wasm_memory_initialize_region(¤t_wasm_module_instance.memory, offset, region_size, region); } diff --git a/runtime/include/current_sandbox.h b/runtime/include/current_sandbox.h index eb2b57083..cc403ca7b 100644 --- a/runtime/include/current_sandbox.h +++ b/runtime/include/current_sandbox.h @@ -3,7 +3,7 @@ #include #include "sandbox_types.h" -#include "wasm_module_instance.h" +#include "current_wasm_module_instance.h" /* current sandbox that is active.. */ extern thread_local struct sandbox *worker_thread_current_sandbox; @@ -30,16 +30,20 @@ current_sandbox_set(struct sandbox *sandbox) /* Unpack hierarchy to avoid pointer chasing */ if (sandbox == NULL) { current_wasm_module_instance = (struct wasm_module_instance){ - .memory = NULL, - .table = NULL, + .memory = + (struct wasm_memory){ + .size = 0, + .capacity = 0, + .max = 0, + .buffer = NULL, + }, + .table = NULL, }; worker_thread_current_sandbox = NULL; runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX; } else { - current_wasm_module_instance = (struct wasm_module_instance){ - .memory = sandbox->memory, - .table = sandbox->module->indirect_table, - }; + memcpy(¤t_wasm_module_instance.memory, sandbox->memory, sizeof(struct wasm_memory)); + current_wasm_module_instance.table = sandbox->module->indirect_table, worker_thread_current_sandbox = sandbox; runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline; } @@ -51,19 +55,19 @@ extern void current_sandbox_sleep(); static inline void * current_sandbox_get_ptr_void(uint32_t offset, uint32_t bounds_check) { - assert(current_wasm_module_instance.memory != NULL); - return wasm_memory_get_ptr_void(current_wasm_module_instance.memory, offset, bounds_check); + assert(current_wasm_module_instance.memory.capacity > 0); + return wasm_memory_get_ptr_void(¤t_wasm_module_instance.memory, offset, bounds_check); } static inline char current_sandbox_get_char(uint32_t offset) { - assert(current_wasm_module_instance.memory != NULL); - return wasm_memory_get_char(current_wasm_module_instance.memory, offset); + assert(current_wasm_module_instance.memory.capacity > 0); + return wasm_memory_get_char(¤t_wasm_module_instance.memory, offset); } static inline char * current_sandbox_get_string(uint32_t offset, uint32_t size) { - return wasm_memory_get_string(current_wasm_module_instance.memory, offset, size); + return wasm_memory_get_string(¤t_wasm_module_instance.memory, offset, size); } diff --git a/runtime/include/current_wasm_module_instance.h b/runtime/include/current_wasm_module_instance.h new file mode 100644 index 000000000..73b0ed59b --- /dev/null +++ b/runtime/include/current_wasm_module_instance.h @@ -0,0 +1,7 @@ +#pragma once + +#include "wasm_module_instance.h" + +extern thread_local struct wasm_module_instance current_wasm_module_instance; + +extern void current_wasm_module_instance_memory_writeback(void); diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 45492d397..c35f7551f 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -36,7 +36,7 @@ sandbox_close_http(struct sandbox *sandbox) static inline void sandbox_free_linear_memory(struct sandbox *sandbox) { - wasm_memory_free(sandbox->memory); + wasm_memory_delete(sandbox->memory); sandbox->memory = NULL; } diff --git a/runtime/include/sandbox_setup_arguments.h b/runtime/include/sandbox_setup_arguments.h index 4bb0f6f2e..ae2e77bd1 100644 --- a/runtime/include/sandbox_setup_arguments.h +++ b/runtime/include/sandbox_setup_arguments.h @@ -22,8 +22,13 @@ sandbox_setup_arguments(struct sandbox *sandbox) * WASI, so not worth fixing*/ sandbox->arguments_offset = wasm_memory_get_size(sandbox->memory); - int rc = wasm_memory_expand(sandbox->memory, WASM_PAGE_SIZE); + + /* Assumption: we can fit the arguments in a single wasm page */ + int rc = wasm_memory_expand(sandbox->memory, WASM_PAGE_SIZE); assert(rc == 0); + /* We have to update our cache here */ + memcpy(¤t_wasm_module_instance.memory, sandbox->memory, sizeof(struct wasm_memory)); + stub_init(sandbox->arguments_offset); } diff --git a/runtime/include/wasm_memory.h b/runtime/include/wasm_memory.h index d4c4af4c4..d5b5cdb83 100644 --- a/runtime/include/wasm_memory.h +++ b/runtime/include/wasm_memory.h @@ -10,62 +10,113 @@ #include "types.h" /* PAGE_SIZE */ #include "wasm_types.h" -#define WASM_MEMORY_MAX (size_t) UINT32_MAX + 1 +#define WASM_MEMORY_MAX (size_t) UINT32_MAX + 1 +#define WASM_MEMORY_SIZE_TO_ALLOC ((size_t)WASM_MEMORY_MAX + /* guard page */ PAGE_SIZE) struct wasm_memory { - size_t size; /* Initial Size in bytes */ - size_t capacity; /* Size backed by actual pages */ - size_t max; /* Soft cap in bytes. Defaults to 4GB */ - uint8_t data[]; + size_t size; /* Initial Size in bytes */ + size_t capacity; /* Size backed by actual pages */ + size_t max; /* Soft cap in bytes. Defaults to 4GB */ + uint8_t *buffer; }; +static INLINE struct wasm_memory *wasm_memory_alloc(void); +static INLINE int wasm_memory_init(struct wasm_memory *self, size_t initial, size_t max); +static INLINE struct wasm_memory *wasm_memory_new(size_t initial, size_t max); +static INLINE void wasm_memory_deinit(struct wasm_memory *self); +static INLINE void wasm_memory_free(struct wasm_memory *self); +static INLINE void wasm_memory_delete(struct wasm_memory *self); + static INLINE struct wasm_memory * -wasm_memory_allocate(size_t initial, size_t max) +wasm_memory_alloc(void) +{ + return malloc(sizeof(struct wasm_memory)); +} + +static INLINE int +wasm_memory_init(struct wasm_memory *self, size_t initial, size_t max) { + assert(self != NULL); + + /* We assume WASI modules, which are required to declare and export a linear memory with a non-zero size to + * allow a standard lib to initialize. Technically, a WebAssembly module that exports pure functions may not use + * a linear memory */ assert(initial > 0); assert(initial <= (size_t)UINT32_MAX + 1); assert(max > 0); assert(max <= (size_t)UINT32_MAX + 1); - /* Allocate contiguous virtual addresses for struct, full linear memory, and guard page */ - size_t size_to_alloc = sizeof(struct wasm_memory) + WASM_MEMORY_MAX + /* guard page */ PAGE_SIZE; - void * temp = mmap(NULL, size_to_alloc, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (temp == MAP_FAILED) { - fprintf(stderr, "wasm_memory_allocate - allocation failed, (size: %lu) %s\n", size_to_alloc, - strerror(errno)); - return NULL; - } - struct wasm_memory *self = (struct wasm_memory *)temp; - - /* Set the struct and initial pages to read / write */ - size_t size_to_read_write = sizeof(struct wasm_memory) + initial; + /* Allocate buffer of contiguous virtual addresses for full wasm32 linear memory and guard page */ + self->buffer = mmap(NULL, WASM_MEMORY_SIZE_TO_ALLOC, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (self->buffer == MAP_FAILED) return -1; - int rc = mprotect(self, size_to_read_write, PROT_READ | PROT_WRITE); + /* Set the initial bytes to read / write */ + int rc = mprotect(self->buffer, initial, PROT_READ | PROT_WRITE); if (rc != 0) { - perror("wasm_memory_allocate - prot r/w failed"); - munmap(self, size_to_alloc); - assert(0); - return NULL; + munmap(self->buffer, WASM_MEMORY_SIZE_TO_ALLOC); + return -1; } self->size = initial; self->capacity = initial; self->max = max; + + return 0; +} + +static INLINE struct wasm_memory * +wasm_memory_new(size_t initial, size_t max) +{ + struct wasm_memory *self = wasm_memory_alloc(); + if (self == NULL) return self; + + int rc = wasm_memory_init(self, initial, max); + if (rc < 0) { + assert(0); + wasm_memory_free(self); + return NULL; + } + return self; } +static INLINE void +wasm_memory_deinit(struct wasm_memory *self) +{ + assert(self != NULL); + assert(self->buffer != NULL); + + munmap(self->buffer, WASM_MEMORY_SIZE_TO_ALLOC); + self->buffer = NULL; + self->size = 0; + self->capacity = 0; + self->max = 0; +} + static INLINE void wasm_memory_free(struct wasm_memory *self) { - size_t size_to_free = sizeof(struct wasm_memory) + WASM_MEMORY_MAX + /* guard page */ PAGE_SIZE; - munmap(self, size_to_free); + assert(self != NULL); + /* Assume prior deinitialization so we don't leak buffers */ + assert(self->buffer == NULL); + + free(self); +} + +static INLINE void +wasm_memory_delete(struct wasm_memory *self) +{ + assert(self != NULL); + + wasm_memory_deinit(self); + wasm_memory_free(self); } static INLINE void wasm_memory_wipe(struct wasm_memory *self) { - memset(self->data, 0, self->size); + memset(self->buffer, 0, self->size); } static INLINE int @@ -77,8 +128,13 @@ wasm_memory_expand(struct wasm_memory *self, size_t size_to_expand) return -1; } + /* If recycling a wasm_memory from an object pool, a previous execution may have already expanded to or what + * beyond what we need. The capacity represents the "high water mark" of previous executions. If the desired + * size is less than this "high water mark," we just need to update size for accounting purposes. Otherwise, we + * need to actually issue an mprotect syscall. The goal of these optimizations is to reduce mmap and demand + * paging overhead for repeated instantiations of a WebAssembly module. */ if (target_size > self->capacity) { - int rc = mprotect(self, sizeof(struct wasm_memory) + target_size, PROT_READ | PROT_WRITE); + int rc = mprotect(self->buffer, target_size, PROT_READ | PROT_WRITE); if (rc != 0) { perror("wasm_memory_expand mprotect"); return -1; @@ -91,6 +147,28 @@ wasm_memory_expand(struct wasm_memory *self, size_t size_to_expand) return 0; } +static INLINE void +wasm_memory_set_size(struct wasm_memory *self, size_t size) +{ + self->size = size; +} + +static INLINE size_t +wasm_memory_get_size(struct wasm_memory *self) +{ + return self->size; +} + +static INLINE void +wasm_memory_initialize_region(struct wasm_memory *self, uint32_t offset, uint32_t region_size, uint8_t region[]) +{ + assert((size_t)offset + region_size <= self->size); + memcpy(&self->buffer[offset], region, region_size); +} + +/* NOTE: These wasm_memory functions require pointer dereferencing. For this reason, they are not directly by wasm32 + * instructions. These functions are intended to be used by the runtime to interacts with linear memories. */ + /** * Translates WASM offsets into runtime VM pointers * @param offset an offset into the WebAssembly linear memory @@ -101,7 +179,7 @@ static INLINE void * wasm_memory_get_ptr_void(struct wasm_memory *self, uint32_t offset, uint32_t size) { assert(offset + size <= self->size); - return (void *)&self->data[offset]; + return (void *)&self->buffer[offset]; } /** @@ -113,7 +191,7 @@ static INLINE char wasm_memory_get_char(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(char) <= self->size); - return *(char *)&self->data[offset]; + return *(char *)&self->buffer[offset]; } /** @@ -125,7 +203,7 @@ static INLINE float wasm_memory_get_f32(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(float) <= self->size); - return *(float *)&self->data[offset]; + return *(float *)&self->buffer[offset]; } /** @@ -137,7 +215,7 @@ static INLINE double wasm_memory_get_f64(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(double) <= self->size); - return *(double *)&self->data[offset]; + return *(double *)&self->buffer[offset]; } /** @@ -149,7 +227,7 @@ static INLINE int8_t wasm_memory_get_i8(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(int8_t) <= self->size); - return *(int8_t *)&self->data[offset]; + return *(int8_t *)&self->buffer[offset]; } /** @@ -161,7 +239,7 @@ static INLINE int16_t wasm_memory_get_i16(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(int16_t) <= self->size); - return *(int16_t *)&self->data[offset]; + return *(int16_t *)&self->buffer[offset]; } /** @@ -173,7 +251,7 @@ static INLINE int32_t wasm_memory_get_i32(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(int32_t) <= self->size); - return *(int32_t *)&self->data[offset]; + return *(int32_t *)&self->buffer[offset]; } /** @@ -185,7 +263,7 @@ static INLINE int64_t wasm_memory_get_i64(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(int64_t) <= self->size); - return *(int64_t *)&self->data[offset]; + return *(int64_t *)&self->buffer[offset]; } static INLINE uint32_t @@ -206,7 +284,7 @@ wasm_memory_get_string(struct wasm_memory *self, uint32_t offset, uint32_t size) assert(offset + (sizeof(char) * size) <= self->size); for (uint32_t i = 0; i < size; i++) { - if (self->data[offset + i] == '\0') return (char *)&self->data[offset]; + if (self->buffer[offset + i] == '\0') return (char *)&self->buffer[offset]; } return NULL; } @@ -220,7 +298,7 @@ static INLINE void wasm_memory_set_f32(struct wasm_memory *self, uint32_t offset, float value) { assert(offset + sizeof(float) <= self->size); - *(float *)&self->data[offset] = value; + *(float *)&self->buffer[offset] = value; } /** @@ -232,7 +310,7 @@ static INLINE void wasm_memory_set_f64(struct wasm_memory *self, uint32_t offset, double value) { assert(offset + sizeof(double) <= self->size); - *(double *)&self->data[offset] = value; + *(double *)&self->buffer[offset] = value; } /** @@ -244,7 +322,7 @@ static INLINE void wasm_memory_set_i8(struct wasm_memory *self, uint32_t offset, int8_t value) { assert(offset + sizeof(int8_t) <= self->size); - *(int8_t *)&self->data[offset] = value; + *(int8_t *)&self->buffer[offset] = value; } /** @@ -256,7 +334,7 @@ static INLINE void wasm_memory_set_i16(struct wasm_memory *self, uint32_t offset, int16_t value) { assert(offset + sizeof(int16_t) <= self->size); - *(int16_t *)&self->data[offset] = value; + *(int16_t *)&self->buffer[offset] = value; } /** @@ -268,7 +346,7 @@ static INLINE void wasm_memory_set_i32(struct wasm_memory *self, uint32_t offset, int32_t value) { assert(offset + sizeof(int32_t) <= self->size); - *(int32_t *)&self->data[offset] = value; + *(int32_t *)&self->buffer[offset] = value; } /** @@ -280,24 +358,5 @@ static INLINE void wasm_memory_set_i64(struct wasm_memory *self, uint64_t offset, int64_t value) { assert(offset + sizeof(int64_t) <= self->size); - *(int64_t *)&self->data[offset] = value; -} - -static INLINE void -wasm_memory_set_size(struct wasm_memory *self, size_t size) -{ - self->size = size; -} - -static INLINE size_t -wasm_memory_get_size(struct wasm_memory *self) -{ - return self->size; -} - -static INLINE void -wasm_memory_initialize_region(struct wasm_memory *self, uint32_t offset, uint32_t region_size, uint8_t region[]) -{ - assert((size_t)offset + region_size <= self->size); - memcpy(&self->data[offset], region, region_size); + *(int64_t *)&self->buffer[offset] = value; } diff --git a/runtime/include/wasm_module_instance.h b/runtime/include/wasm_module_instance.h index 59cd67c37..dafd79fde 100644 --- a/runtime/include/wasm_module_instance.h +++ b/runtime/include/wasm_module_instance.h @@ -7,8 +7,6 @@ * entities https://webassembly.github.io/spec/core/exec/runtime.html#module-instances */ struct wasm_module_instance { - struct wasm_memory *memory; - struct wasm_table * table; + struct wasm_memory memory; + struct wasm_table *table; }; - -extern thread_local struct wasm_module_instance current_wasm_module_instance; diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index 350b05afd..f28b279fd 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -16,11 +16,6 @@ thread_local struct sandbox *worker_thread_current_sandbox = NULL; -thread_local struct wasm_module_instance current_wasm_module_instance = { - .memory = NULL, - .table = NULL, -}; - /** * @brief Switches from an executing sandbox to the worker thread base context * diff --git a/runtime/src/current_wasm_module_instance.c b/runtime/src/current_wasm_module_instance.c new file mode 100644 index 000000000..d7b1b3587 --- /dev/null +++ b/runtime/src/current_wasm_module_instance.c @@ -0,0 +1,28 @@ +#include + +#include "current_sandbox.h" +#include "wasm_module_instance.h" +#include "wasm_memory.h" + +thread_local struct wasm_module_instance current_wasm_module_instance = { + .memory = + (struct wasm_memory){ + .size = 0, + .max = 0, + .capacity = 0, + .buffer = NULL, + }, + .table = NULL, +}; + +/** + * Because we copy the members of a sandbox when it is set to current_sandbox, current_wasm_module_instance acts as a + * cache. If we change state by doing something like expanding a member, we have to perform writeback on the sandbox + * member that we copied from. + */ +void +current_wasm_module_instance_memory_writeback(void) +{ + struct sandbox *current_sandbox = current_sandbox_get(); + memcpy(current_sandbox->memory, ¤t_wasm_module_instance.memory, sizeof(struct wasm_memory)); +} diff --git a/runtime/src/libc/syscall.c b/runtime/src/libc/syscall.c index ba657f8b4..1ceb29b39 100644 --- a/runtime/src/libc/syscall.c +++ b/runtime/src/libc/syscall.c @@ -223,8 +223,8 @@ wasm_mmap(int32_t addr, int32_t len, int32_t prot, int32_t flags, int32_t fd, in assert(len % WASM_PAGE_SIZE == 0); - int32_t result = wasm_memory_get_size(current_wasm_module_instance.memory); - if (wasm_memory_expand(current_wasm_module_instance.memory, len) == -1) { result = (uint32_t)-1; } + int32_t result = wasm_memory_get_size(¤t_wasm_module_instance.memory); + if (wasm_memory_expand(¤t_wasm_module_instance.memory, len) == -1) { result = (uint32_t)-1; } return result; } @@ -321,18 +321,18 @@ wasm_mremap(int32_t offset, int32_t old_size, int32_t new_size, int32_t flags) if (new_size <= old_size) return offset; // If at end of linear memory, just expand and return same address - if (offset + old_size == current_wasm_module_instance.memory->size) { + if (offset + old_size == current_wasm_module_instance.memory.size) { int32_t amount_to_expand = new_size - old_size; - wasm_memory_expand(current_wasm_module_instance.memory, amount_to_expand); + wasm_memory_expand(¤t_wasm_module_instance.memory, amount_to_expand); return offset; } // Otherwise allocate at end of address space and copy - int32_t new_offset = current_wasm_module_instance.memory->size; - wasm_memory_expand(current_wasm_module_instance.memory, new_size); + int32_t new_offset = current_wasm_module_instance.memory.size; + wasm_memory_expand(¤t_wasm_module_instance.memory, new_size); // Get pointer of old offset and pointer of new offset - uint8_t *linear_mem = current_wasm_module_instance.memory->data; + uint8_t *linear_mem = current_wasm_module_instance.memory.buffer; uint8_t *src = &linear_mem[offset]; uint8_t *dest = &linear_mem[new_offset]; diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index eff6c90d5..2b52f3a16 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -43,7 +43,7 @@ sandbox_allocate_linear_memory(struct sandbox *sandbox) assert(initial <= (size_t)UINT32_MAX + 1); assert(max <= (size_t)UINT32_MAX + 1); - sandbox->memory = wasm_memory_allocate(initial, max); + sandbox->memory = wasm_memory_new(initial, max); if (unlikely(sandbox->memory == NULL)) return -1; return 0;