From 569fdd39ea71f88a89da8a075bdb785906f9bc0a Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 9 Dec 2021 16:38:33 -0500 Subject: [PATCH 1/7] refactor: Use INLINE macro throughout compiletime --- runtime/include/wasm_memory.h | 47 ++++++++++++++++++----------------- runtime/include/wasm_stack.h | 5 ++-- runtime/include/wasm_table.h | 10 +++++--- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/runtime/include/wasm_memory.h b/runtime/include/wasm_memory.h index a142491..d4c4af4 100644 --- a/runtime/include/wasm_memory.h +++ b/runtime/include/wasm_memory.h @@ -19,7 +19,8 @@ struct wasm_memory { uint8_t data[]; }; -static inline struct wasm_memory * + +static INLINE struct wasm_memory * wasm_memory_allocate(size_t initial, size_t max) { assert(initial > 0); @@ -54,20 +55,20 @@ wasm_memory_allocate(size_t initial, size_t max) return self; } -static inline void +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); } -static inline void +static INLINE void wasm_memory_wipe(struct wasm_memory *self) { memset(self->data, 0, self->size); } -static inline int +static INLINE int wasm_memory_expand(struct wasm_memory *self, size_t size_to_expand) { size_t target_size = self->size + size_to_expand; @@ -96,7 +97,7 @@ wasm_memory_expand(struct wasm_memory *self, size_t size_to_expand) * @param bounds_check the size of the thing we are pointing to * @return void pointer to something in WebAssembly linear memory */ -static inline void * +static INLINE void * wasm_memory_get_ptr_void(struct wasm_memory *self, uint32_t offset, uint32_t size) { assert(offset + size <= self->size); @@ -108,7 +109,7 @@ wasm_memory_get_ptr_void(struct wasm_memory *self, uint32_t offset, uint32_t siz * @param offset an offset into the WebAssembly linear memory * @return char at the offset */ -static inline char +static INLINE char wasm_memory_get_char(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(char) <= self->size); @@ -120,7 +121,7 @@ wasm_memory_get_char(struct wasm_memory *self, uint32_t offset) * @param offset an offset into the WebAssembly linear memory * @return float at the offset */ -static inline float +static INLINE float wasm_memory_get_f32(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(float) <= self->size); @@ -132,7 +133,7 @@ wasm_memory_get_f32(struct wasm_memory *self, uint32_t offset) * @param offset an offset into the WebAssembly linear memory * @return double at the offset */ -static inline double +static INLINE double wasm_memory_get_f64(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(double) <= self->size); @@ -144,7 +145,7 @@ wasm_memory_get_f64(struct wasm_memory *self, uint32_t offset) * @param offset an offset into the WebAssembly linear memory * @return int8_t at the offset */ -static inline int8_t +static INLINE int8_t wasm_memory_get_i8(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(int8_t) <= self->size); @@ -156,7 +157,7 @@ wasm_memory_get_i8(struct wasm_memory *self, uint32_t offset) * @param offset an offset into the WebAssembly linear memory * @return int16_t at the offset */ -static inline int16_t +static INLINE int16_t wasm_memory_get_i16(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(int16_t) <= self->size); @@ -168,7 +169,7 @@ wasm_memory_get_i16(struct wasm_memory *self, uint32_t offset) * @param offset an offset into the WebAssembly linear memory * @return int32_t at the offset */ -static inline int32_t +static INLINE int32_t wasm_memory_get_i32(struct wasm_memory *self, uint32_t offset) { assert(offset + sizeof(int32_t) <= self->size); @@ -180,14 +181,14 @@ wasm_memory_get_i32(struct wasm_memory *self, uint32_t offset) * @param offset an offset into the WebAssembly linear memory * @return int32_t at the offset */ -static inline int64_t +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]; } -static inline uint32_t +static INLINE uint32_t wasm_memory_get_page_count(struct wasm_memory *self) { return (uint32_t)(self->size / WASM_PAGE_SIZE); @@ -199,7 +200,7 @@ wasm_memory_get_page_count(struct wasm_memory *self) * @param size the maximum expected length in characters * @return pointer to the string or NULL if max_length is reached without finding null-terminator */ -static inline char * +static INLINE char * wasm_memory_get_string(struct wasm_memory *self, uint32_t offset, uint32_t size) { assert(offset + (sizeof(char) * size) <= self->size); @@ -215,7 +216,7 @@ wasm_memory_get_string(struct wasm_memory *self, uint32_t offset, uint32_t size) * @param offset an offset into the WebAssembly linear memory * @return float at the offset */ -static inline void +static INLINE void wasm_memory_set_f32(struct wasm_memory *self, uint32_t offset, float value) { assert(offset + sizeof(float) <= self->size); @@ -227,7 +228,7 @@ wasm_memory_set_f32(struct wasm_memory *self, uint32_t offset, float value) * @param offset an offset into the WebAssembly linear memory * @return double at the offset */ -static inline void +static INLINE void wasm_memory_set_f64(struct wasm_memory *self, uint32_t offset, double value) { assert(offset + sizeof(double) <= self->size); @@ -239,7 +240,7 @@ wasm_memory_set_f64(struct wasm_memory *self, uint32_t offset, double value) * @param offset an offset into the WebAssembly linear memory * @return int8_t at the offset */ -static inline void +static INLINE void wasm_memory_set_i8(struct wasm_memory *self, uint32_t offset, int8_t value) { assert(offset + sizeof(int8_t) <= self->size); @@ -251,7 +252,7 @@ wasm_memory_set_i8(struct wasm_memory *self, uint32_t offset, int8_t value) * @param offset an offset into the WebAssembly linear memory * @return int16_t at the offset */ -static inline void +static INLINE void wasm_memory_set_i16(struct wasm_memory *self, uint32_t offset, int16_t value) { assert(offset + sizeof(int16_t) <= self->size); @@ -263,7 +264,7 @@ wasm_memory_set_i16(struct wasm_memory *self, uint32_t offset, int16_t value) * @param offset an offset into the WebAssembly linear memory * @return int32_t at the offset */ -static inline void +static INLINE void wasm_memory_set_i32(struct wasm_memory *self, uint32_t offset, int32_t value) { assert(offset + sizeof(int32_t) <= self->size); @@ -275,26 +276,26 @@ wasm_memory_set_i32(struct wasm_memory *self, uint32_t offset, int32_t value) * @param offset an offset into the WebAssembly linear memory * @return int64_t at the offset */ -static inline void +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 +static INLINE void wasm_memory_set_size(struct wasm_memory *self, size_t size) { self->size = size; } -static inline size_t +static INLINE size_t wasm_memory_get_size(struct wasm_memory *self) { return self->size; } -static inline void +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); diff --git a/runtime/include/wasm_stack.h b/runtime/include/wasm_stack.h index dd6c809..52773df 100644 --- a/runtime/include/wasm_stack.h +++ b/runtime/include/wasm_stack.h @@ -5,6 +5,7 @@ #include #include "sandbox_types.h" +#include "types.h" struct wasm_stack { size_t capacity; /* Usable capacity. Excludes size of guard page that we need to free */ @@ -20,7 +21,7 @@ struct wasm_stack { * @param sandbox sandbox that we want to allocate a stack for * @returns 0 on success, -1 on error */ -static inline int +static INLINE int wasm_stack_allocate(struct wasm_stack *stack, size_t capacity) { assert(stack); @@ -56,7 +57,7 @@ err_stack_allocation_failed: goto done; } -static inline void +static INLINE void wasm_stack_free(struct wasm_stack *stack) { assert(stack != NULL); diff --git a/runtime/include/wasm_table.h b/runtime/include/wasm_table.h index 2379f45..e2f19d4 100644 --- a/runtime/include/wasm_table.h +++ b/runtime/include/wasm_table.h @@ -4,6 +4,8 @@ #include #include +#include "types.h" + /* memory also provides the table access functions */ #define INDIRECT_TABLE_SIZE (1 << 10) @@ -18,7 +20,7 @@ struct wasm_table { struct wasm_table_entry data[]; }; -static inline struct wasm_table * +static INLINE struct wasm_table * wasm_table_allocate(size_t capacity) { struct wasm_table *self = (struct wasm_table *)malloc(sizeof(struct wasm_table) @@ -30,14 +32,14 @@ wasm_table_allocate(size_t capacity) return self; } -static inline void +static INLINE void wasm_table_free(struct wasm_table *self) { assert(self != NULL); free(self); } -static inline void * +static INLINE void * wasm_table_get(struct wasm_table *self, uint32_t idx, uint32_t type_id) { assert(self != NULL); @@ -52,7 +54,7 @@ wasm_table_get(struct wasm_table *self, uint32_t idx, uint32_t type_id) return f.func_pointer; } -static inline void +static INLINE void wasm_table_set(struct wasm_table *self, uint32_t idx, uint32_t type_id, char *pointer) { assert(self != NULL); From acff35683a1c8355a7e541f74d0b79d299aab717 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 9 Dec 2021 16:47:23 -0500 Subject: [PATCH 2/7] fix: send_reponse err handling --- runtime/include/client_socket.h | 2 +- runtime/include/current_sandbox_send_response.h | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/runtime/include/client_socket.h b/runtime/include/client_socket.h index f801f5e..3717c10 100644 --- a/runtime/include/client_socket.h +++ b/runtime/include/client_socket.h @@ -40,7 +40,7 @@ typedef void (*void_cb)(void); * @param client_socket - the client we are rejecting * @param buffer - buffer to write to socket * @param on_eagain - cb to execute when client socket returns EAGAIN. If NULL, error out - * @returns 0 + * @returns 0 on success, -1 on error. */ static inline int client_socket_send(int client_socket, const char *buffer, size_t buffer_len, void_cb on_eagain) diff --git a/runtime/include/current_sandbox_send_response.h b/runtime/include/current_sandbox_send_response.h index d61081c..ddccc8f 100644 --- a/runtime/include/current_sandbox_send_response.h +++ b/runtime/include/current_sandbox_send_response.h @@ -40,9 +40,12 @@ current_sandbox_send_response() sandbox->total_time = end_time - sandbox->timestamp_of.request_arrival; /* Send HTTP Response Header and Body */ - http_header_200_write(sandbox->client_socket_descriptor, module_content_type, response_body_size); - client_socket_send(sandbox->client_socket_descriptor, (const char *)response->buffer, response_body_size, - current_sandbox_sleep); + rc = http_header_200_write(sandbox->client_socket_descriptor, module_content_type, response_body_size); + if (rc < 0) goto err; + + rc = client_socket_send(sandbox->client_socket_descriptor, (const char *)response->buffer, response_body_size, + current_sandbox_sleep); + if (rc < 0) goto err; http_total_increment_2xx(); rc = 0; From ae48d1ace6cd42214409abc1d21170f1b399513a Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 9 Dec 2021 17:34:49 -0500 Subject: [PATCH 3/7] fix: Spell environment correctly --- runtime/include/sandbox_functions.h | 2 +- runtime/include/scheduler.h | 4 ++-- runtime/src/sandbox.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 6b1900d..9ad0731 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -14,7 +14,7 @@ struct sandbox *sandbox_new(struct module *module, int socket_descriptor, const struct sockaddr *socket_address, uint64_t request_arrival_timestamp, uint64_t admissions_estimate); -int sandbox_prepare_execution_environemnt(struct sandbox *sandbox); +int sandbox_prepare_execution_environment(struct sandbox *sandbox); void sandbox_free(struct sandbox *sandbox); void sandbox_main(struct sandbox *sandbox); void sandbox_switch_to(struct sandbox *next_sandbox); diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index b4812d9..6d5ad0f 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -85,7 +85,7 @@ scheduler_edf_get_next() if (global_request_scheduler_remove_if_earlier(&global, local_deadline) == 0) { assert(global != NULL); assert(global->absolute_deadline < local_deadline); - sandbox_prepare_execution_environemnt(global); + sandbox_prepare_execution_environment(global); assert(global->state == SANDBOX_INITIALIZED); sandbox_set_as_runnable(global, SANDBOX_INITIALIZED); } @@ -106,7 +106,7 @@ scheduler_fifo_get_next() /* If the local runqueue is empty, pull from global request scheduler */ if (global_request_scheduler_remove(&global) < 0) goto done; - sandbox_prepare_execution_environemnt(global); + sandbox_prepare_execution_environment(global); sandbox_set_as_runnable(global, SANDBOX_INITIALIZED); } else if (local == current_sandbox_get()) { /* Execute Round Robin Scheduling Logic if the head is the current sandbox */ diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index c160a42..e6e7118 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -102,7 +102,7 @@ sandbox_allocate(void) * @returns 0 on success, -1 on error */ int -sandbox_prepare_execution_environemnt(struct sandbox *sandbox) +sandbox_prepare_execution_environment(struct sandbox *sandbox) { assert(sandbox != NULL); From 4b1f9914f7d85890a041c5b4be067c7240e3bdaf Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Fri, 10 Dec 2021 13:52:37 +0000 Subject: [PATCH 4/7] refactor: flatten http buffers --- .../include/current_sandbox_send_response.h | 2 +- runtime/include/sandbox_functions.h | 8 +- runtime/include/sandbox_receive_request.h | 2 +- runtime/include/sandbox_types.h | 4 +- runtime/include/vec_u8.h | 90 +++++++++++++++++-- runtime/src/libc/syscall.c | 11 +-- runtime/src/sandbox.c | 11 +-- 7 files changed, 100 insertions(+), 28 deletions(-) diff --git a/runtime/include/current_sandbox_send_response.h b/runtime/include/current_sandbox_send_response.h index ddccc8f..38f586c 100644 --- a/runtime/include/current_sandbox_send_response.h +++ b/runtime/include/current_sandbox_send_response.h @@ -25,7 +25,7 @@ current_sandbox_send_response() { struct sandbox *sandbox = current_sandbox_get(); assert(sandbox != NULL); - struct vec_u8 *response = sandbox->response; + struct vec_u8 *response = &sandbox->response; assert(response != NULL); int rc; diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 9ad0731..45492d3 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -48,12 +48,8 @@ static inline void sandbox_free_http_buffers(struct sandbox *sandbox) { assert(sandbox); - assert(sandbox->request); - assert(sandbox->response); - vec_u8_free(sandbox->request); - vec_u8_free(sandbox->response); - sandbox->request = NULL; - sandbox->response = NULL; + vec_u8_deinit(&sandbox->request); + vec_u8_deinit(&sandbox->response); } /** diff --git a/runtime/include/sandbox_receive_request.h b/runtime/include/sandbox_receive_request.h index 03a0277..507110e 100644 --- a/runtime/include/sandbox_receive_request.h +++ b/runtime/include/sandbox_receive_request.h @@ -27,7 +27,7 @@ sandbox_receive_request(struct sandbox *sandbox) int rc = 0; - struct vec_u8 *request = sandbox->request; + struct vec_u8 *request = &sandbox->request; assert(request->length == 0); assert(request->capacity > 0); diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index 6267e8f..7495494 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -50,8 +50,8 @@ struct sandbox { int client_socket_descriptor; http_parser http_parser; struct http_request http_request; - struct vec_u8 * request; - struct vec_u8 * response; + struct vec_u8 request; + struct vec_u8 response; /* WebAssembly Module State */ struct module *module; /* the module this is an instance of */ diff --git a/runtime/include/vec_u8.h b/runtime/include/vec_u8.h index 8ac47df..2a43e9e 100644 --- a/runtime/include/vec_u8.h +++ b/runtime/include/vec_u8.h @@ -4,34 +4,108 @@ #include struct vec_u8 { - size_t length; - size_t capacity; - uint8_t buffer[]; + size_t length; + size_t capacity; + uint8_t *buffer; }; +static inline struct vec_u8 *vec_u8_alloc(void); +static inline int vec_u8_init(struct vec_u8 *self, size_t capacity); +static inline struct vec_u8 *vec_u8_new(size_t capacity); +static inline void vec_u8_deinit(struct vec_u8 *self); +static inline void vec_u8_free(struct vec_u8 *self); +static inline void vec_u8_delete(struct vec_u8 *self); + +/** + * Allocates an uninitialized vec on the heap' + * @returns a pointer to an uninitialized vec on the heap + */ static inline struct vec_u8 * -vec_u8_alloc(size_t capacity) +vec_u8_alloc(void) { - return (struct vec_u8 *)calloc(1, sizeof(struct vec_u8) + capacity * sizeof(uint8_t)); + return (struct vec_u8 *)calloc(1, sizeof(struct vec_u8)); } -static inline void +/** + * Initializes a vec, allocating a backing buffer for the provided capcity + * @param self pointer to an uninitialized vec + * @param capacity + * @returns 0 on success, -1 on failure + */ +static inline int vec_u8_init(struct vec_u8 *self, size_t capacity) { + if (capacity == 0) { + self->buffer = NULL; + } else { + self->buffer = calloc(capacity, sizeof(uint8_t)); + if (self->buffer == NULL) return -1; + } + self->length = 0; self->capacity = capacity; + + return 0; } +/** + * Allocate and initialize a vec with a backing buffer + * @param capacity + * @returns a pointer to an initialized vec on the heap, ready for use + */ static inline struct vec_u8 * vec_u8_new(size_t capacity) { - struct vec_u8 *self = vec_u8_alloc(capacity); - vec_u8_init(self, capacity); + struct vec_u8 *self = vec_u8_alloc(); + if (self == NULL) return self; + + int rc = vec_u8_init(self, capacity); + if (rc < 0) { + vec_u8_free(self); + return NULL; + } + return self; } +/** + * Deinitialize a vec, clearing out members and releasing the backing buffer + * @param self + */ +static inline void +vec_u8_deinit(struct vec_u8 *self) +{ + if (self->capacity == 0) { + assert(self->buffer == NULL); + assert(self->length == 0); + } + + free(self->buffer); + self->buffer = NULL; + self->length = 0; + self->capacity = 0; +} + +/** + * Frees a vec struct allocated on the heap + * Assumes that the vec has already been deinitialized + */ static inline void vec_u8_free(struct vec_u8 *self) { + assert(self->buffer == NULL); + assert(self->length == 0); + assert(self->capacity == 0); free(self); } + +/** + * Deinitializes and frees a vec allocated to the heap + * @param self + */ +static inline void +vec_u8_delete(struct vec_u8 *self) +{ + vec_u8_deinit(self); + vec_u8_free(self); +} diff --git a/runtime/src/libc/syscall.c b/runtime/src/libc/syscall.c index 8e71b1b..ba657f8 100644 --- a/runtime/src/libc/syscall.c +++ b/runtime/src/libc/syscall.c @@ -135,18 +135,19 @@ err: int32_t wasm_write(int32_t fd, int32_t buf_offset, int32_t buf_size) { - struct sandbox *s = current_sandbox_get(); - char * buffer = current_sandbox_get_ptr_void(buf_offset, buf_size); + struct sandbox *s = current_sandbox_get(); + char * buffer = current_sandbox_get_ptr_void(buf_offset, buf_size); + struct vec_u8 * response = &s->response; if (fd == STDERR_FILENO) { write(STDERR_FILENO, buffer, buf_size); } if (fd == STDOUT_FILENO) { - int buffer_remaining = s->response->capacity - s->response->length; + int buffer_remaining = response->capacity - response->length; int to_write = buffer_remaining > buf_size ? buf_size : buffer_remaining; if (to_write == 0) return 0; - memcpy(&s->response->buffer[s->response->length], buffer, to_write); - s->response->length += to_write; + memcpy(&response->buffer[response->length], buffer, to_write); + response->length += to_write; return to_write; } diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index e6e7118..eff6c90 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -74,12 +74,13 @@ sandbox_free_stack(struct sandbox *sandbox) static inline int sandbox_allocate_http_buffers(struct sandbox *self) { - self->request = vec_u8_new(self->module->max_request_size); - if (self->request == NULL) return -1; + int rc; + rc = vec_u8_init(&self->request, self->module->max_request_size); + if (rc < 0) return -1; - self->response = vec_u8_new(self->module->max_response_size); - if (self->response == NULL) { - vec_u8_free(self->request); + rc = vec_u8_init(&self->response, self->module->max_response_size); + if (rc < 0) { + vec_u8_deinit(&self->request); return -1; } From 3cf4580b5d503c564a9ecb134115afdd830d0b94 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Fri, 10 Dec 2021 19:33:19 +0000 Subject: [PATCH 5/7] 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 5e67a76..1a498c3 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 eb2b570..cc403ca 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 0000000..73b0ed5 --- /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 45492d3..c35f755 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 4bb0f6f..ae2e77b 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 d4c4af4..d5b5cdb 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 59cd67c..dafd79f 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 350b05a..f28b279 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 0000000..d7b1b35 --- /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 ba657f8..1ceb29b 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 eff6c90..2b52f3a 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; From 57d95388b1f4b04d868e8b2adfd28632885a29c7 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Fri, 10 Dec 2021 19:49:10 +0000 Subject: [PATCH 6/7] refactor: wasm_table --- .vscode/settings.json | 1 + runtime/include/vec_u8.h | 2 ++ runtime/include/wasm_table.h | 68 +++++++++++++++++++++++++++++++----- runtime/src/module.c | 2 +- 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 52765fc..b40a8af 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -102,6 +102,7 @@ "software_interrupt_counts.h": "c", "sandbox_set_as_running_sys.h": "c", "wasm_module_instance.h": "c", + "wasm_table.h": "c" }, "files.exclude": { "**/.git": true, diff --git a/runtime/include/vec_u8.h b/runtime/include/vec_u8.h index 2a43e9e..39b8f54 100644 --- a/runtime/include/vec_u8.h +++ b/runtime/include/vec_u8.h @@ -78,8 +78,10 @@ vec_u8_deinit(struct vec_u8 *self) if (self->capacity == 0) { assert(self->buffer == NULL); assert(self->length == 0); + return; } + assert(self->buffer != NULL); free(self->buffer); self->buffer = NULL; self->length = 0; diff --git a/runtime/include/wasm_table.h b/runtime/include/wasm_table.h index e2f19d4..33b0b50 100644 --- a/runtime/include/wasm_table.h +++ b/runtime/include/wasm_table.h @@ -15,23 +15,73 @@ struct wasm_table_entry { }; struct wasm_table { - uint32_t length; - uint32_t capacity; - struct wasm_table_entry data[]; + uint32_t length; + uint32_t capacity; + struct wasm_table_entry *buffer; }; +static INLINE struct wasm_table *wasm_table_alloc(void); +static INLINE int wasm_table_init(struct wasm_table *self, size_t capacity); +static INLINE struct wasm_table *wasm_table_new(size_t capacity); +static INLINE void wasm_table_deinit(struct wasm_table *self); +static INLINE void wasm_table_free(struct wasm_table *self); +static INLINE void wasm_table_delete(struct wasm_table *self); + static INLINE struct wasm_table * -wasm_table_allocate(size_t capacity) +wasm_table_alloc(void) { - struct wasm_table *self = (struct wasm_table *)malloc(sizeof(struct wasm_table) - + capacity * sizeof(struct wasm_table_entry)); + return (struct wasm_table *)malloc(sizeof(struct wasm_table)); +} + +static INLINE int +wasm_table_init(struct wasm_table *self, size_t capacity) +{ + assert(self != NULL); + + if (capacity > 0) { + self->buffer = calloc(capacity, sizeof(struct wasm_table_entry)); + if (self->buffer == NULL) return -1; + } self->capacity = capacity; self->length = 0; + return 0; +} + +static INLINE struct wasm_table * +wasm_table_new(size_t capacity) +{ + struct wasm_table *self = wasm_table_alloc(); + if (self == NULL) return NULL; + + int rc = wasm_table_init(self, capacity); + if (rc < 0) { + wasm_table_free(self); + return NULL; + } + return self; } +static INLINE void +wasm_table_deinit(struct wasm_table *self) +{ + assert(self != NULL); + + if (self->capacity > 0) { + assert(self->buffer == NULL); + assert(self->length == 0); + return; + } + + assert(self->buffer != NULL); + free(self->buffer); + self->buffer = NULL; + self->length = 0; + self->capacity = 0; +} + static INLINE void wasm_table_free(struct wasm_table *self) { @@ -45,7 +95,7 @@ wasm_table_get(struct wasm_table *self, uint32_t idx, uint32_t type_id) assert(self != NULL); assert(idx < self->capacity); - struct wasm_table_entry f = self->data[idx]; + struct wasm_table_entry f = self->buffer[idx]; // FIXME: Commented out function type check because of gocr // assert(f.type_id == type_id); @@ -62,7 +112,7 @@ wasm_table_set(struct wasm_table *self, uint32_t idx, uint32_t type_id, char *po assert(pointer != NULL); /* TODO: atomic for multiple concurrent invocations? Issue #97 */ - if (self->data[idx].type_id == type_id && self->data[idx].func_pointer == pointer) return; + if (self->buffer[idx].type_id == type_id && self->buffer[idx].func_pointer == pointer) return; - self->data[idx] = (struct wasm_table_entry){ .type_id = type_id, .func_pointer = pointer }; + self->buffer[idx] = (struct wasm_table_entry){ .type_id = type_id, .func_pointer = pointer }; } diff --git a/runtime/src/module.c b/runtime/src/module.c index f4fe23a..8e8ad9a 100644 --- a/runtime/src/module.c +++ b/runtime/src/module.c @@ -186,7 +186,7 @@ module_new(char *name, char *path, uint32_t stack_size, uint32_t max_memory, uin /* WebAssembly Indirect Table */ /* TODO: Should this be part of the module or per-sandbox? */ /* TODO: How should this table be sized? */ - module->indirect_table = wasm_table_allocate(INDIRECT_TABLE_SIZE); + module->indirect_table = wasm_table_new(INDIRECT_TABLE_SIZE); /* Request Response Buffer */ if (request_size == 0) request_size = MODULE_DEFAULT_REQUEST_RESPONSE_SIZE; From 452db10284fce6a062d9fa313ed8b4b5fb33e9db Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Fri, 10 Dec 2021 19:57:33 +0000 Subject: [PATCH 7/7] refactor: wasm_memory_get_string --- runtime/include/wasm_memory.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/runtime/include/wasm_memory.h b/runtime/include/wasm_memory.h index d5b5cdb..4114977 100644 --- a/runtime/include/wasm_memory.h +++ b/runtime/include/wasm_memory.h @@ -283,10 +283,11 @@ 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->buffer[offset + i] == '\0') return (char *)&self->buffer[offset]; + if (strnlen((const char *)&self->buffer[offset], size) < size) { + return (char *)&self->buffer[offset]; + } else { + return NULL; } - return NULL; } /**