feat: libsledge pattern for wasmception (#299)

* feat: libsledge pattern for wasmception

* ci: build libsledge

* ci: fix YAML whitespace issue

* ci: fix another YAML whitespace issue

* fix: Correct type issues in memcpy

* ci: debug permissions

* ci: restore build rules

* chore: Change wasmception init symbol

* chore: Assored cleanup

* fix: update g0 cache on preemption

* refactor: inline global vec in sandbox struct

* chore: trailing newline on JSON

* chore: Clean up extraneous file associations

* docs: Explain export and weak symbols

* docs: Remove comment

* refactor: Replace CHAR_BIT with limits.h

* refactor: Remove redundant unlikely define

* docs: Wasmception fn type checking disabled note
wasmception-bench wasmception
Sean McBride 3 years ago committed by GitHub
parent bbaae33ce9
commit 5d19891e63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,7 +5,6 @@ on: [push, pull_request]
env:
LLVM_VERSION: 8
WASMCEPTION_URL: https://github.com/gwsystems/wasmception/releases/download/v0.2.0/wasmception-linux-x86_64-0.2.0.tar.gz
# WASI_SDK: /opt/wasi-sdk
LANG: C.UTF-8
LANGUAGE: C.UTF-8
LC_ALL: C.UTF-8
@ -61,10 +60,6 @@ jobs:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
sh -s -- --default-toolchain stable --component rustfmt --target wasm32-wasi -y
echo "/root/.cargo/bin:$PATH" >> $GITHUB_PATH
# - name: Get WASI-SDK
# run: |
# curl -sS -L -O https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-8/wasi-sdk_8.0_amd64.deb && sudo dpkg -i wasi-sdk_8.0_amd64.deb && rm -f wasi-sdk_8.0_amd64.deb
# echo "ENV WASI_SDK=/opt/wasi-sdk" >> $GITHUB_ENV
- name: Install Test Script Utilities
run: |
sudo apt-get install -y --no-install-recommends \
@ -96,6 +91,9 @@ jobs:
LD_LIBRARY_PATH="$(pwd)/lib:$LD_LIBRARY_PATH"
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> $GITHUB_ENV
make build-validate
- name: Compile libsledge
run: |
make libsledge
# TODO:Cache assets before being copied to ./runtime/bin
- name: Cache gocr
uses: actions/cache@v2
@ -112,7 +110,7 @@ jobs:
if: failure()
with:
name: hyde-logs
path: ./runtime/experiments/applications/ocr/hyde/res/**/
path: ./tests/gocr/hyde/res/**/
- name: Handwriting
run: |
make -f test.mk gocr__handwriting

@ -8,7 +8,8 @@
"${workspaceFolder}/runtime/include/",
"${workspaceFolder}/runtime/thirdparty/ck/include/",
"${workspaceFolder}/runtime/thirdparty/http-parser/",
"${workspaceFolder}/runtime/thirdparty/jsmn/"
"${workspaceFolder}/runtime/thirdparty/jsmn/",
"${workspaceFolder}/libsledge/include"
],
"defines": [
"x86_64",

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

@ -15,6 +15,7 @@ RUN apt-get install -y --no-install-recommends \
pkg-config \
gcc \
g++ \
httpie \
clang-8 \
clang-tools-8 \
llvm-8 \

@ -46,6 +46,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
fonts-cascadia-code \
fonts-roboto \
gnuplot \
httpie \
imagemagick \
jq \
libz3-4 \

@ -52,3 +52,6 @@ runtime:
install: build rtinit
@./install.sh wasmception
.PHONY: libsledge
libsledge:
make -C libsledge clean all

@ -5,14 +5,12 @@ CC=clang-8
AWSMFLAGS= --inline-constant-globals --runtime-globals
# Used by clang when compiling the *.so module
CFLAGS=-O3
LDFLAGS=--shared -fPIC -flto
# --whole-archive causes the symbols in the listed static archive to be exported from the resulting *.so
# https://stackoverflow.com/questions/805555/ld-linker-question-the-whole-archive-option
CFLAGS=-O3 -flto
LDFLAGS=-shared -fPIC -Wl,--export-dynamic,--whole-archive -L../libsledge/dist/ -lsledge -Wl,--no-whole-archive -lm
# LDFLAGS=-flto -fvisibility=hidden
# Compiletime Components to link into *.so
SLEDGE_BASE_DIR=../
SLEDGE_RT_DIR=${SLEDGE_BASE_DIR}/runtime/
SLEDGE_COMPILETIME_INC=${SLEDGE_RT_DIR}/include
SLEDGE_COMPILETIME_SRC=${SLEDGE_RT_DIR}/compiletime/*.c
.PHONY: all
all: \
@ -39,12 +37,18 @@ clean:
dist:
mkdir -p dist
../libsledge/dist/:
mkdir ../libsledge/dist
../libsledge/dist/libsledge.a: ../libsledge/dist/
make -C .. libsledge
%.bc: %.wasm dist
${AWSMCC} ${AWSMFLAGS} $< -o $@
%.wasm.so: %.bc ${SLEDGE_COMPILETIME_SRC}
%.wasm.so: %.bc
mkdir -p dist
${CC} ${CFLAGS} ${LDFLAGS} -I${SLEDGE_COMPILETIME_INC} $^ -o $@
${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@
../runtime/bin/%.wasm.so: dist/%.wasm.so
cp $^ $@

@ -1,6 +1,6 @@
WASMCC=wasm32-unknown-unknown-wasm-clang
OPTFLAGS=-O3 -flto
WASMLINKFLAGS=-Wl,-z,stack-size=524288,--allow-undefined,--no-threads,--stack-first,--no-entry,--export-all,--export=main,--export=dummy
WASMLINKFLAGS=-Wl,-z,stack-size=524288,--allow-undefined,--no-threads,--stack-first,--no-entry,--export=main,--export=dummy,--export=__init_libc
WASMCFLAGS=${WASMLINKFLAGS} -nostartfiles
all: fibonacci.wasm

@ -1 +1 @@
Subproject commit 782efc4448889ed4e89fe57ed548e1907f36eafa
Subproject commit 90b535a67ca09421e55b74de06f4a8a817131a8c

@ -0,0 +1,45 @@
CFILES := src/*.c
INCLUDES := -Iinclude/
CFLAGS := -fPIC -O3
# CFI Sanitizer
# CFLAGS+=-fvisibility=default -fsanitize=cfi
# Undefined Sanitizer - https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
# CFLAGS+=-fsanitize=undefined,float-divide-by-zero,unsigned-integer-overflow,implicit-conversion,local-bounds,nullability
# Address Sanitizer - "Fast Memory Error Detector" - https://clang.llvm.org/docs/AddressSanitizer.html
# CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
# Clang SafeStack - https://clang.llvm.org/docs/SafeStack.html
# CFLAGS+=-fsanitize=safe-stack
# Memory Sanitizer - https://clang.llvm.org/docs/MemorySanitizer.html
# CFLAGS+=-fsanitize=memory -fno-omit-frame-pointer
all: dist/libsledge.a
dist:
mkdir dist
dist/memory_instructions.o: src/memory_instructions.c dist
clang ${CFLAGS} -c ${INCLUDES} -o $@ $<
dist/numeric_instructions.o: src/numeric_instructions.c dist
clang ${CFLAGS} -c ${INCLUDES} -o $@ $<
dist/table_instructions.o: src/table_instructions.c dist
clang ${CFLAGS} -c ${INCLUDES} -o $@ $<
dist/variable_instructions.o: src/variable_instructions.c dist
clang ${CFLAGS} -c ${INCLUDES} -o $@ $<
dist/instantiation.o: src/instantiation.c dist
clang ${CFLAGS} -c ${INCLUDES} -o $@ $<
dist/libsledge.a: dist/memory_instructions.o dist/numeric_instructions.o dist/table_instructions.o dist/variable_instructions.o dist/instantiation.o
ar rcs dist/libsledge.a $^
clean:
rm -rf dist

@ -0,0 +1,164 @@
---
geometry: margin=2cm
---
# libsledge Binary Interfaces
libsledge is a \*.a static library (archive) that is statically linked with a \*.bc file generated by the aWsm compiler when compiling to a \*.so Linux shared library that can be loaded and executed by the sledgert runtime.
The static library internally implements the aWsm ABI in order to link to the \*.bc file generated by the aWsm compiler. [See the relevant documentation for this ABI here](../awsm/doc/abi.md).
libsledge defines a ABI between the sledgert runtime and a \*.so shared library containing an executable serverless function. This is distinct from the aWsm ABI.
# SLEdge \*.so serverless module
A SLEdge \*.so serverless module is generated by the latter portion of the aWsm/SLEdge toolchain.
The first portion of the toolchain is responsible for compiling a source program into a WebAssembly module. This is handled by standard compilers capable of emitting WebAssembly.
The second portion of the toolchain is the aWsm compiler, which generates a \*.bc file with a well defined ABI
The third portion of the toolchain is the LLVM compiler, which ingests a \*.bc file emitted by aWsm and the libsledge static library, and emits a SLEdge \*.so serverless module.
## Architecture
In order to reduce the overhead of calling sledgert functions, libsledge operates on global state of type `sledge_abi__wasm_module_instance` at `sledge_abi__current_wasm_module_instance`. This represents the global state of the wasm32 context executing on a sledgert worker core. The scheduler is responsible for populating these symbols before yielding execution to a serverless function.
The `sledge_abi__wasm_module_instance` structure includes the WebAssembly function table and the WebAssembly linear memory. This subset was selected because the author believes that use of function pointers and linear memory is frequent enough that LTO when compiling the \*.so file is beneficial.
All WebAssembly state
## WebAssembly Instruction Implementation
Here is a list of WebAssembly instructions that depend on symbols from libsledge, libc, or sledgert (via the SLEdge ABI).
### [Control Instructions](https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions)
The ABI includes the
| Instruction | aWsm ABI | libc Dependencies | SLEdge ABI |
| ------------- | ------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| call_indirect | `get_function_from_table` | `stderr`, `fprintf` | `sledge_abi__current_wasm_module_instance.table`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_INVALID_INDEX`, `WASM_TRAP_MISMATCHED_FUNCTION_TYPE` |
### [Variable Instructions](https://webassembly.github.io/spec/core/syntax/instructions.html#variable-instructions)
| Instruction | aWsm ABI | libc Dependencies | SLEdge ABI |
| ----------- | ---------------------------------- | ----------------- | ---------------------------------------------------------------------- |
| global.get | `get_global_i32`, `get_global_i64` | None | `sledge_abi__wasm_globals_get_i32`, `sledge_abi__wasm_globals_get_i64` |
| global.set | `set_global_i32`, `set_global_i64` | None | `sledge_abi__wasm_globals_set_i32`, `sledge_abi__wasm_globals_set_i64` |
### [Numeric Instructions](https://webassembly.github.io/spec/core/syntax/instructions.html#numeric-instructions)
| Instruction | aWsm ABI | libc Dependencies | SLEdge ABI |
| --------------- | ---------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------- |
| i32.div_s | `i32_div` ("fast unsafe" disabled) | `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i32.div_u | `u32_div` ("fast unsafe" disabled) | `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i32.rem_s | `i32_rem` ("fast unsafe" disabled) | `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i32.rem_u | `u32_rem` ("fast unsafe" disabled) | `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i32.rotl | `rotl_u32` | None | None |
| i32.rotr | `rotr_u32` | None | None |
| i32.trunc_f32_s | `i32_trunc_f32` ("fast unsafe" disabled) | `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i32.trunc_f32_u | `u32_trunc_f32` ("fast unsafe" disabled) | `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i32.trunc_f64_s | `i32_trunc_f64` ("fast unsafe" disabled) | `INT32_MIN`, `INT32_MAX`, `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i32.trunc_f64_u | `u32_trunc_f64` ("fast unsafe" disabled) | `UINT32_MAX`, `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i64.div_s | `i64_div` ("fast unsafe" disabled) | `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i64.div_u | `u64_div` ("fast unsafe" disabled) | `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i64.rem_s | `i64_rem` ("fast unsafe" disabled) | `INT32_MIN`, `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i64.rem_u | `u64_rem` ("fast unsafe" disabled) | `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i64.rotl | `rotl_u64` | **NOT SUPPORTED** | **NOT SUPPORTED** |
| i64.rotr | `rotr_u64` | **NOT SUPPORTED** | **NOT SUPPORTED** |
| i64.trunc_f32_s | `i64_trunc_f32` | `INT64_MIN`, `INT64_MAX`, `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i64.trunc_f32_u | `u64_trunc_f32` | `UINT64_MAX`, `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i64.trunc_f64_s | `i64_trunc_f64` | `INT64_MIN`, `INT64_MAX`, `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| i64.trunc_f64_u | `u64_trunc_f64` | `UINT64_MAX`, `stderr`, `fprintf` | `sledge_abi__wasm_trap_raise`, `WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION` |
| f32.ceil | `f32_ceil` | **NOT SUPPORTED** | **NOT SUPPORTED** |
| f32.copysign | `f32_copysign` | **NOT SUPPORTED** | **NOT SUPPORTED** |
| f32.floor | `f32_floor` | `floor` | None |
| f32.max | `f32_max` | None | None |
| f32.min | `f32_min` | None | None |
| f32.nearest | `f32_nearest` | **NOT SUPPORTED** | **NOT SUPPORTED** |
| f32.trunc | `f32_trunc_f32` | `trunc` | None |
| f64.ceil | `f64_ceil` | **NOT SUPPORTED** | **NOT SUPPORTED** |
| f64.floor | `f64_floor` | `floor` | None |
| f64.max | `f64_max` | None | None |
| f64.min | `f64_min` | None | None |
| f64.nearest | `f64_nearest` | **NOT SUPPORTED** | **NOT SUPPORTED** |
| f64.trunc | `f64_trunc_f64` | **NOT SUPPORTED** | **NOT SUPPORTED** |
### [Memory Instructions](https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions)
| instruction | aWsm ABI | libc Dependencies | SLEdge ABI |
| ------------ | ------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| i32.load | `get_i32` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i32.load8_s | `get_i8` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i32.load8_u | `get_i8` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i32.load16_s | `get_i16` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i32.load16_u | `get_i16` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i32.store | `set_i32` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i32.store8 | `set_i8` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i32.store16 | `set_i16` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.load | `get_i64` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.load8_s | `get_i8` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.load8_u | `get_i8` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.load16_s | `get_i16` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.load16_u | `get_i16` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.load32_s | `get_i32` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.load32_u | `get_i32` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.store | `set_i64` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.store8 | `set_i8` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.store16 | `set_i16` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| i64.store32 | `set_i32` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| f32.load | `get_f32` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| f32.store | `set_f32` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| f64.load | `get_f64` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| f64.store | `set_f64` | `fprintf`, `stderr` | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY` |
| memory.grow | `instruction_memory_grow` | | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_memory_expand` |
| memory.size | `instruction_memory_size` | | `sledge_abi__current_wasm_module_instance.memory` |
| None | `initialize_region` | | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_memory_initialize_region` |
Discussion:
- Should `instruction_memory_grow` be moved into sledgert? This would simplify the handling of the "cache" and generating a memory profile?
- Rename `sledge_abi__wasm_globals_*` to `sledge_abi__wasm_global_*`
- Implement Unsupported Numeric Instructions
- Should the wasm global table be accessed directly instead of via a runtime function?
- Should the Function Table be handled by the \*.so file or sledgert? Are function pointers really called that frequently?
# SLEdge \*.so Module Loading / Initialization
The `sledgert` runtime is invoked with an argument containing the path to a JSON file defining serverless functions. The JSON format is a top level array containing 0..N JSON objects with the following keys:
"name" - A Human friendly name identifying a serverless function. Is required.
"path" - A path to a \*.so module containing the program to be executed
"port" - The port which the serverless function is registered
"relative-deadline-us"
"expected-execution-us"
"admissions-percentile"
"http-req-size"
"http-resp-size"
"http-resp-content-type"
The path to the JSON file is passed to `module_alloc_from_json`, which uses the Jasmine library to parse the JSON, performs validation, and passes the resulting specification to `module_alloc` for each module definition found. `module_alloc` allocated heap memory for a `struct module` and then calls `module_init`. `module_init` calls `sledge_abi_symbols_init`, which calls `dlopen` on the _.so file at the path specified in the JSON and then calls `dlsym` to resolve symbols within the _.so module.
`module.abi.initialize_globals` -> `SLEDGE_ABI__INITIALIZE_GLOBALS` -> `populate_globals`
`module.abi.initialize_memory`-> `SLEDGE_ABI__INITIALIZE_MEMORY` -> `populate_memory`
`module.abi.initialize_table` -> `SLEDGE_ABI__INITIALIZE_TABLE` -> `populate_table`
`module.abi.entrypoint` -> `SLEDGE_ABI__ENTRYPOINT` -> `wasmf__start`
`module.abi.starting_pages` -> `SLEDGE_ABI__STARTING_PAGES` -> `starting_pages`
`module.abi.max_pages` -> `SLEDGE_ABI__MAX_PAGES` -> `max_pages`
`module init` then calls `module.abi.initialize_table`, which populates the indirect function table with the actual functions. This is performed once during module initialization because this table does not actually vary between instances of a module.
# SLEdge \*.so Module Instantiation
When `sledgert` receives a request at the registered port specified in the JSON, it performs assorted allocation and initialization steps. The scheduler sets the expected ABI symbols and yields to `current_sandbox_start`, which immediately calls `current_sandbox_init`. This function initializes the associated runtime state and
1. calls `module.abi.initialize_globals` for the current sandbox if not NULL. This is optional because the module might not have been built with the `--runtime-globals`, in which case runtime globals are not used at all. If not NULL, the globals are set in the table.
2. calls `module.abi.initialize_memory`, which copies regions into the linear memory
`current_sandbox_init` calls `wasi_context_init` to initialize the WASI context within the runtime.
`current_sandbox_init` returns to `current_sandbox_start`, which sets up wasm traps using `setjmp` and then calls `module.abi.entrypoint`
# Questions:
- Should `sledge_abi__current_wasm_module_instance` be turned into a macro defined int the ABI header?
- What happens if the runtime is executing and calls `sledge_abi__current_wasm_module_instance_trap`?

@ -0,0 +1,84 @@
#pragma once
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <threads.h>
/* Do not include runtime headers here! */
/** ABI Types
* Changes to these types breaks the contract between sledgert and the *.so modules that it runs. This means that all
* modules must be recompiled. Avoid this!
*/
struct sledge_abi__wasm_table_entry {
uint32_t type_id;
void * func_pointer;
};
struct sledge_abi__wasm_table {
uint32_t length;
uint32_t capacity;
struct sledge_abi__wasm_table_entry *buffer; /* Backing heap allocation */
};
struct sledge_abi__wasm_memory {
uint64_t size; /* Initial Size in bytes */
uint64_t capacity; /* Size backed by actual pages */
uint64_t max; /* Soft cap in bytes. Defaults to 4GB */
uint8_t *buffer; /* Backing heap allocation. Different lifetime because realloc might move this */
};
/* This structure is the runtime representation of the unique state of a module instance
* Currently this is not spec-compliant, as it only supports a single table and a single memory and it excludes many
* entities https://webassembly.github.io/spec/core/exec/runtime.html#module-instances
*/
struct sledge_abi__wasm_module_instance {
uint64_t wasmg_0; /* Used to refer to the shadow stack */
struct sledge_abi__wasm_table *table;
/* Note: memory has an opaque type due to private state. Do not reorder members below this! */
struct sledge_abi__wasm_memory memory;
/* Private runtime state follows */
};
/* Symbols expected from sledgert */
extern int32_t sledge_abi__wasm_memory_expand(struct sledge_abi__wasm_memory *wasm_memory, uint32_t page_count);
void sledge_abi__wasm_memory_initialize_region(struct sledge_abi__wasm_memory *wasm_memory, uint32_t offset,
uint32_t region_size, uint8_t region[]);
extern int32_t sledge_abi__wasm_globals_get_i32(uint32_t idx);
extern int64_t sledge_abi__wasm_globals_get_i64(uint32_t idx);
extern int32_t sledge_abi__wasm_globals_set_i32(uint32_t idx, int32_t value, bool is_mutable);
extern int32_t sledge_abi__wasm_globals_set_i64(uint32_t idx, int64_t value, bool is_mutable);
/* Wasm initialization functions generated by the aWsm compiler */
extern void sledge_abi__init_globals(void);
extern void sledge_abi__init_mem(void);
extern void sledge_abi__init_tbl(void);
extern int32_t sledge_abi__entrypoint(int32_t, int32_t);
extern uint32_t sledge_abi__wasm_memory_starting_pages(void);
extern uint32_t sledge_abi__wasm_memory_max_pages(void);
typedef void (*sledge_abi__init_globals_fn_t)(void);
#define SLEDGE_ABI__INITIALIZE_GLOBALS "sledge_abi__init_globals"
typedef void (*sledge_abi__init_mem_fn_t)(void);
#define SLEDGE_ABI__INITIALIZE_MEMORY "sledge_abi__init_mem"
typedef void (*sledge_abi__init_tbl_fn_t)(void);
#define SLEDGE_ABI__INITIALIZE_TABLE "sledge_abi__init_tbl"
typedef void (*sledge_abi__init_libc_fn_t)(int32_t, int32_t);
#define SLEDGE_ABI__INITIALIZE_LIBC "sledge_abi__init_libc"
typedef int32_t (*sledge_abi__entrypoint_fn_t)(int32_t a, int32_t b);
#define SLEDGE_ABI__ENTRYPOINT "sledge_abi__entrypoint"
typedef uint32_t (*sledge_abi__wasm_memory_starting_pages_fn_t)(void);
#define SLEDGE_ABI__STARTING_PAGES "sledge_abi__wasm_memory_starting_pages"
typedef uint32_t (*sledge_abi__wasm_memory_max_pages_fn_t)(void);
#define SLEDGE_ABI__MAX_PAGES "sledge_abi__wasm_memory_max_pages"

@ -0,0 +1,68 @@
#include "sledge_abi.h"
/* The visibility attribute is used to control the visibility of a symbol across C translation units. The default
* argument forces "external" linkage. This originated in gcc, but had been adopted by LLVM.
* Reference: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html */
#define EXPORT __attribute__((visibility("default")))
/* The weak attribute is used to provide a weak symbol that can be overridden by later linking to a "strong" symbol.
* This is useful for defining a default or no-op implementation of a symbol that might or might not be present in a
* binary. This applies to populate_globals() below, which is only generated by aWsm when a module is compiled with the
* "--runtime-globals" argument. We need to provide a weak symbol that does nothing to prevent unresolved symbols from
* triggering linker errors. */
#define WEAK __attribute__((weak))
/* aWsm ABI Symbols */
extern void populate_globals(void);
extern void populate_memory(void);
extern void populate_table(void);
extern void populate_table(void);
extern void wasmf___init_libc(int32_t, int32_t);
extern int32_t wasmf_main(int32_t, int32_t);
extern uint32_t starting_pages;
extern uint32_t max_pages;
WEAK void populate_globals(){};
EXPORT void
sledge_abi__init_globals(void)
{
populate_globals();
}
void
sledge_abi__init_mem(void)
{
populate_memory();
}
EXPORT void
sledge_abi__init_tbl(void)
{
populate_table();
}
// Wasmception Initialization. Unsure what a and b is here
EXPORT void
sledge_abi__init_libc(int32_t envp, int32_t pn)
{
wasmf___init_libc(envp, pn);
}
EXPORT int32_t
sledge_abi__entrypoint(int32_t argc, int32_t argv)
{
return wasmf_main(argc, argv);
}
EXPORT uint32_t
sledge_abi__wasm_memory_starting_pages(void)
{
return starting_pages;
}
EXPORT uint32_t
sledge_abi__wasm_memory_max_pages(void)
{
return max_pages;
}

@ -0,0 +1,136 @@
#include "sledge_abi.h"
#define INLINE __attribute__((always_inline))
#define WASM_PAGE_SIZE (1024 * 64) /* 64KB */
#define likely(X) __builtin_expect(!!(X), 1)
#define unlikely(X) __builtin_expect(!!(X), 0)
/* This is private and NOT in the sledge_abi.h header because the runtime uses an overlay struct that extends this
* symbol with private members */
extern thread_local struct sledge_abi__wasm_module_instance sledge_abi__current_wasm_module_instance;
INLINE uint32_t
instruction_memory_size()
{
return (uint32_t)(sledge_abi__current_wasm_module_instance.memory.size / WASM_PAGE_SIZE);
}
// These functions are equivalent to those in wasm_memory.h, but they minimize pointer dereferencing
INLINE float
get_f32(uint32_t offset)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(float) <= sledge_abi__current_wasm_module_instance.memory.size);
return *(float *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset];
}
INLINE double
get_f64(uint32_t offset)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(double) <= sledge_abi__current_wasm_module_instance.memory.size);
return *(double *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset];
}
INLINE int8_t
get_i8(uint32_t offset)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(int8_t) <= sledge_abi__current_wasm_module_instance.memory.size);
return *(int8_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset];
}
INLINE int16_t
get_i16(uint32_t offset)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(int16_t) <= sledge_abi__current_wasm_module_instance.memory.size);
return *(int16_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset];
}
INLINE int32_t
get_i32(uint32_t offset)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(int32_t) <= sledge_abi__current_wasm_module_instance.memory.size);
return *(int32_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset];
}
INLINE int64_t
get_i64(uint32_t offset)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(int64_t) <= sledge_abi__current_wasm_module_instance.memory.size);
return *(int64_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset];
}
// Now setting routines
INLINE void
set_f32(uint32_t offset, float value)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(float) <= sledge_abi__current_wasm_module_instance.memory.size);
*(float *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value;
}
INLINE void
set_f64(uint32_t offset, double value)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(double) <= sledge_abi__current_wasm_module_instance.memory.size);
*(double *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value;
}
INLINE void
set_i8(uint32_t offset, int8_t value)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(int8_t) <= sledge_abi__current_wasm_module_instance.memory.size);
*(int8_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value;
}
INLINE void
set_i16(uint32_t offset, int16_t value)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(int16_t) <= sledge_abi__current_wasm_module_instance.memory.size);
*(int16_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value;
}
INLINE void
set_i32(uint32_t offset, int32_t value)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(int32_t) <= sledge_abi__current_wasm_module_instance.memory.size);
*(int32_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value;
}
INLINE void
set_i64(uint32_t offset, int64_t value)
{
assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL);
assert(offset + sizeof(int64_t) <= sledge_abi__current_wasm_module_instance.memory.size);
*(int64_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value;
}
/**
* @brief Stub that implements the WebAssembly memory.grow instruction
*
* @param count number of pages to grow the WebAssembly linear memory by
* @return The previous size of the linear memory in pages or -1 if enough memory cannot be allocated
*/
INLINE int32_t
instruction_memory_grow(uint32_t count)
{
return sledge_abi__wasm_memory_expand(&sledge_abi__current_wasm_module_instance.memory, count);
}
INLINE void
initialize_region(uint32_t offset, uint32_t region_size, uint8_t region[region_size])
{
sledge_abi__wasm_memory_initialize_region(&sledge_abi__current_wasm_module_instance.memory, offset, region_size,
region);
}

@ -1,13 +1,11 @@
#include <assert.h>
#include <limits.h>
#include <math.h>
#include "types.h"
#include "sledge_abi.h"
#define CHAR_BIT 8
// TODO: Throughout here we use `assert` for error conditions, which isn't optimal
// Instead we should use `unlikely` branches to a single trapping function (which should optimize better)
// The below functions are for implementing WASM instructions
#define INLINE __attribute__((always_inline))
#define likely(X) __builtin_expect(!!(X), 1)
#define unlikely(X) __builtin_expect(!!(X), 0)
// ROTL and ROTR helper functions
INLINE uint32_t

@ -0,0 +1,50 @@
#include "sledge_abi.h"
#define INDIRECT_TABLE_SIZE (1 << 10)
#define INLINE __attribute__((always_inline))
#define likely(X) __builtin_expect(!!(X), 1)
#define unlikely(X) __builtin_expect(!!(X), 0)
/* This is private and NOT in the sledge_abi.h header because the runtime uses an overlay struct that extends this
* symbol with private members */
extern thread_local struct sledge_abi__wasm_module_instance sledge_abi__current_wasm_module_instance;
static INLINE void *
wasm_table_get(struct sledge_abi__wasm_table *wasm_table, uint32_t idx, uint32_t type_id)
{
assert(wasm_table != NULL);
assert(idx < wasm_table->capacity);
struct sledge_abi__wasm_table_entry f = wasm_table->buffer[idx];
/* Wasmception-based modules trigger function type mismatches for an unknown reason.
* This should be reenabled when WASI is added */
// assert(f.type_id != type_id);
assert(f.func_pointer != NULL);
return f.func_pointer;
}
static INLINE void
wasm_table_set(struct sledge_abi__wasm_table *wasm_table, uint32_t idx, uint32_t type_id, char *pointer)
{
assert(wasm_table != NULL);
assert(idx < wasm_table->capacity);
assert(pointer != NULL);
if (wasm_table->buffer[idx].type_id == type_id && wasm_table->buffer[idx].func_pointer == pointer) return;
wasm_table->buffer[idx] = (struct sledge_abi__wasm_table_entry){ .type_id = type_id, .func_pointer = pointer };
}
INLINE void
add_function_to_table(uint32_t idx, uint32_t type_id, char *pointer)
{
wasm_table_set(sledge_abi__current_wasm_module_instance.table, idx, type_id, pointer);
}
/* char * is used as a generic pointer to a function pointer */
INLINE char *
get_function_from_table(uint32_t idx, uint32_t type_id)
{
return wasm_table_get(sledge_abi__current_wasm_module_instance.table, idx, type_id);
}

@ -0,0 +1,50 @@
#include <stdbool.h>
#include <stdint.h>
#include "sledge_abi.h"
/* This is private and NOT in the sledge_abi.h header because the runtime uses an overlay struct that extends this
* symbol with private members */
extern thread_local struct sledge_abi__wasm_module_instance sledge_abi__current_wasm_module_instance;
int32_t
get_global_i32(uint32_t idx)
{
if (idx == 0) {
return (int32_t)sledge_abi__current_wasm_module_instance.wasmg_0;
} else {
return sledge_abi__wasm_globals_get_i32(idx);
}
}
int64_t
get_global_i64(uint32_t idx)
{
if (idx == 0) {
return (int64_t)sledge_abi__current_wasm_module_instance.wasmg_0;
} else {
return sledge_abi__wasm_globals_get_i64(idx);
}
}
void
set_global_i32(uint32_t idx, int32_t value)
{
if (idx == 0) sledge_abi__current_wasm_module_instance.wasmg_0 = (uint64_t)value;
/* aWsm does not currently pass the is_mutable flag, so all runtime globals are assumed to be mutable.
This is true if aWsm uses the flags to inline constant globals */
int rc = sledge_abi__wasm_globals_set_i32(idx, value, true);
assert(rc == 0);
}
void
set_global_i64(uint32_t idx, int64_t value)
{
if (idx == 0) sledge_abi__current_wasm_module_instance.wasmg_0 = (uint64_t)value;
/* aWsm does not currently pass the is_mutable flag, so all runtime globals are assumed to be mutable.
This is true if aWsm uses the flags to inline constant globals */
int rc = sledge_abi__wasm_globals_set_i64(idx, value, true);
assert(rc == 0);
}

@ -20,19 +20,19 @@ CFLAGS+=-O3 -flto
# CFLAGS+=-O0 -g
# CFI Sanitizer
# CFLAGS+=-O0 -g -flto -fvisibility=default -fsanitize=cfi
# CFLAGS+=-fvisibility=default -fsanitize=cfi
# Undefined Sanitizer
# CFLAGS+=-O0 -g -fsanitize=undefined,float-divide-by-zero,unsigned-integer-overflow,implicit-conversion,local-bounds
# Undefined Sanitizer - https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
# CFLAGS+=-fsanitize=undefined,float-divide-by-zero,unsigned-integer-overflow,implicit-conversion,local-bounds,nullability
# Clang SafeStack - https://clang.llvm.org/docs/SafeStack.html
# CFLAGS+=-O0 -g -fsanitize=safe-stack
# CFLAGS+=-fsanitize=safe-stack
# Memory Sanitizer - https://clang.llvm.org/docs/MemorySanitizer.html
# CFLAGS+=-O0 -g -fsanitize=memory -fno-omit-frame-pointer
# CFLAGS+=-fsanitize=memory -fno-omit-frame-pointer
# Address Sanitizer - https://clang.llvm.org/docs/AddressSanitizer.html
# CFLAGS+=-O0 -g -fsanitize=address -fno-omit-frame-pointer
# Address Sanitizer - "Fast Memory Error Detector" - https://clang.llvm.org/docs/AddressSanitizer.html
# CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
BINARY_NAME=sledgert
@ -86,7 +86,6 @@ BINARY_NAME=sledgert
# Sets a flag equal to the processor architecture
CFLAGS += -D${ARCH}
# Preprocessor
# SLEdge serverless functions are *.so shared-libraries. The runtime thus requires the dynamic linker
@ -98,7 +97,7 @@ LDFLAGS += -Wl,--export-dynamic -ldl -lm
# Our third-party dependencies build into a single dist directory to simplify configuration here.
LDFLAGS += -Lthirdparty/dist/lib/
INCLUDES += -Iinclude/ -Ithirdparty/dist/include/
INCLUDES += -Iinclude/ -Ithirdparty/dist/include/ -I../libsledge/include/
# CFILES
CFILES += src/*.c
@ -110,30 +109,40 @@ CFILES += thirdparty/dist/lib/http_parser.o
JSMNCFLAGS += -DJSMN_STATIC
JSMNCFLAGS += -DJSMN_STRICT
# Force sledgert to rebuild when header files change
# This is a bit fragile, as it does not recurse subdirectories when detecting last changed times
HEADER_DEPS = thirdparty/dist/include/*.h include/*.h include/arch/x86_64/*.h include/arch/aarch64/*.h
.PHONY: all
all: runtime
all: thirdparty runtime
bin/sledgert: ${CFILES}
.PHONY: clean
clean: thirdparty.clean runtime.clean
# sledgert Rules
bin/sledgert: ${HEADER_DEPS} ${CFILES}
@echo "Compiling runtime"
@mkdir -p bin/
${CC} ${INCLUDES} ${CFLAGS} ${LDFLAGS} ${JSMNCFLAGS} -L/usr/lib/ $^ -o bin/sledgert
${CC} ${INCLUDES} ${CFLAGS} ${LDFLAGS} ${JSMNCFLAGS} -L/usr/lib/ ${CFILES} -o bin/sledgert
.PHONY: runtime
runtime: thirdparty bin/sledgert
runtime: bin/sledgert
.PHONY: runtime.clean
runtime.clean:
@rm -f bin/${BINARY_NAME}
# Thirdparty Dependency Rules
thirdparty/dist/lib/http_parser.o: thirdparty
thirdparty/dist/include/*.h: thirdparty
.PHONY: thirdparty
thirdparty:
@echo "Compiling thirdparty"
@make --no-print-directory -C thirdparty build
.PHONY: clean
clean:
@rm -f core
@echo "Cleaning up runtime"
@rm -f bin/${BINARY_NAME}
.PHONY: distclean
distclean: clean
.PHONY: thirdparty.clean
thirdparty.clean:
@make --no-print-directory -C thirdparty clean
.PHONY: submodules

@ -1,171 +0,0 @@
#include <assert.h>
#include "current_wasm_module_instance.h"
INLINE uint32_t
instruction_memory_size()
{
return (uint32_t)(current_wasm_module_instance.memory.size / WASM_PAGE_SIZE);
}
// These functions are equivalent to those in wasm_memory.h, but they minimize pointer dereferencing
INLINE float
get_f32(uint32_t 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)
{
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)
{
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)
{
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)
{
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)
{
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
get_global_i32(uint32_t offset)
{
return get_i32(offset);
}
INLINE int64_t
get_global_i64(uint32_t offset)
{
return get_i64(offset);
}
// Now setting routines
INLINE void
set_f32(uint32_t offset, float value)
{
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 value)
{
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 value)
{
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 value)
{
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 value)
{
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 value)
{
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 value)
{
set_i32(offset, value);
}
INLINE void
set_global_i64(uint32_t offset, int64_t value)
{
set_i64(offset, value);
}
/**
* @brief Stub that implements the WebAssembly memory.grow instruction
*
* @param count number of pages to grow the WebAssembly linear memory by
* @return The previous size of the linear memory in pages or -1 if enough memory cannot be allocated
*/
INLINE int32_t
instruction_memory_grow(uint32_t count)
{
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);
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++) {
if (likely(sandbox->timestamp_of.page_allocations_size < SANDBOX_PAGE_ALLOCATION_TIMESTAMP_COUNT)) {
sandbox->timestamp_of.page_allocations[sandbox->timestamp_of.page_allocations_size++] =
sandbox->duration_of_state.running
+ (uint32_t)(__getcycles() - sandbox->timestamp_of.last_state_change);
}
}
#endif
return rc;
}
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);
}

@ -1,17 +0,0 @@
#include "types.h"
#include "wasm_module_instance.h"
extern thread_local struct wasm_module_instance current_wasm_module_instance;
INLINE void
add_function_to_table(uint32_t idx, uint32_t type_id, char *pointer)
{
wasm_table_set(current_wasm_module_instance.table, idx, type_id, pointer);
}
/* char * is used as a generic pointer to a function pointer */
INLINE char *
get_function_from_table(uint32_t idx, uint32_t type_id)
{
return wasm_table_get(current_wasm_module_instance.table, idx, type_id);
}

@ -1,117 +0,0 @@
#pragma once
#include <assert.h>
#include <dlfcn.h>
#include <stdint.h>
#include "debuglog.h"
#include "wasm_types.h"
struct awsm_abi {
void * handle;
awsm_abi_init_globals_fn_t initialize_globals;
awsm_abi_init_mem_fn_t initialize_memory;
awsm_abi_init_tbl_fn_t initialize_tables;
awsm_abi_init_libc_fn_t initialize_libc;
awsm_abi_entrypoint_fn_t entrypoint;
uint32_t starting_pages;
uint32_t max_pages;
};
/* Initializes the ABI object using the *.so file at path */
static inline int
awsm_abi_init(struct awsm_abi *abi, char *path)
{
assert(abi != NULL);
int rc = 0;
abi->handle = dlopen(path, RTLD_LAZY | RTLD_DEEPBIND);
if (abi->handle == NULL) {
fprintf(stderr, "Failed to open %s with error: %s\n", path, dlerror());
goto dl_open_error;
};
/* Resolve the symbols in the dynamic library *.so file */
abi->entrypoint = (awsm_abi_entrypoint_fn_t)dlsym(abi->handle, AWSM_ABI_ENTRYPOINT);
if (abi->entrypoint == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", AWSM_ABI_ENTRYPOINT, path,
dlerror());
goto dl_error;
}
/*
* This symbol may or may not be present depending on whether the aWsm was
* run with the --runtime-globals flag. It is not clear what the proper
* configuration would be for SLEdge, so no validation is performed
*/
abi->initialize_globals = (awsm_abi_init_globals_fn_t)dlsym(abi->handle, AWSM_ABI_INITIALIZE_GLOBALS);
abi->initialize_memory = (awsm_abi_init_mem_fn_t)dlsym(abi->handle, AWSM_ABI_INITIALIZE_MEMORY);
if (abi->initialize_memory == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", AWSM_ABI_INITIALIZE_MEMORY, path,
dlerror());
goto dl_error;
};
abi->initialize_tables = (awsm_abi_init_tbl_fn_t)dlsym(abi->handle, AWSM_ABI_INITIALIZE_TABLE);
if (abi->initialize_tables == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", AWSM_ABI_INITIALIZE_TABLE, path,
dlerror());
goto dl_error;
};
abi->initialize_libc = (awsm_abi_init_libc_fn_t)dlsym(abi->handle, AWSM_ABI_INITIALIZE_LIBC);
if (abi->initialize_libc == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", AWSM_ABI_INITIALIZE_LIBC, path,
dlerror());
goto dl_error;
}
abi->starting_pages = *(uint32_t *)dlsym(abi->handle, AWSM_ABI_STARTING_PAGES);
if (abi->starting_pages == 0) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", AWSM_ABI_STARTING_PAGES, path,
dlerror());
goto dl_error;
}
abi->max_pages = *(uint32_t *)dlsym(abi->handle, AWSM_ABI_MAX_PAGES);
if (abi->max_pages == 0) {
/* This seems to not always be present. I assume this is only there if the source module explicitly
* specified this */
abi->max_pages = WASM_MEMORY_PAGES_MAX;
debuglog("max_pages symbols not defined. Defaulting to MAX defined by spec.\n");
// TODO: We need to prove that this actually can get generated by awsm
// fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", AWSM_ABI_MAX_PAGES, path,
// dlerror());
// goto dl_error;
}
done:
return rc;
dl_error:
dlclose(abi->handle);
dl_open_error:
rc = -1;
goto done;
}
static inline int
awsm_abi_deinit(struct awsm_abi *abi)
{
abi->entrypoint = NULL;
abi->initialize_globals = NULL;
abi->initialize_memory = NULL;
abi->initialize_tables = NULL;
abi->initialize_libc = NULL;
int rc = dlclose(abi->handle);
if (rc != 0) {
fprintf(stderr, "Failed to close *.so file with error: %s\n", dlerror());
return 1;
}
return 0;
}

@ -2,8 +2,8 @@
#include <threads.h>
#include "sandbox_types.h"
#include "current_wasm_module_instance.h"
#include "sandbox_types.h"
/* current sandbox that is active.. */
extern thread_local struct sandbox *worker_thread_current_sandbox;
@ -29,45 +29,67 @@ current_sandbox_set(struct sandbox *sandbox)
{
/* Unpack hierarchy to avoid pointer chasing */
if (sandbox == NULL) {
current_wasm_module_instance = (struct wasm_module_instance){
.memory =
(struct wasm_memory){
.size = 0,
.capacity = 0,
.max = 0,
.buffer = NULL,
sledge_abi__current_wasm_module_instance = (struct wasm_module_instance){
/* Public */
.abi =
(struct sledge_abi__wasm_module_instance){
.memory =
(struct sledge_abi__wasm_memory){
.size = 0,
.capacity = 0,
.max = 0,
.buffer = NULL,
},
.table = NULL,
.wasmg_0 = 0,
},
.table = NULL,
};
worker_thread_current_sandbox = NULL;
runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX;
} else {
memcpy(&current_wasm_module_instance.memory, sandbox->memory, sizeof(struct wasm_memory));
current_wasm_module_instance.table = sandbox->module->indirect_table,
memcpy(&sledge_abi__current_wasm_module_instance.abi.memory, &sandbox->memory->abi,
sizeof(struct sledge_abi__wasm_memory));
sledge_abi__current_wasm_module_instance.abi.table = sandbox->module->indirect_table;
wasm_globals_update_if_used(&sandbox->globals, 0,
&sledge_abi__current_wasm_module_instance.abi.wasmg_0);
worker_thread_current_sandbox = sandbox;
runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline;
}
}
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.capacity > 0);
return wasm_memory_get_ptr_void(&current_wasm_module_instance.memory, offset, bounds_check);
assert(sledge_abi__current_wasm_module_instance.abi.memory.capacity > 0);
return wasm_memory_get_ptr_void((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory,
offset, bounds_check);
}
static inline char
current_sandbox_get_char(uint32_t offset)
{
assert(current_wasm_module_instance.memory.capacity > 0);
return wasm_memory_get_char(&current_wasm_module_instance.memory, offset);
assert(sledge_abi__current_wasm_module_instance.abi.memory.capacity > 0);
return wasm_memory_get_char((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.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((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory,
offset, size);
}
/**
* Because we copy the members of a sandbox when it is set to current_sandbox, sledge_abi__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.
*/
static inline void
current_sandbox_memory_writeback(void)
{
struct sandbox *current_sandbox = current_sandbox_get();
memcpy(&current_sandbox->memory->abi, &sledge_abi__current_wasm_module_instance.abi.memory,
sizeof(struct sledge_abi__wasm_memory));
}

@ -2,6 +2,4 @@
#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);
extern thread_local struct wasm_module_instance sledge_abi__current_wasm_module_instance;

@ -1,6 +1,7 @@
#pragma once
#include <pthread.h>
#include <sched.h>
#include <stdint.h>
#include <stdio.h>

@ -7,11 +7,11 @@
#include "admissions_control.h"
#include "admissions_info.h"
#include "awsm_abi.h"
#include "current_wasm_module_instance.h"
#include "http.h"
#include "panic.h"
#include "pool.h"
#include "sledge_abi_symbols.h"
#include "types.h"
#include "wasm_stack.h"
#include "wasm_memory.h"
@ -68,10 +68,10 @@ struct module {
int socket_descriptor;
/* Handle and ABI Symbols for *.so file */
struct awsm_abi abi;
struct sledge_abi_symbols abi;
_Atomic uint32_t reference_count; /* ref count how many instances exist here. */
struct wasm_table *indirect_table;
_Atomic uint32_t reference_count; /* ref count how many instances exist here. */
struct sledge_abi__wasm_table *indirect_table;
struct module_pools pools[MAX_WORKER_THREADS];
};
@ -112,8 +112,8 @@ module_initialize_globals(struct module *module)
* initialization is complete.
*
* assumption: This approach depends on module_alloc only being invoked at program start before preemption is
* enabled. We are check that current_wasm_module_instance.table is NULL to gain confidence that
* we are not invoking this in a way that clobbers a current module.
* enabled. We are check that sledge_abi__current_wasm_module_instance.abi.table is NULL to gain confidence
* that we are not invoking this in a way that clobbers a current module.
*
* If we want to be able to do this later, we can possibly defer module_initialize_table until the first
* invocation. Alternatively, we can maintain the table per sandbox and call initialize
@ -122,10 +122,10 @@ module_initialize_globals(struct module *module)
static inline void
module_initialize_table(struct module *module)
{
assert(current_wasm_module_instance.table == NULL);
current_wasm_module_instance.table = module->indirect_table;
assert(sledge_abi__current_wasm_module_instance.abi.table == NULL);
sledge_abi__current_wasm_module_instance.abi.table = module->indirect_table;
module->abi.initialize_tables();
current_wasm_module_instance.table = NULL;
sledge_abi__current_wasm_module_instance.abi.table = NULL;
}
static inline int

@ -50,10 +50,9 @@ extern void runtime_set_pthread_prio(pthread_t thread, unsigned int nice);
extern void runtime_set_resource_limits_to_max(void);
/* External Symbols */
extern void alloc_linear_memory(void);
extern int expand_memory(void);
INLINE char *get_function_from_table(uint32_t idx, uint32_t type_id);
INLINE char *get_memory_ptr_for_runtime(uint32_t offset, uint32_t bounds_check);
INLINE char *get_memory_ptr(uint32_t offset, uint32_t length);
extern void stub_init(int32_t offset);
static inline char *

@ -45,7 +45,7 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox)
sandbox->duration_of_state[SANDBOX_RUNNING_SYS], sandbox->duration_of_state[SANDBOX_RUNNING_USER],
sandbox->duration_of_state[SANDBOX_ASLEEP], sandbox->duration_of_state[SANDBOX_RETURNED],
sandbox->duration_of_state[SANDBOX_COMPLETE], sandbox->duration_of_state[SANDBOX_ERROR],
runtime_processor_speed_MHz, sandbox->memory->size);
runtime_processor_speed_MHz, sandbox->memory->abi.size);
}
static inline void

@ -28,7 +28,8 @@ sandbox_setup_arguments(struct sandbox *sandbox)
assert(rc == 0);
/* We have to update our cache here */
memcpy(&current_wasm_module_instance.memory, sandbox->memory, sizeof(struct wasm_memory));
memcpy(&sledge_abi__current_wasm_module_instance.abi.memory, &sandbox->memory->abi,
sizeof(struct sledge_abi__wasm_memory));
stub_init(sandbox->arguments_offset);
}

@ -17,6 +17,7 @@
#include "wasm_memory.h"
#include "wasm_types.h"
#include "wasm_stack.h"
#include "wasm_globals.h"
#ifdef LOG_SANDBOX_MEMORY_PROFILE
#define SANDBOX_PAGE_ALLOCATION_TIMESTAMP_COUNT 1024
@ -60,9 +61,10 @@ struct sandbox {
struct module *module; /* the module this is an instance of */
/* WebAssembly Instance State */
struct arch_context ctxt;
struct wasm_stack * stack;
struct wasm_memory *memory;
struct arch_context ctxt;
struct wasm_stack * stack;
struct wasm_memory * memory;
struct vec_wasm_global_t globals;
/* Scheduling and Temporal State */
struct sandbox_timestamps timestamp_of;

@ -0,0 +1,114 @@
#pragma once
#include <assert.h>
#include <dlfcn.h>
#include <stdint.h>
#include "debuglog.h"
#include "wasm_types.h"
#include "sledge_abi.h"
struct sledge_abi_symbols {
void * handle;
sledge_abi__init_globals_fn_t initialize_globals;
sledge_abi__init_mem_fn_t initialize_memory;
sledge_abi__init_tbl_fn_t initialize_tables;
sledge_abi__init_libc_fn_t initialize_libc;
sledge_abi__entrypoint_fn_t entrypoint;
uint32_t starting_pages;
uint32_t max_pages;
};
/* Initializes the ABI object using the *.so file at path */
static inline int
sledge_abi_symbols_init(struct sledge_abi_symbols *abi, char *path)
{
assert(abi != NULL);
int rc = 0;
abi->handle = dlopen(path, RTLD_LAZY | RTLD_DEEPBIND);
if (abi->handle == NULL) {
fprintf(stderr, "Failed to open %s with error: %s\n", path, dlerror());
goto dl_open_error;
};
/* Resolve the symbols in the dynamic library *.so file */
abi->entrypoint = (sledge_abi__entrypoint_fn_t)dlsym(abi->handle, SLEDGE_ABI__ENTRYPOINT);
if (abi->entrypoint == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", SLEDGE_ABI__ENTRYPOINT, path,
dlerror());
goto dl_error;
}
/*
* This symbol may or may not be present depending on whether the aWsm was
* run with the --runtime-globals flag. It is not clear what the proper
* configuration would be for SLEdge, so no validation is performed
*/
abi->initialize_globals = (sledge_abi__init_globals_fn_t)dlsym(abi->handle, SLEDGE_ABI__INITIALIZE_GLOBALS);
abi->initialize_memory = (sledge_abi__init_mem_fn_t)dlsym(abi->handle, SLEDGE_ABI__INITIALIZE_MEMORY);
if (abi->initialize_memory == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", SLEDGE_ABI__INITIALIZE_MEMORY,
path, dlerror());
goto dl_error;
};
abi->initialize_tables = (sledge_abi__init_tbl_fn_t)dlsym(abi->handle, SLEDGE_ABI__INITIALIZE_TABLE);
if (abi->initialize_tables == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", SLEDGE_ABI__INITIALIZE_TABLE,
path, dlerror());
goto dl_error;
};
abi->initialize_libc = (sledge_abi__init_libc_fn_t)dlsym(abi->handle, SLEDGE_ABI__INITIALIZE_LIBC);
if (abi->initialize_libc == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", SLEDGE_ABI__INITIALIZE_LIBC, path,
dlerror());
goto dl_error;
};
sledge_abi__wasm_memory_starting_pages_fn_t get_starting_pages = dlsym(abi->handle, SLEDGE_ABI__STARTING_PAGES);
if (get_starting_pages == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", SLEDGE_ABI__STARTING_PAGES, path,
dlerror());
goto dl_error;
}
abi->starting_pages = get_starting_pages();
sledge_abi__wasm_memory_max_pages_fn_t get_max_pages = dlsym(abi->handle, SLEDGE_ABI__MAX_PAGES);
if (get_max_pages == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", SLEDGE_ABI__MAX_PAGES, path,
dlerror());
goto dl_error;
}
abi->max_pages = get_max_pages();
done:
return rc;
dl_error:
dlclose(abi->handle);
dl_open_error:
rc = -1;
goto done;
}
static inline int
sledge_abi_symbols_deinit(struct sledge_abi_symbols *abi)
{
abi->entrypoint = NULL;
abi->initialize_globals = NULL;
abi->initialize_memory = NULL;
abi->initialize_tables = NULL;
abi->initialize_libc = NULL;
int rc = dlclose(abi->handle);
if (rc != 0) {
fprintf(stderr, "Failed to close *.so file with error: %s\n", dlerror());
return 1;
}
return 0;
}

@ -0,0 +1,101 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <vec.h>
/* https://webassembly.github.io/spec/core/syntax/modules.html#globals */
/* This only supports i32 and i64 because this is all that aWsm currently supports */
enum wasm_global_type
{
WASM_GLOBAL_TYPE_UNUSED,
WASM_GLOBAL_TYPE_I32,
WASM_GLOBAL_TYPE_I64,
// WASM_GLOBAL_TYPE_F32,
// WASM_GLOBAL_TYPE_F64,
// WASM_GLOBAL_TYPE_V128,
// WASM_GLOBAL_TYPE_FUNCREF,
// WASM_GLOBAL_TYPE_EXTERNREF,
};
union wasm_global_value {
int32_t i32;
int64_t i64;
// float f32;
// double f64;
};
typedef struct wasm_global {
enum wasm_global_type type;
bool mut;
union wasm_global_value value;
} wasm_global_t;
VEC(wasm_global_t)
static inline void
wasm_globals_deinit(struct vec_wasm_global_t *globals)
{
vec_wasm_global_t_deinit(globals);
}
static inline int
wasm_globals_init(struct vec_wasm_global_t *globals, uint32_t capacity)
{
return vec_wasm_global_t_init(globals, capacity);
}
static inline void
wasm_globals_update_if_used(struct vec_wasm_global_t *globals, uint32_t idx, uint64_t *dest)
{
wasm_global_t *global = vec_wasm_global_t_get(globals, idx);
if (likely(global->type != WASM_GLOBAL_TYPE_UNUSED)) *dest = (uint64_t)global->value.i64;
}
static inline int32_t
wasm_globals_get_i32(struct vec_wasm_global_t *globals, uint32_t idx)
{
wasm_global_t *global = vec_wasm_global_t_get(globals, idx);
assert(global != NULL);
assert(global->type == WASM_GLOBAL_TYPE_I32);
return global->value.i32;
}
static inline int64_t
wasm_globals_get_i64(struct vec_wasm_global_t *globals, uint32_t idx)
{
wasm_global_t *global = vec_wasm_global_t_get(globals, idx);
assert(global != NULL);
assert(global->type == WASM_GLOBAL_TYPE_I64);
return global->value.i64;
}
static inline int32_t
wasm_globals_set_i32(struct vec_wasm_global_t *globals, uint32_t idx, int32_t value, bool is_mutable)
{
wasm_global_t *current = vec_wasm_global_t_get(globals, idx);
assert(current->type == WASM_GLOBAL_TYPE_UNUSED || current->mut == true);
int rc = vec_wasm_global_t_insert(globals, idx,
(wasm_global_t){
.mut = is_mutable, .type = WASM_GLOBAL_TYPE_I32, .value = value });
return rc;
}
static inline int32_t
wasm_globals_set_i64(struct vec_wasm_global_t *globals, uint32_t idx, int64_t value, bool is_mutable)
{
wasm_global_t *current = vec_wasm_global_t_get(globals, idx);
assert(current->type == WASM_GLOBAL_TYPE_UNUSED || current->mut == true);
int rc = vec_wasm_global_t_insert(globals, idx,
(wasm_global_t){
.mut = is_mutable, .type = WASM_GLOBAL_TYPE_I64, .value = value });
return rc;
}

@ -9,29 +9,29 @@
#include "ps_list.h"
#include "types.h" /* PAGE_SIZE */
#include "sledge_abi.h"
#include "wasm_types.h"
#define WASM_MEMORY_MAX (size_t) UINT32_MAX + 1
#define WASM_MEMORY_SIZE_TO_ALLOC ((size_t)WASM_MEMORY_MAX + /* guard page */ PAGE_SIZE)
#define WASM_MEMORY_MAX (uint64_t) UINT32_MAX + 1
#define WASM_MEMORY_SIZE_TO_ALLOC ((uint64_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 * buffer; /* Backing heap allocation. Different lifetime because realloc might move this */
/* Public */
struct sledge_abi__wasm_memory abi;
/* Private */
struct ps_list list; /* Linked List Node used for object pool */
};
/* Object Lifecycle Functions */
static INLINE struct wasm_memory *wasm_memory_alloc(size_t initial, size_t max);
static INLINE int wasm_memory_init(struct wasm_memory *wasm_memory, size_t initial, size_t max);
static INLINE struct wasm_memory *wasm_memory_alloc(uint64_t initial, uint64_t max);
static INLINE int32_t wasm_memory_init(struct wasm_memory *wasm_memory, uint64_t initial, uint64_t max);
static INLINE void wasm_memory_deinit(struct wasm_memory *wasm_memory);
static INLINE void wasm_memory_free(struct wasm_memory *wasm_memory);
static INLINE void wasm_memory_reinit(struct wasm_memory *wasm_memory, size_t initial);
static INLINE void wasm_memory_reinit(struct wasm_memory *wasm_memory, uint64_t initial);
/* Memory Size */
static INLINE int wasm_memory_expand(struct wasm_memory *wasm_memory, size_t size_to_expand);
static INLINE size_t wasm_memory_get_size(struct wasm_memory *wasm_memory);
static INLINE int32_t wasm_memory_expand(struct wasm_memory *wasm_memory, uint64_t size_to_expand);
static INLINE uint64_t wasm_memory_get_size(struct wasm_memory *wasm_memory);
static INLINE uint32_t wasm_memory_get_page_count(struct wasm_memory *wasm_memory);
/* Reading and writing to wasm_memory */
@ -54,9 +54,9 @@ static INLINE void wasm_memory_set_f32(struct wasm_memory *wasm_memory, uint3
static INLINE void wasm_memory_set_f64(struct wasm_memory *wasm_memory, uint32_t offset, double value);
static INLINE struct wasm_memory *
wasm_memory_alloc(size_t initial, size_t max)
wasm_memory_alloc(uint64_t initial, uint64_t max)
{
struct wasm_memory *wasm_memory = malloc(sizeof(struct wasm_memory));
struct wasm_memory *wasm_memory = aligned_alloc(4096, sizeof(struct wasm_memory));
if (wasm_memory == NULL) return wasm_memory;
int rc = wasm_memory_init(wasm_memory, initial, max);
@ -69,8 +69,8 @@ wasm_memory_alloc(size_t initial, size_t max)
return wasm_memory;
}
static INLINE int
wasm_memory_init(struct wasm_memory *wasm_memory, size_t initial, size_t max)
static INLINE int32_t
wasm_memory_init(struct wasm_memory *wasm_memory, uint64_t initial, uint64_t max)
{
assert(wasm_memory != NULL);
@ -83,20 +83,20 @@ wasm_memory_init(struct wasm_memory *wasm_memory, size_t initial, size_t max)
assert(max <= (size_t)UINT32_MAX + 1);
/* Allocate buffer of contiguous virtual addresses for full wasm32 linear memory and guard page */
wasm_memory->buffer = mmap(NULL, WASM_MEMORY_SIZE_TO_ALLOC, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (wasm_memory->buffer == MAP_FAILED) return -1;
wasm_memory->abi.buffer = mmap(NULL, WASM_MEMORY_SIZE_TO_ALLOC, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (wasm_memory->abi.buffer == MAP_FAILED) return -1;
/* Set the initial bytes to read / write */
int rc = mprotect(wasm_memory->buffer, initial, PROT_READ | PROT_WRITE);
int rc = mprotect(wasm_memory->abi.buffer, initial, PROT_READ | PROT_WRITE);
if (rc != 0) {
munmap(wasm_memory->buffer, WASM_MEMORY_SIZE_TO_ALLOC);
munmap(wasm_memory->abi.buffer, WASM_MEMORY_SIZE_TO_ALLOC);
return -1;
}
ps_list_init_d(wasm_memory);
wasm_memory->size = initial;
wasm_memory->capacity = initial;
wasm_memory->max = max;
wasm_memory->abi.size = initial;
wasm_memory->abi.capacity = initial;
wasm_memory->abi.max = max;
return 0;
}
@ -105,13 +105,13 @@ static INLINE void
wasm_memory_deinit(struct wasm_memory *wasm_memory)
{
assert(wasm_memory != NULL);
assert(wasm_memory->buffer != NULL);
assert(wasm_memory->abi.buffer != NULL);
munmap(wasm_memory->buffer, WASM_MEMORY_SIZE_TO_ALLOC);
wasm_memory->buffer = NULL;
wasm_memory->size = 0;
wasm_memory->capacity = 0;
wasm_memory->max = 0;
munmap(wasm_memory->abi.buffer, WASM_MEMORY_SIZE_TO_ALLOC);
wasm_memory->abi.buffer = NULL;
wasm_memory->abi.size = 0;
wasm_memory->abi.capacity = 0;
wasm_memory->abi.max = 0;
}
static INLINE void
@ -123,19 +123,19 @@ wasm_memory_free(struct wasm_memory *wasm_memory)
}
static INLINE void
wasm_memory_reinit(struct wasm_memory *wasm_memory, size_t initial)
wasm_memory_reinit(struct wasm_memory *wasm_memory, uint64_t initial)
{
memset(wasm_memory->buffer, 0, wasm_memory->size);
wasm_memory->size = initial;
memset(wasm_memory->abi.buffer, 0, wasm_memory->abi.size);
wasm_memory->abi.size = initial;
}
static INLINE int
wasm_memory_expand(struct wasm_memory *wasm_memory, size_t size_to_expand)
static INLINE int32_t
wasm_memory_expand(struct wasm_memory *wasm_memory, uint64_t size_to_expand)
{
size_t target_size = wasm_memory->size + size_to_expand;
if (unlikely(target_size > wasm_memory->max)) {
fprintf(stderr, "wasm_memory_expand - Out of Memory!. %lu out of %lu\n", wasm_memory->size,
wasm_memory->max);
uint64_t target_size = wasm_memory->abi.size + size_to_expand;
if (unlikely(target_size > wasm_memory->abi.max)) {
fprintf(stderr, "wasm_memory_expand - Out of Memory!. %lu out of %lu\n", wasm_memory->abi.size,
wasm_memory->abi.max);
return -1;
}
@ -144,31 +144,31 @@ wasm_memory_expand(struct wasm_memory *wasm_memory, size_t size_to_expand)
* 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 > wasm_memory->capacity) {
int rc = mprotect(wasm_memory->buffer, target_size, PROT_READ | PROT_WRITE);
if (target_size > wasm_memory->abi.capacity) {
int rc = mprotect(wasm_memory->abi.buffer, target_size, PROT_READ | PROT_WRITE);
if (rc != 0) {
perror("wasm_memory_expand mprotect");
return -1;
}
wasm_memory->capacity = target_size;
wasm_memory->abi.capacity = target_size;
}
wasm_memory->size = target_size;
wasm_memory->abi.size = target_size;
return 0;
}
static INLINE size_t
static INLINE uint64_t
wasm_memory_get_size(struct wasm_memory *wasm_memory)
{
return wasm_memory->size;
return wasm_memory->abi.size;
}
static INLINE void
wasm_memory_initialize_region(struct wasm_memory *wasm_memory, uint32_t offset, uint32_t region_size, uint8_t region[])
{
assert((size_t)offset + region_size <= wasm_memory->size);
memcpy(&wasm_memory->buffer[offset], region, region_size);
assert((size_t)offset + region_size <= wasm_memory->abi.size);
memcpy(&wasm_memory->abi.buffer[offset], region, region_size);
}
/* NOTE: These wasm_memory functions require pointer dereferencing. For this reason, they are not directly by wasm32
@ -183,8 +183,8 @@ wasm_memory_initialize_region(struct wasm_memory *wasm_memory, uint32_t offset,
static INLINE void *
wasm_memory_get_ptr_void(struct wasm_memory *wasm_memory, uint32_t offset, uint32_t size)
{
assert(offset + size <= wasm_memory->size);
return (void *)&wasm_memory->buffer[offset];
assert(offset + size <= wasm_memory->abi.size);
return (void *)&wasm_memory->abi.buffer[offset];
}
/**
@ -195,8 +195,8 @@ wasm_memory_get_ptr_void(struct wasm_memory *wasm_memory, uint32_t offset, uint3
static INLINE char
wasm_memory_get_char(struct wasm_memory *wasm_memory, uint32_t offset)
{
assert(offset + sizeof(char) <= wasm_memory->size);
return *(char *)&wasm_memory->buffer[offset];
assert(offset + sizeof(char) <= wasm_memory->abi.size);
return *(char *)&wasm_memory->abi.buffer[offset];
}
/**
@ -207,8 +207,8 @@ wasm_memory_get_char(struct wasm_memory *wasm_memory, uint32_t offset)
static INLINE float
wasm_memory_get_f32(struct wasm_memory *wasm_memory, uint32_t offset)
{
assert(offset + sizeof(float) <= wasm_memory->size);
return *(float *)&wasm_memory->buffer[offset];
assert(offset + sizeof(float) <= wasm_memory->abi.size);
return *(float *)&wasm_memory->abi.buffer[offset];
}
/**
@ -219,8 +219,8 @@ wasm_memory_get_f32(struct wasm_memory *wasm_memory, uint32_t offset)
static INLINE double
wasm_memory_get_f64(struct wasm_memory *wasm_memory, uint32_t offset)
{
assert(offset + sizeof(double) <= wasm_memory->size);
return *(double *)&wasm_memory->buffer[offset];
assert(offset + sizeof(double) <= wasm_memory->abi.size);
return *(double *)&wasm_memory->abi.buffer[offset];
}
/**
@ -231,8 +231,8 @@ wasm_memory_get_f64(struct wasm_memory *wasm_memory, uint32_t offset)
static INLINE int8_t
wasm_memory_get_i8(struct wasm_memory *wasm_memory, uint32_t offset)
{
assert(offset + sizeof(int8_t) <= wasm_memory->size);
return *(int8_t *)&wasm_memory->buffer[offset];
assert(offset + sizeof(int8_t) <= wasm_memory->abi.size);
return *(int8_t *)&wasm_memory->abi.buffer[offset];
}
/**
@ -243,8 +243,8 @@ wasm_memory_get_i8(struct wasm_memory *wasm_memory, uint32_t offset)
static INLINE int16_t
wasm_memory_get_i16(struct wasm_memory *wasm_memory, uint32_t offset)
{
assert(offset + sizeof(int16_t) <= wasm_memory->size);
return *(int16_t *)&wasm_memory->buffer[offset];
assert(offset + sizeof(int16_t) <= wasm_memory->abi.size);
return *(int16_t *)&wasm_memory->abi.buffer[offset];
}
/**
@ -255,8 +255,8 @@ wasm_memory_get_i16(struct wasm_memory *wasm_memory, uint32_t offset)
static INLINE int32_t
wasm_memory_get_i32(struct wasm_memory *wasm_memory, uint32_t offset)
{
assert(offset + sizeof(int32_t) <= wasm_memory->size);
return *(int32_t *)&wasm_memory->buffer[offset];
assert(offset + sizeof(int32_t) <= wasm_memory->abi.size);
return *(int32_t *)&wasm_memory->abi.buffer[offset];
}
/**
@ -267,14 +267,14 @@ wasm_memory_get_i32(struct wasm_memory *wasm_memory, uint32_t offset)
static INLINE int64_t
wasm_memory_get_i64(struct wasm_memory *wasm_memory, uint32_t offset)
{
assert(offset + sizeof(int64_t) <= wasm_memory->size);
return *(int64_t *)&wasm_memory->buffer[offset];
assert(offset + sizeof(int64_t) <= wasm_memory->abi.size);
return *(int64_t *)&wasm_memory->abi.buffer[offset];
}
static INLINE uint32_t
wasm_memory_get_page_count(struct wasm_memory *wasm_memory)
{
return (uint32_t)(wasm_memory->size / WASM_PAGE_SIZE);
return (uint32_t)(wasm_memory->abi.size / WASM_PAGE_SIZE);
}
/**
@ -286,10 +286,10 @@ wasm_memory_get_page_count(struct wasm_memory *wasm_memory)
static INLINE char *
wasm_memory_get_string(struct wasm_memory *wasm_memory, uint32_t offset, uint32_t size)
{
assert(offset + (sizeof(char) * size) <= wasm_memory->size);
assert(offset + (sizeof(char) * size) <= wasm_memory->abi.size);
if (strnlen((const char *)&wasm_memory->buffer[offset], size) < size) {
return (char *)&wasm_memory->buffer[offset];
if (strnlen((const char *)&wasm_memory->abi.buffer[offset], size) < size) {
return (char *)&wasm_memory->abi.buffer[offset];
} else {
return NULL;
}
@ -303,8 +303,8 @@ wasm_memory_get_string(struct wasm_memory *wasm_memory, uint32_t offset, uint32_
static INLINE void
wasm_memory_set_f32(struct wasm_memory *wasm_memory, uint32_t offset, float value)
{
assert(offset + sizeof(float) <= wasm_memory->size);
*(float *)&wasm_memory->buffer[offset] = value;
assert(offset + sizeof(float) <= wasm_memory->abi.size);
*(float *)&wasm_memory->abi.buffer[offset] = value;
}
/**
@ -315,8 +315,8 @@ wasm_memory_set_f32(struct wasm_memory *wasm_memory, uint32_t offset, float valu
static INLINE void
wasm_memory_set_f64(struct wasm_memory *wasm_memory, uint32_t offset, double value)
{
assert(offset + sizeof(double) <= wasm_memory->size);
*(double *)&wasm_memory->buffer[offset] = value;
assert(offset + sizeof(double) <= wasm_memory->abi.size);
*(double *)&wasm_memory->abi.buffer[offset] = value;
}
/**
@ -327,8 +327,8 @@ wasm_memory_set_f64(struct wasm_memory *wasm_memory, uint32_t offset, double val
static INLINE void
wasm_memory_set_i8(struct wasm_memory *wasm_memory, uint32_t offset, int8_t value)
{
assert(offset + sizeof(int8_t) <= wasm_memory->size);
*(int8_t *)&wasm_memory->buffer[offset] = value;
assert(offset + sizeof(int8_t) <= wasm_memory->abi.size);
*(int8_t *)&wasm_memory->abi.buffer[offset] = value;
}
/**
@ -339,8 +339,8 @@ wasm_memory_set_i8(struct wasm_memory *wasm_memory, uint32_t offset, int8_t valu
static INLINE void
wasm_memory_set_i16(struct wasm_memory *wasm_memory, uint32_t offset, int16_t value)
{
assert(offset + sizeof(int16_t) <= wasm_memory->size);
*(int16_t *)&wasm_memory->buffer[offset] = value;
assert(offset + sizeof(int16_t) <= wasm_memory->abi.size);
*(int16_t *)&wasm_memory->abi.buffer[offset] = value;
}
/**
@ -351,8 +351,8 @@ wasm_memory_set_i16(struct wasm_memory *wasm_memory, uint32_t offset, int16_t va
static INLINE void
wasm_memory_set_i32(struct wasm_memory *wasm_memory, uint32_t offset, int32_t value)
{
assert(offset + sizeof(int32_t) <= wasm_memory->size);
*(int32_t *)&wasm_memory->buffer[offset] = value;
assert(offset + sizeof(int32_t) <= wasm_memory->abi.size);
*(int32_t *)&wasm_memory->abi.buffer[offset] = value;
}
/**
@ -363,6 +363,6 @@ wasm_memory_set_i32(struct wasm_memory *wasm_memory, uint32_t offset, int32_t va
static INLINE void
wasm_memory_set_i64(struct wasm_memory *wasm_memory, uint64_t offset, int64_t value)
{
assert(offset + sizeof(int64_t) <= wasm_memory->size);
*(int64_t *)&wasm_memory->buffer[offset] = value;
assert(offset + sizeof(int64_t) <= wasm_memory->abi.size);
*(int64_t *)&wasm_memory->abi.buffer[offset] = value;
}

@ -1,12 +1,13 @@
#pragma once
#include "wasm_memory.h"
#include "wasm_table.h"
#include "sledge_abi.h"
/* This structure is the runtime representation of the unique state of a module instance
* Currently this is not spec-compliant, as it only supports a single table and a single memory and it excludes many
* entities https://webassembly.github.io/spec/core/exec/runtime.html#module-instances
*/
struct wasm_module_instance {
struct wasm_memory memory;
struct wasm_table *table;
/* Public */
struct sledge_abi__wasm_module_instance abi;
};

@ -9,29 +9,18 @@
/* memory also provides the table access functions */
#define INDIRECT_TABLE_SIZE (1 << 10)
struct wasm_table_entry {
uint32_t type_id;
void * func_pointer;
};
struct wasm_table {
uint32_t length;
uint32_t capacity;
struct wasm_table_entry *buffer; /* Backing heap allocation */
};
static INLINE int wasm_table_init(struct wasm_table *wasm_table, size_t capacity);
static INLINE struct wasm_table *wasm_table_alloc(size_t capacity);
static INLINE void wasm_table_deinit(struct wasm_table *wasm_table);
static INLINE void wasm_table_free(struct wasm_table *wasm_table);
static INLINE int wasm_table_init(struct sledge_abi__wasm_table *wasm_table, size_t capacity);
static INLINE struct sledge_abi__wasm_table *wasm_table_alloc(size_t capacity);
static INLINE void wasm_table_deinit(struct sledge_abi__wasm_table *wasm_table);
static INLINE void wasm_table_free(struct sledge_abi__wasm_table *wasm_table);
static INLINE int
wasm_table_init(struct wasm_table *wasm_table, size_t capacity)
wasm_table_init(struct sledge_abi__wasm_table *wasm_table, size_t capacity)
{
assert(wasm_table != NULL);
if (capacity > 0) {
wasm_table->buffer = calloc(capacity, sizeof(struct wasm_table_entry));
wasm_table->buffer = calloc(capacity, sizeof(struct sledge_abi__wasm_table_entry));
if (wasm_table->buffer == NULL) return -1;
}
@ -41,10 +30,11 @@ wasm_table_init(struct wasm_table *wasm_table, size_t capacity)
return 0;
}
static INLINE struct wasm_table *
static INLINE struct sledge_abi__wasm_table *
wasm_table_alloc(size_t capacity)
{
struct wasm_table *wasm_table = (struct wasm_table *)malloc(sizeof(struct wasm_table));
struct sledge_abi__wasm_table *wasm_table = (struct sledge_abi__wasm_table *)malloc(
sizeof(struct sledge_abi__wasm_table));
if (wasm_table == NULL) return NULL;
int rc = wasm_table_init(wasm_table, capacity);
@ -57,7 +47,7 @@ wasm_table_alloc(size_t capacity)
}
static INLINE void
wasm_table_deinit(struct wasm_table *wasm_table)
wasm_table_deinit(struct sledge_abi__wasm_table *wasm_table)
{
assert(wasm_table != NULL);
@ -75,19 +65,19 @@ wasm_table_deinit(struct wasm_table *wasm_table)
}
static INLINE void
wasm_table_free(struct wasm_table *wasm_table)
wasm_table_free(struct sledge_abi__wasm_table *wasm_table)
{
assert(wasm_table != NULL);
free(wasm_table);
}
static INLINE void *
wasm_table_get(struct wasm_table *wasm_table, uint32_t idx, uint32_t type_id)
wasm_table_get(struct sledge_abi__wasm_table *wasm_table, uint32_t idx, uint32_t type_id)
{
assert(wasm_table != NULL);
assert(idx < wasm_table->capacity);
struct wasm_table_entry f = wasm_table->buffer[idx];
struct sledge_abi__wasm_table_entry f = wasm_table->buffer[idx];
// FIXME: Commented out function type check because of gocr
// assert(f.type_id == type_id);
@ -97,7 +87,7 @@ wasm_table_get(struct wasm_table *wasm_table, uint32_t idx, uint32_t type_id)
}
static INLINE void
wasm_table_set(struct wasm_table *wasm_table, uint32_t idx, uint32_t type_id, char *pointer)
wasm_table_set(struct sledge_abi__wasm_table *wasm_table, uint32_t idx, uint32_t type_id, char *pointer)
{
assert(wasm_table != NULL);
assert(idx < wasm_table->capacity);
@ -106,5 +96,5 @@ wasm_table_set(struct wasm_table *wasm_table, uint32_t idx, uint32_t type_id, ch
/* TODO: atomic for multiple concurrent invocations? Issue #97 */
if (wasm_table->buffer[idx].type_id == type_id && wasm_table->buffer[idx].func_pointer == pointer) return;
wasm_table->buffer[idx] = (struct wasm_table_entry){ .type_id = type_id, .func_pointer = pointer };
wasm_table->buffer[idx] = (struct sledge_abi__wasm_table_entry){ .type_id = type_id, .func_pointer = pointer };
}

@ -6,20 +6,3 @@
#define WASM_MEMORY_PAGES_INITIAL (1 << 8) /* 256 Pages ~16MB */
#define WASM_MEMORY_PAGES_MAX (1 << 16) /* 32,768 Pages ~4GB */
#define WASM_STACK_SIZE (1 << 19) /* 512KB */
/* Wasm initialization functions generated by the compiler */
#define AWSM_ABI_INITIALIZE_GLOBALS "populate_globals"
#define AWSM_ABI_INITIALIZE_MEMORY "populate_memory"
#define AWSM_ABI_INITIALIZE_TABLE "populate_table"
#define AWSM_ABI_INITIALIZE_LIBC "wasmf___init_libc"
#define AWSM_ABI_ENTRYPOINT "wasmf_main"
#define AWSM_ABI_STARTING_PAGES "starting_pages"
#define AWSM_ABI_MAX_PAGES "max_pages"
/* functions in the module to lookup and call per sandbox. */
typedef void (*awsm_abi_init_globals_fn_t)(void);
typedef void (*awsm_abi_init_mem_fn_t)(void);
typedef void (*awsm_abi_init_tbl_fn_t)(void);
typedef void (*awsm_abi_init_libc_fn_t)(int32_t, int32_t);
typedef int32_t (*awsm_abi_entrypoint_fn_t)(int32_t a, int32_t b);

@ -4,25 +4,14 @@
#include "wasm_module_instance.h"
#include "wasm_memory.h"
thread_local struct wasm_module_instance current_wasm_module_instance = {
.memory =
(struct wasm_memory){
thread_local struct wasm_module_instance sledge_abi__current_wasm_module_instance = {
.abi.memory =
(struct sledge_abi__wasm_memory){
.size = 0,
.max = 0,
.capacity = 0,
.buffer = NULL,
},
.table = NULL,
.abi.table = NULL,
.abi.wasmg_0 = 0xDEADBEEF,
};
/**
* 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));
}

@ -223,8 +223,11 @@ 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(
(struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory);
if (wasm_memory_expand((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory, len) == -1) {
result = (uint32_t)-1;
}
return result;
}
@ -321,18 +324,19 @@ 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 == sledge_abi__current_wasm_module_instance.abi.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((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.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 = sledge_abi__current_wasm_module_instance.abi.memory.size;
wasm_memory_expand((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory, new_size);
// Get pointer of old offset and pointer of new offset
uint8_t *linear_mem = current_wasm_module_instance.memory.buffer;
uint8_t *linear_mem = sledge_abi__current_wasm_module_instance.abi.memory.buffer;
uint8_t *src = &linear_mem[offset];
uint8_t *dest = &linear_mem[new_offset];

@ -122,7 +122,7 @@ module_free(struct module *module)
if (module->reference_count) return;
close(module->socket_descriptor);
awsm_abi_deinit(&module->abi);
sledge_abi_symbols_deinit(&module->abi);
free(module);
}
@ -136,7 +136,7 @@ module_init(struct module *module, char *name, char *path, uint32_t stack_size,
atomic_init(&module->reference_count, 0);
rc = awsm_abi_init(&module->abi, path);
rc = sledge_abi_symbols_init(&module->abi, path);
if (rc != 0) goto err;
/* Set fields in the module struct */

@ -53,6 +53,25 @@ sandbox_allocate_stack(struct sandbox *sandbox)
return 0;
}
static inline int
sandbox_allocate_globals(struct sandbox *sandbox)
{
assert(sandbox);
assert(sandbox->module);
return wasm_globals_init(&sandbox->globals, 10);
}
static inline void
sandbox_free_globals(struct sandbox *sandbox)
{
assert(sandbox);
assert(sandbox->module);
assert(sandbox->globals.buffer != NULL);
wasm_globals_deinit(&sandbox->globals);
}
static inline void
sandbox_free_stack(struct sandbox *sandbox)
{
@ -103,6 +122,12 @@ sandbox_prepare_execution_environment(struct sandbox *sandbox)
goto err_http_allocation_failed;
}
rc = sandbox_allocate_globals(sandbox);
if (rc < 0) {
error_message = "failed to allocate globals";
goto err_globals_allocation_failed;
}
/* Allocate linear memory in a 4GB address space */
if (sandbox_allocate_linear_memory(sandbox)) {
error_message = "failed to allocate sandbox linear memory";
@ -124,6 +149,7 @@ done:
return rc;
err_stack_allocation_failed:
err_memory_allocation_failed:
err_globals_allocation_failed:
err_http_allocation_failed:
client_socket_send_oneshot(sandbox->client_socket_descriptor, http_header_build(503), http_header_len(503));
client_socket_close(sandbox->client_socket_descriptor, &sandbox->client_address);
@ -201,6 +227,8 @@ sandbox_deinit(struct sandbox *sandbox)
/* Free Sandbox Struct*/
if (likely(sandbox->stack != NULL)) sandbox_free_stack(sandbox);
if (likely(sandbox->globals.buffer != NULL)) sandbox_free_globals(sandbox);
}
/**

@ -0,0 +1,64 @@
#include "current_sandbox.h"
#include "sledge_abi.h"
#include "wasm_memory.h"
EXPORT int32_t
sledge_abi__wasm_memory_expand(struct sledge_abi__wasm_memory *wasm_memory, uint32_t page_count)
{
int32_t old_page_count = wasm_memory->size / WASM_PAGE_SIZE;
int rc = wasm_memory_expand((struct wasm_memory *)wasm_memory, page_count * WASM_PAGE_SIZE);
if (unlikely(rc == -1)) return -1;
/* We updated "forked state" in sledge_abi__current_wasm_module_instance.memory. We need to write this back to
* the original struct as well */
current_sandbox_memory_writeback();
#ifdef LOG_SANDBOX_MEMORY_PROFILE
// Cache the runtime of the first N page allocations
for (int i = 0; i < page_count; i++) {
if (likely(sandbox->timestamp_of.page_allocations_size < SANDBOX_PAGE_ALLOCATION_TIMESTAMP_COUNT)) {
sandbox->timestamp_of.page_allocations[sandbox->timestamp_of.page_allocations_size++] =
sandbox->duration_of_state.running
+ (uint32_t)(__getcycles() - sandbox->timestamp_of.last_state_change);
}
}
#endif
return old_page_count;
}
EXPORT void
sledge_abi__wasm_memory_initialize_region(struct sledge_abi__wasm_memory *wasm_memory, uint32_t offset,
uint32_t region_size, uint8_t region[])
{
return wasm_memory_initialize_region((struct wasm_memory *)wasm_memory, offset, region_size, region);
}
EXPORT int32_t
sledge_abi__wasm_globals_get_i32(uint32_t idx)
{
struct sandbox *current = current_sandbox_get();
return wasm_globals_get_i32(&current->globals, idx);
}
EXPORT int64_t
sledge_abi__wasm_globals_get_i64(uint32_t idx)
{
struct sandbox *current = current_sandbox_get();
return wasm_globals_get_i64(&current->globals, idx);
}
EXPORT int32_t
sledge_abi__wasm_globals_set_i32(uint32_t idx, int32_t value, bool is_mutable)
{
struct sandbox *current = current_sandbox_get();
return wasm_globals_set_i32(&current->globals, idx, value, true);
}
EXPORT int32_t
sledge_abi__wasm_globals_set_i64(uint32_t idx, int64_t value, bool is_mutable)
{
struct sandbox *current = current_sandbox_get();
return wasm_globals_set_i64(&current->globals, idx, value, true);
}

@ -43,5 +43,6 @@ jsmn: ${DIST_PREFIX}/include/jsmn.h
.PHONY: clean
clean:
make -C ck uninstall
rm -rf ${DIST_PREFIX}
-@test -f ck/Makefile && make -k -C ck uninstall || echo "Makefile not generated. Skipping!"
-@rm -f ck/Makefile
-@rm -rf ${DIST_PREFIX}

Loading…
Cancel
Save