Merge branch 'spec-alignment-2' of github.com:gwsystems/sledge-serverless-framework into object-pool

master
Sean McBride 3 years ago
commit a446ed077a

@ -102,7 +102,8 @@
"software_interrupt_counts.h": "c",
"sandbox_set_as_running_sys.h": "c",
"wasm_module_instance.h": "c",
"wasm_stack.h": "c"
"wasm_stack.h": "c",
"wasm_table.h": "c"
},
"files.exclude": {
"**/.git": true,

@ -1,48 +1,60 @@
#include <assert.h>
#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 *)&current_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 *)&current_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 *)&current_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 *)&current_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 *)&current_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 *)&current_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 *)&current_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 *)&current_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 *)&current_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 *)&current_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 *)&current_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 *)&current_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(&current_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(&current_wasm_module_instance.memory, offset, region_size, region);
}

@ -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)

@ -3,7 +3,7 @@
#include <threads.h>
#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(&current_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(&current_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(&current_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(&current_wasm_module_instance.memory, offset, size);
}

@ -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;
@ -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;

@ -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);

@ -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);
@ -50,12 +50,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);
}
/**

@ -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);

@ -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(&current_wasm_module_instance.memory, sandbox->memory, sizeof(struct wasm_memory));
stub_init(sandbox->arguments_offset);
}

@ -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 */

@ -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 */

@ -4,34 +4,110 @@
#include <stdlib.h>
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);
return;
}
assert(self->buffer != NULL);
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);
}

@ -11,73 +11,125 @@
#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 {
struct ps_list list; /* Linked List Node used for object pool */
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[];
uint8_t * buffer;
};
static inline struct wasm_memory *
wasm_memory_new(size_t initial, size_t max)
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_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_new - 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_new - prot r/w failed");
munmap(self, size_to_alloc);
assert(0);
return NULL;
munmap(self->buffer, WASM_MEMORY_SIZE_TO_ALLOC);
return -1;
}
ps_list_init_d(self);
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
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)
{
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)
{
size_t size_to_free = sizeof(struct wasm_memory) + WASM_MEMORY_MAX + /* guard page */ PAGE_SIZE;
munmap(self, size_to_free);
assert(self != NULL);
wasm_memory_deinit(self);
wasm_memory_free(self);
}
static inline void
static INLINE void
wasm_memory_wipe(struct wasm_memory *self)
{
memset(self->data, 0, self->size);
memset(self->buffer, 0, self->size);
}
static inline void
static INLINE void
wasm_memory_reinit(struct wasm_memory *self, size_t initial)
{
wasm_memory_wipe(self);
self->size = initial;
}
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;
@ -86,8 +138,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;
@ -100,17 +157,39 @@ 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
* @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);
return (void *)&self->data[offset];
return (void *)&self->buffer[offset];
}
/**
@ -118,11 +197,11 @@ 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);
return *(char *)&self->data[offset];
return *(char *)&self->buffer[offset];
}
/**
@ -130,11 +209,11 @@ 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);
return *(float *)&self->data[offset];
return *(float *)&self->buffer[offset];
}
/**
@ -142,11 +221,11 @@ 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);
return *(double *)&self->data[offset];
return *(double *)&self->buffer[offset];
}
/**
@ -154,11 +233,11 @@ 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);
return *(int8_t *)&self->data[offset];
return *(int8_t *)&self->buffer[offset];
}
/**
@ -166,11 +245,11 @@ 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);
return *(int16_t *)&self->data[offset];
return *(int16_t *)&self->buffer[offset];
}
/**
@ -178,11 +257,11 @@ 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);
return *(int32_t *)&self->data[offset];
return *(int32_t *)&self->buffer[offset];
}
/**
@ -190,14 +269,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];
return *(int64_t *)&self->buffer[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);
@ -209,15 +288,16 @@ 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);
for (uint32_t i = 0; i < size; i++) {
if (self->data[offset + i] == '\0') return (char *)&self->data[offset];
if (strnlen((const char *)&self->buffer[offset], size) < size) {
return (char *)&self->buffer[offset];
} else {
return NULL;
}
return NULL;
}
/**
@ -225,11 +305,11 @@ 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);
*(float *)&self->data[offset] = value;
*(float *)&self->buffer[offset] = value;
}
/**
@ -237,11 +317,11 @@ 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);
*(double *)&self->data[offset] = value;
*(double *)&self->buffer[offset] = value;
}
/**
@ -249,11 +329,11 @@ 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);
*(int8_t *)&self->data[offset] = value;
*(int8_t *)&self->buffer[offset] = value;
}
/**
@ -261,11 +341,11 @@ 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);
*(int16_t *)&self->data[offset] = value;
*(int16_t *)&self->buffer[offset] = value;
}
/**
@ -273,11 +353,11 @@ 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);
*(int32_t *)&self->data[offset] = value;
*(int32_t *)&self->buffer[offset] = value;
}
/**
@ -285,28 +365,9 @@ 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
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;
}

@ -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;

@ -4,8 +4,9 @@
#include <stdlib.h>
#include <sys/mman.h>
/* This structure is not suitable for a flexible array member because it allocates a guard page beneath the buffer. This
* negates the benefit of tight locality */
#include "sandbox_types.h"
#include "types.h"
struct wasm_stack {
struct ps_list list; /* Linked List Node used for object pool */
size_t capacity; /* Usable capacity. Excludes size of guard page that we need to free */
@ -64,7 +65,7 @@ err_stack_allocation_failed:
goto done;
}
static inline void
static INLINE void
wasm_stack_free(struct wasm_stack *self)
{
free(self);

@ -4,6 +4,8 @@
#include <stdint.h>
#include <stdlib.h>
#include "types.h"
/* memory also provides the table access functions */
#define INDIRECT_TABLE_SIZE (1 << 10)
@ -13,37 +15,87 @@ 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_allocate(size_t capacity)
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_alloc(void)
{
return (struct wasm_table *)malloc(sizeof(struct wasm_table));
}
static INLINE int
wasm_table_init(struct wasm_table *self, size_t capacity)
{
struct wasm_table *self = (struct wasm_table *)malloc(sizeof(struct wasm_table)
+ capacity * sizeof(struct wasm_table_entry));
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
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)
{
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);
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);
@ -52,7 +104,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);
@ -60,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 };
}

@ -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
*

@ -0,0 +1,28 @@
#include <stdlib.h>
#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, &current_wasm_module_instance.memory, sizeof(struct wasm_memory));
}

@ -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;
}
@ -222,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(&current_wasm_module_instance.memory);
if (wasm_memory_expand(&current_wasm_module_instance.memory, len) == -1) { result = (uint32_t)-1; }
return result;
}
@ -320,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(&current_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(&current_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];

@ -184,7 +184,7 @@ module_new(char *name, char *path, uint32_t stack_size, uint32_t relative_deadli
/* 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;

@ -69,12 +69,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;
}
@ -97,7 +98,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);

Loading…
Cancel
Save