feat: add support for .so dylib files (#103)

* add support for .so dynamic lib files

* implement a missing wasi_intruction (prestat)

* seperate the wasm instructions from runtime code

* temporary commit to figure out github CI wat2wasm version

* add debug and release flags to makefile

* apply the .so compilation logic to all Makefiles and Python scripts

* separate wasm instructions from memory files

* update the tests to for CI

* make the Makefile independent of .so or .bc linked runtime

* update submodule cmu

* Specify clear rules for providing a ".so" library
pull/105/head
Emil 1 year ago committed by GitHub
parent e804863246
commit f94cfea983
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -11,10 +11,14 @@ submodules:
git submodule update --init --recursive
# aWsm: the WebAssembly to LLVM bitcode compiler
.PHONY: awsm
awsm:
.PHONY: awsm/release
awsm/release:
cargo build --release
.PHONY: awsm/debug
awsm/debug:
cargo build
.PHONY: awsm.clean
awsm.clean:
cargo clean

@ -1,20 +1,28 @@
AWSMCC=../target/release/awsm
CC=clang
ARCH=64bit_nix
# Used by aWsm when compiling the *.wasm to *.bc
# No need for adding the --runtime-globals flag for just a single sandbox exec
AWSMFLAGS= --inline-constant-globals
RUNTIME_PATH=../runtime
RUNTIME_INCLUDES=-I${RUNTIME_PATH}/libc/wasi/include -I${RUNTIME_PATH}/thirdparty/dist/include
RUNTIME_UVWASI_INCLUDES=-I${RUNTIME_PATH}/libc/wasi/include -I${RUNTIME_PATH}/thirdparty/dist/include
RUNTIME_MINIMAL_INCLUDES=-I${RUNTIME_PATH}/libc/wasi/include
WASI_CPATH+=${RUNTIME_PATH}/runtime.c
WASI_CPATH+=${RUNTIME_PATH}/libc/wasi/wasi_main.c
WASI_CPATH+=${RUNTIME_PATH}/libc/wasi/wasi_backing.c
WASI_CPATH+=${RUNTIME_PATH}/libc/wasi/wasi_impl_uvwasi.c
WASI_CPATH+=${RUNTIME_PATH}/libc/env.c
WASI_CPATH+=${RUNTIME_PATH}/memory/64bit_nix.c
WASI_CPATH+=${RUNTIME_PATH}/thirdparty/dist/lib/libuv_a.a
WASI_CPATH+=${RUNTIME_PATH}/thirdparty/dist/lib/libuvwasi_a.a
WASM_INSTRUCTIONS=${RUNTIME_PATH}/wasm_instructions/common.c ${RUNTIME_PATH}/wasm_instructions/memory/${ARCH}.c
# WASI_COMMON_CPATH+=${RUNTIME_PATH}/libc/env.c # not necessary so far
WASI_COMMON_CPATH+=${RUNTIME_PATH}/memory/${ARCH}.c
WASI_COMMON_CPATH+=${RUNTIME_PATH}/libc/wasi/wasi_backing.c
WASI_COMMON_CPATH+=${RUNTIME_PATH}/libc/wasi/wasi_main.c
WASI_COMMON_CPATH+=${RUNTIME_PATH}/runtime.c
WASI_MINIMAL_CPATH=${WASI_COMMON_CPATH} ${RUNTIME_PATH}/libc/wasi/wasi_impl_minimal.c
WASI_UVWASI_CPATH=${WASI_COMMON_CPATH} ${RUNTIME_PATH}/libc/wasi/wasi_impl_uvwasi.c
WASI_UVWASI_LIBPATH+=${RUNTIME_PATH}/thirdparty/dist/lib/libuv_a.a
WASI_UVWASI_LIBPATH+=${RUNTIME_PATH}/thirdparty/dist/lib/libuvwasi_a.a
dist:
mkdir dist
@ -33,8 +41,27 @@ dist/%.bc: ./wasm_apps/dist/%.wasm dist
dist/%.ll: dist/%.bc
llvm-dis-12 $< -o $@
dist/%.awsm: dist/%.bc ${WASI_CPATH}
${CC} -pthread -ldl -lm -O3 -flto -g ${RUNTIME_INCLUDES} $^ -o $@
# By default choose the bc.mini.awsm mode:
dist/%.awsm: dist/%.bc.mini.awsm ;
dist/%.bc.mini.awsm: dist/%.bc ${WASM_INSTRUCTIONS} ${WASI_MINIMAL_CPATH}
${CC} -lm -O3 -flto ${RUNTIME_MINIMAL_INCLUDES} $^ -o $@
dist/%.bc.uvwasi.awsm: dist/%.bc ${WASM_INSTRUCTIONS} ${WASI_UVWASI_CPATH} ${WASI_UVWASI_LIBPATH}
${CC} -lm -O3 -flto -pthread -ldl ${RUNTIME_UVWASI_INCLUDES} $^ -o $@
dist/%.so: dist/%.bc ${WASM_INSTRUCTIONS}
${CC} -O3 -flto -shared -fPIC $^ -o $@
# When executing the following binary, make sure the shell variable SO_PATH is set showing the path to the .so file.
# e.g. SO_PATH=./fibonacci.so awsm_so_runtime.out
dist/awsm_so_runtime.out: dist
$(eval WASI_SO_MINIMAL_CPATH= $(subst runtime.c,runtime_so.c,$(WASI_MINIMAL_CPATH)))
${CC} ${RUNTIME_MINIMAL_INCLUDES} ${CFLAGS} -Wl,--export-dynamic -ldl -lm ${WASI_SO_MINIMAL_CPATH} -o $@
# UVWASI version does not work now, since libuv_a.a and libuvwai_a.a were NOT complied with -fPIC option
# dist/%.so.uvwasi.awsm: dist ${WASI_UVWASI_CPATH}
# ${CC} ${RUNTIME_UVWASI_INCLUDES} -pthread -D_GNU_SOURCE ${CFLAGS} ${LDFLAGS_UVWASI_so} $^ -o $@
dist/armstrong-numbers.awsm: dist/armstrong-numbers.bc armstrong-numbers/main.c ${RUNTIME_PATH}/runtime.c ${RUNTIME_PATH}/memory/64bit_nix.c
${CC} -lm -O3 -flto $^ -o $@
@ -72,6 +99,7 @@ dist/triangle.awsm: dist/triangle.bc triangle/main.c ${RUNTIME_PATH}/runtime.c $
dist/unreachable.awsm: dist/unreachable.bc unreachable/main.c ${RUNTIME_PATH}/runtime.c ${RUNTIME_PATH}/memory/64bit_nix.c
${CC} -lm -O3 -flto $^ -o $@
.PHONY: all.awsm
all.awsm: \
dist/app_pid.awsm \

@ -322,7 +322,7 @@ def compile_wasm_to_executable(program, exe_postfix, memory_impl, unsafe_impls=F
else:
target_flag = "-target " + AWSM_TARGET
command = "clang -lm {target} {opt} {bc_file} {runtime}/runtime.c {backing} {runtime}/libc/env.c {runtime}/memory/{mem_impl} -o bin/{pname}_{postfix}"\
command = "clang -lm {target} {opt} {bc_file} {runtime}/runtime.c {runtime}/wasm_instructions/common.c {runtime}/wasm_instructions/memory/{mem_impl} {backing} {runtime}/libc/env.c {runtime}/memory/{mem_impl} -o bin/{pname}_{postfix}"\
.format(target=target_flag, opt=opt, bc_file=bc_file, pname=program.name, runtime=RUNTIME_PATH, backing=WASM_BACKING, mem_impl=memory_impl, postfix=exe_postfix)
print(command)
sp.check_call(command, shell=True, cwd=program.name)

@ -160,7 +160,7 @@
style="stroke-width:0.26458332"
y="79.4991"
x="71.4375"
sodipodi:role="line"> (table 0 anyfunc)</tspan><tspan
sodipodi:role="line"> (table 0 funcref)</tspan><tspan
id="tspan833"
style="stroke-width:0.26458332"
y="85.672707"

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

@ -4,6 +4,17 @@ int printf_(const char* format, ...);
volatile int CORTEX_M_ARG_C = 0;
u32 allocate_n_bytes(u32 n) {
awsm_assert(memory_size > 0);
u32 res = runtime_heap_base;
runtime_heap_base += n;
while (memory_size < runtime_heap_base) {
expand_memory();
}
printf("rhb %d\n", runtime_heap_base);
return res;
}
int runtime_main(int argc, char** argv) {
runtime_init();

@ -597,7 +597,7 @@ wasi_snapshot_preview1_backing_fd_pread(void* wasi_context, __wasi_fd_t fd, cons
*/
__wasi_errno_t
wasi_snapshot_preview1_backing_fd_prestat_get(void* wasi_context, __wasi_fd_t fd, __wasi_prestat_t* prestat_retptr) {
return wasi_unsupported_syscall(__func__);
return __WASI_ERRNO_BADF;
}
/**

@ -9,8 +9,8 @@
* writing custom startup logic for other host environments and execution models.
*/
void* current_wasi_context;
void* current_wasi_context;
struct dylib_handler so_handler;
/* Code that actually runs the wasm code */
IMPORT void wasmf__start(void);
@ -24,6 +24,8 @@ void runtime_on_module_exit() {
}
int main(int argc, char* argv[]) {
so_handler.app_path = argv[0];
runtime_init();
/* Copy environ from process */
@ -42,6 +44,11 @@ int main(int argc, char* argv[]) {
atexit(runtime_on_module_exit);
wasmf__start();
if (so_handler.handle) {
so_handler.entrypoint();
} else {
wasmf__start();
}
exit(EXIT_SUCCESS);
}

@ -19,6 +19,17 @@
IMPORT i32 wasmf_main(i32 a, i32 b);
u32 allocate_n_bytes(u32 n) {
awsm_assert(memory_size > 0);
u32 res = runtime_heap_base;
runtime_heap_base += n;
while (memory_size < runtime_heap_base) {
expand_memory();
}
printf("rhb %d\n", runtime_heap_base);
return res;
}
int runtime_main(int argc, char** argv) {
runtime_init();

@ -41,19 +41,6 @@ void expand_memory() {
memory_size += WASM_PAGE_SIZE;
}
i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void check_bounds(u32 offset, u32 bounds_check) {
// Due to how we setup memory for x86, the virtual memory mechanism will catch the error, if bounds < WASM_PAGE_SIZE
awsm_assert(bounds_check < WASM_PAGE_SIZE || (memory_size > bounds_check && offset <= memory_size - bounds_check));
@ -67,94 +54,6 @@ INLINE char* get_memory_ptr_for_runtime(u32 offset, u32 bounds_check) {
return address;
}
// All of these are pretty generic
INLINE float get_f32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i32*)address;
}
INLINE i64 get_i64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i64*)address;
}
// Now setting routines
INLINE void set_f32(u32 offset, float v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
// Table handling functionality
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
// NOTE: Legacy C applications could fail this check if they typecast function pointers.
// Additional reference: https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html
awsm_assert(f.type_id == type_id);
awsm_assert(f.func_pointer);
return f.func_pointer;
}
// Functions that aren't useful for this runtime
INLINE void switch_into_runtime() {}
INLINE void switch_out_of_runtime() {}

@ -3,7 +3,6 @@
void* memory;
u32 memory_size;
#define TOTAL_PAGES (1 << 2)
#define MEM_SIZE (WASM_PAGE_SIZE * TOTAL_PAGES)
char CORTEX_M_MEM[MEM_SIZE] = { 0 };
@ -35,19 +34,6 @@ void expand_memory() {
memory_size += WASM_PAGE_SIZE;
}
i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void check_bounds(u32 offset, u32 bounds_check) {
awsm_assert(offset <= memory_size - bounds_check);
}
@ -61,122 +47,6 @@ INLINE char* get_memory_ptr_for_runtime(u32 offset, u32 bounds_check) {
return address;
}
// All of these are pretty generic
INLINE float get_f32(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(float));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(double));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
// printf_("get %d <= %d - %d\n", offset, memory_size, sizeof(i8));
awsm_assert(offset <= memory_size - sizeof(i8));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i16));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i32));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i32*)address;
}
INLINE i64 get_i64(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i64));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i64*)address;
}
// Now setting routines
INLINE void set_f32(u32 offset, float v) {
awsm_assert(offset <= memory_size - sizeof(float));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
awsm_assert(offset <= memory_size - sizeof(double));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
// printf_("set %d <= %d - %d\n", offset, memory_size, sizeof(i8));
awsm_assert(offset <= memory_size - sizeof(i8));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
awsm_assert(offset <= memory_size - sizeof(i16));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
awsm_assert(offset <= memory_size - sizeof(i32));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
awsm_assert(offset <= memory_size - sizeof(i64));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id && f.func_pointer);
return f.func_pointer;
}
// Functions that aren't useful for this runtime
INLINE void switch_into_runtime() {
return;
}
INLINE void switch_out_of_runtime() {
return;
}
INLINE void switch_into_runtime() {}
INLINE void switch_out_of_runtime() {}

@ -3,7 +3,6 @@
void* memory;
u32 memory_size;
#define TOTAL_PAGES 4
#define MEM_SIZE (WASM_PAGE_SIZE * TOTAL_PAGES)
char CORTEX_M_MEM[MEM_SIZE] = { 0 };
@ -36,19 +35,6 @@ void expand_memory() {
memory_size += WASM_PAGE_SIZE;
}
i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void check_bounds(u32 offset, u32 bounds_check) {
return;
}
@ -60,90 +46,6 @@ INLINE char* get_memory_ptr_for_runtime(u32 offset, u32 bounds_check) {
return address;
}
// All of these are pretty generic
INLINE float get_f32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i32*)address;
}
INLINE i64 get_i64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i64*)address;
}
// Now setting routines
INLINE void set_f32(u32 offset, float v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
struct indirect_table_entry f = indirect_table[idx];
return f.func_pointer;
}
// Functions that aren't useful for this runtime
INLINE void switch_into_runtime() {
return;
}
INLINE void switch_out_of_runtime() {
return;
}
INLINE void switch_into_runtime() {}
INLINE void switch_out_of_runtime() {}

@ -46,19 +46,6 @@ void expand_memory() {
memory_size += WASM_PAGE_SIZE;
}
i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void check_bounds(u32 offset, u32 bounds_check) {
return;
}
@ -70,180 +57,6 @@ INLINE char* get_memory_ptr_for_runtime(u32 offset, u32 bounds_check) {
return address;
}
INLINE void* get_page(u32 offset) {
u32 page_number = (offset >> SPT_PAGE_SIZE_ORDER) & ((1 << SPT_PAGE_COUNT_ORDER) - 1);
awsm_assert(page_number < SPT_PAGE_COUNT);
void* page = PAGE_TABLE[page_number];
awsm_assert(page);
return page;
}
INLINE u32 get_page_offset(u32 offset) {
return offset & ((1 << SPT_PAGE_SIZE_ORDER) - 1);
}
INLINE i8 get_i8(u32 offset) {
i8* page = get_page(offset);
u32 page_offset = get_page_offset(offset);
return page[page_offset];
}
INLINE i16 get_i16(u32 offset) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i16)) {
i8* page = get_page(offset);
i16* page_adj = (void*)&page[page_offset];
return *page_adj;
} else {
u8 a = (u8)get_i8(offset);
u8 b = (u8)get_i8(offset + 1);
return (i16)(((u16)b) << 8) | ((u16)a);
}
// u32 page_offset = get_page_offset(offset);
// i8* page = get_page(offset);
// i16* page_adj = (void*) &page[page_offset];
// printf("Regularly loaded: %p\n", (void*) (u64) *page_adj);
//
// u8 a = (u8) get_i8(offset);
// u8 b = (u8) get_i8(offset + 1);
// i16 split = (i16) (((u16) b) << 8) | ((u16) a);
// printf("Split from (%p, %p)\n", (void*) (u64) a, (void*) (u64) b);
// printf("Split loaded: %p\n", (void*) (u64) split);
//
// awsm_assert(*page_adj == split);
// return *page_adj;
}
INLINE i32 get_i32(u32 offset) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i32)) {
i8* page = get_page(offset);
i32* page_adj = (void*)&page[page_offset];
return *page_adj;
} else {
u16 a = (u16)get_i16(offset);
u16 b = (u16)get_i16(offset + 2);
return (i32)(((u32)b) << 16) | ((u32)a);
}
}
INLINE i64 get_i64(u32 offset) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i64)) {
i8* page = get_page(offset);
i64* page_adj = (void*)&page[page_offset];
return *page_adj;
} else {
u32 a = (u32)get_i32(offset);
u32 b = (u32)get_i32(offset + 4);
return (i64)(((u64)b) << 32) | ((u64)a);
}
}
INLINE float get_f32(u32 offset) {
union {
i32 i;
float f;
} a;
a.i = get_i32(offset);
return a.f;
}
INLINE double get_f64(u32 offset) {
union {
i64 i;
double f;
} a;
a.i = get_i64(offset);
return a.f;
}
// Setting routines
INLINE void set_i8(u32 offset, i8 v) {
i8* page = get_page(offset);
u32 page_offset = get_page_offset(offset);
page[page_offset] = v;
}
INLINE void set_i16(u32 offset, i16 v) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i16)) {
i8* page = get_page(offset);
i16* page_adj = (void*)&page[page_offset];
*page_adj = v;
} else {
u16 v2 = (u16)v;
set_i8(offset, (i8)v2);
set_i8(offset + 1, (i8)(v2 >> 8));
}
}
INLINE void set_i32(u32 offset, i32 v) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i32)) {
i8* page = get_page(offset);
i32* page_adj = (void*)&page[page_offset];
*page_adj = v;
} else {
u32 v2 = (u32)v;
set_i16(offset, (i16)v2);
set_i16(offset + 2, (i16)(v2 >> 16));
}
}
INLINE void set_i64(u32 offset, i64 v) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i64)) {
i8* page = get_page(offset);
i64* page_adj = (void*)&page[page_offset];
*page_adj = v;
} else {
u64 v2 = (u64)v;
set_i32(offset, (i32)v2);
set_i32(offset + 4, (i32)(v2 >> 32));
}
}
INLINE void set_f32(u32 offset, float v) {
union {
i32 i;
float f;
} a;
a.f = v;
set_i32(offset, a.i);
}
INLINE void set_f64(u32 offset, double v) {
union {
i64 i;
double f;
} a;
a.f = v;
set_i64(offset, a.i);
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id && f.func_pointer);
return f.func_pointer;
}
// Functions that aren't useful for this runtime
INLINE void switch_into_runtime() {
return;
}
INLINE void switch_out_of_runtime() {
return;
}
INLINE void switch_into_runtime() {}
INLINE void switch_out_of_runtime() {}

@ -30,19 +30,6 @@ void expand_memory() {
memory_size += WASM_PAGE_SIZE;
}
i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void check_bounds(u32 offset, u32 bounds_check) {
awsm_assert(offset <= memory_size - bounds_check);
}
@ -54,100 +41,6 @@ INLINE char* get_memory_ptr_for_runtime(u32 offset, u32 bounds_check) {
return address;
}
// All of these are pretty generic
INLINE float get_f32(u32 offset) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
return *(i16*)&CORTEX_M_MEM[offset % MEM_SIZE];
}
INLINE i32 get_i32(u32 offset) {
return *(i32*)&CORTEX_M_MEM[offset % MEM_SIZE];
}
INLINE i64 get_i64(u32 offset) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
return *(i64*)address;
}
// Now setting routines
INLINE void set_f32(u32 offset, float v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id && f.func_pointer);
return f.func_pointer;
}
// Functions that aren't useful for this runtime
INLINE void switch_into_runtime() {
return;
}
INLINE void switch_out_of_runtime() {
return;
}
INLINE void switch_into_runtime() {}
INLINE void switch_out_of_runtime() {}

@ -24,19 +24,6 @@ void expand_memory() {
memory_size += WASM_PAGE_SIZE;
}
i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void check_bounds(u32 offset, u32 bounds_check) {
awsm_assert(memory_size > bounds_check && offset <= memory_size - bounds_check);
}
@ -50,115 +37,6 @@ INLINE char* get_memory_ptr_for_runtime(u32 offset, u32 bounds_check) {
return address;
}
// All of these are pretty generic
INLINE float get_f32(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(float));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(double));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i8));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i16));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i32));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i32*)address;
}
INLINE i64 get_i64(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i64));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i64*)address;
}
// Now setting routines
INLINE void set_f32(u32 offset, float v) {
awsm_assert(offset <= memory_size - sizeof(float));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
awsm_assert(offset <= memory_size - sizeof(double));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
awsm_assert(offset <= memory_size - sizeof(i8));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
awsm_assert(offset <= memory_size - sizeof(i16));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
awsm_assert(offset <= memory_size - sizeof(i32));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
awsm_assert(offset <= memory_size - sizeof(i64));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id && f.func_pointer);
return f.func_pointer;
}
// Functions that aren't useful for this runtime
INLINE void switch_into_runtime() {}
INLINE void switch_out_of_runtime() {}

@ -25,19 +25,6 @@ void expand_memory() {
memory_size += WASM_PAGE_SIZE;
}
i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void check_bounds(u32 offset, u32 bounds_check) {
awsm_assert(memory_size > bounds_check && offset <= memory_size - bounds_check);
}
@ -49,134 +36,6 @@ INLINE char* get_memory_ptr_for_runtime(u32 offset, u32 bounds_check) {
return &mem_as_chars[offset];
}
#define MPX_BC(adr, sz) \
{ asm volatile("bndcu " #sz "(%0), %%bnd0" : : "r"(adr)); }
// All of these are pretty generic
INLINE float get_f32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
// Bounds check
MPX_BC(address, 0x3);
float v = *(float*)address;
return v;
}
INLINE double get_f64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x7);
double v = *(double*)address;
return v;
}
INLINE i8 get_i8(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x0);
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x1);
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x3);
i32 v = *(i32*)address;
return v;
}
INLINE i64 get_i64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x7);
i64 v = *(i64*)address;
return v;
}
// Now setting routines
INLINE void set_f32(u32 offset, float v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x3);
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x7);
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x0);
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x1);
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x3);
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x7);
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id && f.func_pointer);
return f.func_pointer;
}
// Functions that aren't useful for this runtime
INLINE void switch_into_runtime() {}
INLINE void switch_out_of_runtime() {}

@ -22,19 +22,6 @@ void expand_memory() {
memory_size += WASM_PAGE_SIZE;
}
i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void check_bounds(u32 offset, u32 bounds_check) {
return;
}
@ -44,89 +31,6 @@ INLINE char* get_memory_ptr_for_runtime(u32 offset, u32 bounds_check) {
return &mem_as_chars[offset];
}
// All of these are pretty generic
INLINE float get_f32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
float v = *(float*)address;
return v;
}
INLINE double get_f64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
double v = *(double*)address;
return v;
}
INLINE i8 get_i8(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
i32 v = *(i32*)address;
return v;
}
INLINE i64 get_i64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
i64 v = *(i64*)address;
return v;
}
// Now setting routines
INLINE void set_f32(u32 offset, float v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
struct indirect_table_entry f = indirect_table[idx];
return f.func_pointer;
}
// Functions that aren't useful for this runtime
INLINE void switch_into_runtime() {}
INLINE void switch_out_of_runtime() {}

@ -1,9 +1,8 @@
#include "../runtime.h"
#include <syscall.h>
#include <asm/ldt.h>
#include <sys/mman.h>
#include <syscall.h>
// Routines for dealing with the ldt
void write_ldt(struct user_desc* desc) {
@ -89,19 +88,6 @@ void expand_memory() {
set_seg_registers();
}
i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void check_bounds(u32 offset, u32 bounds_check) {
awsm_assert(memory_size > bounds_check && offset <= memory_size - bounds_check);
}
@ -115,74 +101,6 @@ INLINE char* get_memory_ptr_for_runtime(u32 offset, u32 bounds_check) {
return address;
}
#define GS_REL __attribute__((address_space(256)))
// All of these are pretty generic
INLINE float get_f32(u32 offset) {
return *((GS_REL float*)offset);
}
INLINE double get_f64(u32 offset) {
return *((GS_REL double*)offset);
}
INLINE i8 get_i8(u32 offset) {
return *((GS_REL i8*)offset);
}
INLINE i16 get_i16(u32 offset) {
return *((GS_REL i16*)offset);
}
INLINE i32 get_i32(u32 offset) {
return *((GS_REL i32*)offset);
}
INLINE i64 get_i64(u32 offset) {
return *((GS_REL i64*)offset);
}
// Now setting routines
INLINE void set_f32(u32 offset, float v) {
GS_REL float* ptr = (GS_REL float*)offset;
*ptr = v;
}
INLINE void set_f64(u32 offset, double v) {
GS_REL double* ptr = (GS_REL double*)offset;
*ptr = v;
}
INLINE void set_i8(u32 offset, i8 v) {
GS_REL i8* ptr = (GS_REL i8*)offset;
*ptr = v;
}
INLINE void set_i16(u32 offset, i16 v) {
GS_REL i16* ptr = (GS_REL i16*)offset;
*ptr = v;
}
INLINE void set_i32(u32 offset, i32 v) {
GS_REL i32* ptr = (GS_REL i32*)offset;
*ptr = v;
}
INLINE void set_i64(u32 offset, i64 v) {
GS_REL i64* ptr = (GS_REL i64*)offset;
*ptr = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id && f.func_pointer);
return f.func_pointer;
}
INLINE void switch_into_runtime() {
reset_seg_registers();
}

@ -2,6 +2,8 @@
#include <fenv.h>
#include <math.h>
struct indirect_table_entry indirect_table[INDIRECT_TABLE_SIZE];
// 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)
@ -10,305 +12,10 @@ void env___cxa_pure_virtual() {
awsm_assert("env___cxa_pure_virtual" == 0);
}
// Region initialization helper function
EXPORT void initialize_region(u32 offset, u32 data_count, char* data) {
awsm_assert(memory_size >= data_count);
awsm_assert(offset < memory_size - data_count);
// awsm_assert(offset <= memory_size - data_count);
// FIXME: Hack around segmented and unsegmented access
memcpy(get_memory_ptr_for_runtime(offset, data_count), data, data_count);
}
struct indirect_table_entry indirect_table[INDIRECT_TABLE_SIZE];
void add_function_to_table(u32 idx, u32 type_id, char* pointer) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
indirect_table[idx] = (struct indirect_table_entry){ .type_id = type_id, .func_pointer = pointer };
}
void clear_table() {
for (int i = 0; i < INDIRECT_TABLE_SIZE; i++) {
indirect_table[i] = (struct indirect_table_entry){ 0 };
}
}
// The below functions are for implementing WASM instructions
// ROTL and ROTR helper functions
INLINE u32 rotl_u32(u32 n, u32 c_u32) {
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u32 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
c &= mask;
return (n << c) | (n >> ((-c) & mask));
}
INLINE u32 rotr_u32(u32 n, u32 c_u32) {
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u32 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
c &= mask;
return (n >> c) | (n << ((-c) & mask));
}
INLINE u64 rotl_u64(u64 n, u64 c_u64) {
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u64 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
c &= mask;
return (n << c) | (n >> ((-c) & mask));
}
INLINE u64 rotr_u64(u64 n, u64 c_u64) {
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u64 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
c &= mask;
return (n >> c) | (n << ((-c) & mask));
}
// Now safe division and remainder
INLINE u32 u32_div(u32 a, u32 b) {
awsm_assert(b);
return a / b;
}
INLINE u32 u32_rem(u32 a, u32 b) {
awsm_assert(b);
return a % b;
}
INLINE i32 i32_div(i32 a, i32 b) {
awsm_assert(b && (a != INT32_MIN || b != -1));
return a / b;
}
INLINE i32 i32_rem(i32 a, i32 b) {
awsm_assert(b != 0);
/* Because MIN is one less than MAX, we can FPE here */
if (unlikely(a == INT32_MIN)) {
return (a + abs(b)) % b;
}
return a % b;
}
INLINE u64 u64_div(u64 a, u64 b) {
awsm_assert(b);
return a / b;
}
INLINE u64 u64_rem(u64 a, u64 b) {
awsm_assert(b);
return a % b;
}
INLINE i64 i64_div(i64 a, i64 b) {
awsm_assert(b && (a != INT64_MIN || b != -1));
return a / b;
}
INLINE i64 i64_rem(i64 a, i64 b) {
awsm_assert(b != 0);
/* Because MIN is one less than MAX, we can FPE here */
if (unlikely(a == INT64_MIN)) {
return (a + labs(b)) % b;
}
return a % b;
}
// float to integer conversion methods
// In C, float => int conversions always truncate
// If a int2float(int::min_value) <= float <= int2float(int::max_value), it must always be safe to truncate it
u32 u32_trunc_f32(float f) {
float integer_part = 0;
float decimal_part = modff(f, &integer_part);
if (unlikely(integer_part < 0 || integer_part > (float)UINT32_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (u32)f;
}
i32 i32_trunc_f32(float f) {
float integer_part = 0;
float decimal_part = modff(f, &integer_part);
if (unlikely(integer_part < (float)INT32_MIN || integer_part > (float)INT32_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (i32)f;
}
u32 u32_trunc_f64(double f) {
double integer_part = 0;
double decimal_part = modf(f, &integer_part);
if (unlikely(integer_part < 0 || integer_part > (double)UINT32_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (u32)f;
}
i32 i32_trunc_f64(double f) {
double integer_part = 0;
double decimal_part = modf(f, &integer_part);
if (unlikely(integer_part < (double)INT32_MIN || integer_part > (double)INT32_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (i32)f;
}
u64 u64_trunc_f32(float f) {
float integer_part = 0;
float decimal_part = modff(f, &integer_part);
if (unlikely(integer_part < 0 || integer_part > (float)UINT64_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (u64)f;
}
i64 i64_trunc_f32(float f) {
float integer_part = 0;
float decimal_part = modff(f, &integer_part);
if (unlikely(integer_part < (float)INT64_MIN || integer_part > (float)INT64_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (i64)f;
}
u64 u64_trunc_f64(double f) {
double integer_part = 0;
double decimal_part = modf(f, &integer_part);
if (unlikely(integer_part < 0 || integer_part > (double)UINT64_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (u64)f;
}
i64 i64_trunc_f64(double f) {
double integer_part = 0;
double decimal_part = modf(f, &integer_part);
if (unlikely(integer_part < (double)INT64_MIN || integer_part > (double)INT64_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (i64)f;
}
// Float => Float truncation functions
INLINE float f32_trunc_f32(float f) {
return truncf(f);
}
INLINE float f32_min(float a, float b) {
return a < b ? a : b;
}
INLINE float f32_max(float a, float b) {
return a > b ? a : b;
}
INLINE float f32_floor(float a) {
return floorf(a);
}
INLINE float f32_ceil(float a) {
return ceilf(a);
}
INLINE float f32_nearest(float a) {
return nearbyintf(a);
}
INLINE float f32_copysign(float a, float b) {
return copysignf(a, b);
}
INLINE double f64_trunc_f64(double f) {
return trunc(f);
}
INLINE double f64_min(double a, double b) {
return a < b ? a : b;
}
INLINE double f64_max(double a, double b) {
return a > b ? a : b;
}
INLINE double f64_floor(double a) {
return floor(a);
}
INLINE double f64_ceil(double a) {
return ceil(a);
}
INLINE double f64_nearest(double a) {
return nearbyint(a);
}
INLINE double f64_copysign(double a, double b) {
return copysign(a, b);
}
__attribute__((noreturn)) void awsm_abi__trap_unreachable() {
fprintf(stderr, "WebAssembly control flow unexpectedly reached unreachable instruction\n");
exit(EXIT_FAILURE);
}
// We want to have some allocation logic here, so we can use it to implement libc
WEAK u32 wasmg___heap_base = 0;
u32 runtime_heap_base;
u32 allocate_n_bytes(u32 n) {
awsm_assert(memory_size > 0);
u32 res = runtime_heap_base;
runtime_heap_base += n;
while (memory_size < runtime_heap_base) {
expand_memory();
}
printf("rhb %d\n", runtime_heap_base);
return res;
}
void* allocate_n_bytes_ptr(u32 n) {
awsm_assert(memory_size > 0);
u32 addr = allocate_n_bytes(n);
return get_memory_ptr_for_runtime(addr, n);
}
// If we are using runtime globals, we need to populate them
WEAK void populate_globals() {}
// If a function is registered using the (start) instruction, call it
WEAK void awsm_abi__start_fn() {}

@ -1,5 +1,7 @@
#pragma once
#include <dlfcn.h>
#define EXPORT __attribute__((visibility("default")))
#define IMPORT __attribute__((visibility("default")))
@ -103,10 +105,12 @@ INLINE void switch_out_of_runtime();
// The code generator also compiles in stubs that populate the linear memory and function table
void populate_memory();
void populate_table();
void populate_globals();
// memory/* provides these memory functions
extern void* memory;
extern u32 memory_size;
extern u32 runtime_heap_base;
void alloc_linear_memory();
void expand_memory();
@ -170,3 +174,20 @@ void stub_init();
int runtime_main(int argc, char** argv);
void runtime_init();
typedef void (*init_globals_fn_t)(void);
typedef void (*init_mem_fn_t)(void);
typedef void (*init_tbl_fn_t)(void);
typedef int32_t (*entrypoint_fn_t)(void);
struct dylib_handler {
void* handle;
char* app_path;
init_globals_fn_t initialize_globals;
init_mem_fn_t initialize_memory;
init_tbl_fn_t initialize_tables;
entrypoint_fn_t entrypoint;
uint32_t* starting_pages;
uint32_t* max_pages;
uint32_t* globals_len;
};

@ -0,0 +1,104 @@
#include "runtime.h"
#include <fenv.h>
#include <math.h>
struct indirect_table_entry indirect_table[INDIRECT_TABLE_SIZE];
// 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)
// We want to have some allocation logic here, so we can use it to implement libc
WEAK u32 wasmg___heap_base = 0;
u32 runtime_heap_base;
// If a function is registered using the (start) instruction, call it
WEAK void start_fn() {}
WEAK void wasmf__start() {}
extern struct dylib_handler so_handler;
u32 starting_pages, max_pages;
static inline int dylib_handler_init(struct dylib_handler* handler, const char* path) {
awsm_assert(handler != NULL);
int rc = 0;
handler->handle = dlopen(path, RTLD_LAZY | RTLD_DEEPBIND);
if (handler->handle == NULL) {
fprintf(stderr, "Failed to open %s with error: %s\n", path, dlerror());
fprintf(stderr, "Either provide a \"lib.so\" file in the same dir "
"or provide a path such as: SO_PATH=./app_name.so\n");
goto dl_open_error;
}
/* Resolve the symbols in the dynamic library *.so file */
handler->entrypoint = (entrypoint_fn_t)dlsym(handler->handle, "wasmf__start");
if (handler->entrypoint == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", "wasmf__start", 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
*/
handler->initialize_globals = (init_globals_fn_t)dlsym(handler->handle, "populate_globals");
handler->initialize_memory = (init_mem_fn_t)dlsym(handler->handle, "populate_memory");
if (handler->initialize_memory == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", "populate_memory", path, dlerror());
goto dl_error;
}
handler->initialize_tables = (init_tbl_fn_t)dlsym(handler->handle, "populate_table");
if (handler->initialize_tables == NULL) {
fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", "populate_table", path, dlerror());
goto dl_error;
}
handler->starting_pages = dlsym(handler->handle, "starting_pages");
handler->max_pages = dlsym(handler->handle, "max_pages");
handler->globals_len = dlsym(handler->handle, "globals_len");
done:
return rc;
dl_error:
dlclose(handler->handle);
dl_open_error:
rc = -1;
goto done;
}
void runtime_init() {
char* dl_path = getenv("SO_PATH");
if (dl_path == NULL) {
/* If no explicit path is provided, then look for lib.so in the same folder */
dl_path = "./lib.so";
}
int ret = dylib_handler_init(&so_handler, dl_path);
if (ret != 0)
exit(ret);
starting_pages = *so_handler.starting_pages;
max_pages = *so_handler.max_pages;
if (likely(starting_pages > 0)) {
alloc_linear_memory();
}
so_handler.initialize_tables();
if (so_handler.initialize_globals)
so_handler.initialize_globals();
so_handler.initialize_memory();
int rc = fesetround(FE_TONEAREST);
awsm_assert(rc == 0);
runtime_heap_base = wasmg___heap_base;
if (runtime_heap_base == 0) {
runtime_heap_base = memory_size;
}
start_fn();
}

@ -0,0 +1,301 @@
#include "../runtime.h"
__attribute__((noreturn)) __attribute__((always_inline)) void awsm_abi__trap_unreachable() {
fprintf(stderr, "WebAssembly control flow unexpectedly reached unreachable instruction\n");
exit(EXIT_FAILURE);
}
/* Instantiation */
// If we are using runtime globals, we need to populate them
WEAK void populate_globals() {}
/* End of Instantiation */
/* Memory Instructions:*/
INLINE i32 instruction_memory_size() {
return memory_size / WASM_PAGE_SIZE;
}
INLINE i32 instruction_memory_grow(i32 count) {
i32 prev_size = instruction_memory_size();
for (int i = 0; i < count; i++) {
expand_memory();
}
return prev_size;
}
INLINE void initialize_region(u32 offset, u32 data_count, char* data) {
// FIXME: Hack around segmented and unsegmented access
memcpy(get_memory_ptr_for_runtime(offset, data_count), data, data_count);
}
/* End of Memory Instructions:*/
/* Table Instructions:*/
INLINE void add_function_to_table(u32 idx, u32 type_id, char* pointer) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
indirect_table[idx] = (struct indirect_table_entry){ .type_id = type_id, .func_pointer = pointer };
}
INLINE void clear_table() {
for (int i = 0; i < INDIRECT_TABLE_SIZE; i++) {
indirect_table[i] = (struct indirect_table_entry){ 0 };
}
}
/* End of Table Instructions:*/
/* Numeric Instructions:*/
INLINE u32 rotl_u32(u32 n, u32 c_u32) {
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u32 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
c &= mask;
return (n << c) | (n >> ((-c) & mask));
}
INLINE u32 rotr_u32(u32 n, u32 c_u32) {
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u32 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
c &= mask;
return (n >> c) | (n << ((-c) & mask));
}
INLINE u64 rotl_u64(u64 n, u64 c_u64) {
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u64 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
c &= mask;
return (n << c) | (n >> ((-c) & mask));
}
INLINE u64 rotr_u64(u64 n, u64 c_u64) {
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u64 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
c &= mask;
return (n >> c) | (n << ((-c) & mask));
}
// Now safe division and remainder
INLINE u32 u32_div(u32 a, u32 b) {
awsm_assert(b);
return a / b;
}
INLINE u32 u32_rem(u32 a, u32 b) {
awsm_assert(b);
return a % b;
}
INLINE i32 i32_div(i32 a, i32 b) {
awsm_assert(b && (a != INT32_MIN || b != -1));
return a / b;
}
INLINE i32 i32_rem(i32 a, i32 b) {
awsm_assert(b != 0);
/* Because MIN is one less than MAX, we can FPE here */
if (unlikely(a == INT32_MIN)) {
return (a + abs(b)) % b;
}
return a % b;
}
INLINE u64 u64_div(u64 a, u64 b) {
awsm_assert(b);
return a / b;
}
INLINE u64 u64_rem(u64 a, u64 b) {
awsm_assert(b);
return a % b;
}
INLINE i64 i64_div(i64 a, i64 b) {
awsm_assert(b && (a != INT64_MIN || b != -1));
return a / b;
}
INLINE i64 i64_rem(i64 a, i64 b) {
awsm_assert(b != 0);
/* Because MIN is one less than MAX, we can FPE here */
if (unlikely(a == INT64_MIN)) {
return (a + labs(b)) % b;
}
return a % b;
}
// float to integer conversion methods
// In C, float => int conversions always truncate
// If a int2float(int::min_value) <= float <= int2float(int::max_value), it must always be safe to truncate it
u32 u32_trunc_f32(float f) {
float integer_part = 0;
float decimal_part = modff(f, &integer_part);
if (unlikely(integer_part < 0 || integer_part > (float)UINT32_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (u32)f;
}
i32 i32_trunc_f32(float f) {
float integer_part = 0;
float decimal_part = modff(f, &integer_part);
if (unlikely(integer_part < (float)INT32_MIN || integer_part > (float)INT32_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (i32)f;
}
u32 u32_trunc_f64(double f) {
double integer_part = 0;
double decimal_part = modf(f, &integer_part);
if (unlikely(integer_part < 0 || integer_part > (double)UINT32_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (u32)f;
}
i32 i32_trunc_f64(double f) {
double integer_part = 0;
double decimal_part = modf(f, &integer_part);
if (unlikely(integer_part < (double)INT32_MIN || integer_part > (double)INT32_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (i32)f;
}
u64 u64_trunc_f32(float f) {
float integer_part = 0;
float decimal_part = modff(f, &integer_part);
if (unlikely(integer_part < 0 || integer_part > (float)UINT64_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (u64)f;
}
i64 i64_trunc_f32(float f) {
float integer_part = 0;
float decimal_part = modff(f, &integer_part);
if (unlikely(integer_part < (float)INT64_MIN || integer_part > (float)INT64_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (i64)f;
}
u64 u64_trunc_f64(double f) {
double integer_part = 0;
double decimal_part = modf(f, &integer_part);
if (unlikely(integer_part < 0 || integer_part > (double)UINT64_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (u64)f;
}
i64 i64_trunc_f64(double f) {
double integer_part = 0;
double decimal_part = modf(f, &integer_part);
if (unlikely(integer_part < (double)INT64_MIN || integer_part > (double)INT64_MAX)) {
fprintf(stderr, "integer overflow\n");
awsm_assert(0);
}
return (i64)f;
}
// Float => Float truncation functions
INLINE float f32_trunc_f32(float f) {
return truncf(f);
}
INLINE float f32_min(float a, float b) {
return a < b ? a : b;
}
INLINE float f32_max(float a, float b) {
return a > b ? a : b;
}
INLINE float f32_floor(float a) {
return floorf(a);
}
INLINE float f32_ceil(float a) {
return ceilf(a);
}
INLINE float f32_nearest(float a) {
return nearbyintf(a);
}
INLINE float f32_copysign(float a, float b) {
return copysignf(a, b);
}
INLINE double f64_trunc_f64(double f) {
return trunc(f);
}
INLINE double f64_min(double a, double b) {
return a < b ? a : b;
}
INLINE double f64_max(double a, double b) {
return a > b ? a : b;
}
INLINE double f64_floor(double a) {
return floor(a);
}
INLINE double f64_ceil(double a) {
return ceil(a);
}
INLINE double f64_nearest(double a) {
return nearbyint(a);
}
INLINE double f64_copysign(double a, double b) {
return copysign(a, b);
}
/* End of Numeric Instructions */

@ -0,0 +1,86 @@
#include "../../runtime.h"
INLINE float get_f32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i32*)address;
}
INLINE i64 get_i64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i64*)address;
}
INLINE void set_f32(u32 offset, float v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
// NOTE: Legacy C applications could fail this check if they typecast function pointers.
// Additional reference: https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html
awsm_assert(f.type_id == type_id);
awsm_assert(f.func_pointer);
return f.func_pointer;
}

@ -0,0 +1,112 @@
#include "../../runtime.h"
INLINE float get_f32(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(float));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(double));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
// printf_("get %d <= %d - %d\n", offset, memory_size, sizeof(i8));
awsm_assert(offset <= memory_size - sizeof(i8));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i16));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i32));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i32*)address;
}
INLINE i64 get_i64(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i64));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i64*)address;
}
INLINE void set_f32(u32 offset, float v) {
awsm_assert(offset <= memory_size - sizeof(float));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
awsm_assert(offset <= memory_size - sizeof(double));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
// printf_("set %d <= %d - %d\n", offset, memory_size, sizeof(i8));
awsm_assert(offset <= memory_size - sizeof(i8));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
awsm_assert(offset <= memory_size - sizeof(i16));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
awsm_assert(offset <= memory_size - sizeof(i32));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
awsm_assert(offset <= memory_size - sizeof(i64));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id);
awsm_assert(f.func_pointer);
return f.func_pointer;
}

@ -0,0 +1,78 @@
#include "../../runtime.h"
INLINE float get_f32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i32*)address;
}
INLINE i64 get_i64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i64*)address;
}
INLINE void set_f32(u32 offset, float v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
struct indirect_table_entry f = indirect_table[idx];
return f.func_pointer;
}

@ -0,0 +1,180 @@
#include "../../runtime.h"
#define SPT_PAGE_COUNT_ORDER 8
#define SPT_PAGE_COUNT (1 << SPT_PAGE_COUNT_ORDER)
#define SPT_PAGE_SIZE_ORDER 10
#define SPT_PAGE_SIZE (1 << SPT_PAGE_SIZE_ORDER)
static void* PAGE_TABLE[SPT_PAGE_COUNT] = { 0 };
INLINE void* get_page(u32 offset) {
u32 page_number = (offset >> SPT_PAGE_SIZE_ORDER) & ((1 << SPT_PAGE_COUNT_ORDER) - 1);
awsm_assert(page_number < SPT_PAGE_COUNT);
void* page = PAGE_TABLE[page_number];
awsm_assert(page);
return page;
}
INLINE u32 get_page_offset(u32 offset) {
return offset & ((1 << SPT_PAGE_SIZE_ORDER) - 1);
}
INLINE i8 get_i8(u32 offset) {
i8* page = get_page(offset);
u32 page_offset = get_page_offset(offset);
return page[page_offset];
}
INLINE i16 get_i16(u32 offset) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i16)) {
i8* page = get_page(offset);
i16* page_adj = (void*)&page[page_offset];
return *page_adj;
} else {
u8 a = (u8)get_i8(offset);
u8 b = (u8)get_i8(offset + 1);
return (i16)(((u16)b) << 8) | ((u16)a);
}
// u32 page_offset = get_page_offset(offset);
// i8* page = get_page(offset);
// i16* page_adj = (void*) &page[page_offset];
// printf("Regularly loaded: %p\n", (void*) (u64) *page_adj);
//
// u8 a = (u8) get_i8(offset);
// u8 b = (u8) get_i8(offset + 1);
// i16 split = (i16) (((u16) b) << 8) | ((u16) a);
// printf("Split from (%p, %p)\n", (void*) (u64) a, (void*) (u64) b);
// printf("Split loaded: %p\n", (void*) (u64) split);
//
// awsm_assert(*page_adj == split);
// return *page_adj;
}
INLINE i32 get_i32(u32 offset) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i32)) {
i8* page = get_page(offset);
i32* page_adj = (void*)&page[page_offset];
return *page_adj;
} else {
u16 a = (u16)get_i16(offset);
u16 b = (u16)get_i16(offset + 2);
return (i32)(((u32)b) << 16) | ((u32)a);
}
}
INLINE i64 get_i64(u32 offset) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i64)) {
i8* page = get_page(offset);
i64* page_adj = (void*)&page[page_offset];
return *page_adj;
} else {
u32 a = (u32)get_i32(offset);
u32 b = (u32)get_i32(offset + 4);
return (i64)(((u64)b) << 32) | ((u64)a);
}
}
INLINE float get_f32(u32 offset) {
union {
i32 i;
float f;
} a;
a.i = get_i32(offset);
return a.f;
}
INLINE double get_f64(u32 offset) {
union {
i64 i;
double f;
} a;
a.i = get_i64(offset);
return a.f;
}
// Setting routines
INLINE void set_i8(u32 offset, i8 v) {
i8* page = get_page(offset);
u32 page_offset = get_page_offset(offset);
page[page_offset] = v;
}
INLINE void set_i16(u32 offset, i16 v) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i16)) {
i8* page = get_page(offset);
i16* page_adj = (void*)&page[page_offset];
*page_adj = v;
} else {
u16 v2 = (u16)v;
set_i8(offset, (i8)v2);
set_i8(offset + 1, (i8)(v2 >> 8));
}
}
INLINE void set_i32(u32 offset, i32 v) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i32)) {
i8* page = get_page(offset);
i32* page_adj = (void*)&page[page_offset];
*page_adj = v;
} else {
u32 v2 = (u32)v;
set_i16(offset, (i16)v2);
set_i16(offset + 2, (i16)(v2 >> 16));
}
}
INLINE void set_i64(u32 offset, i64 v) {
u32 page_offset = get_page_offset(offset);
if (page_offset < SPT_PAGE_SIZE - sizeof(i64)) {
i8* page = get_page(offset);
i64* page_adj = (void*)&page[page_offset];
*page_adj = v;
} else {
u64 v2 = (u64)v;
set_i32(offset, (i32)v2);
set_i32(offset + 4, (i32)(v2 >> 32));
}
}
INLINE void set_f32(u32 offset, float v) {
union {
i32 i;
float f;
} a;
a.f = v;
set_i32(offset, a.i);
}
INLINE void set_f64(u32 offset, double v) {
union {
i64 i;
double f;
} a;
a.f = v;
set_i64(offset, a.i);
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id);
awsm_assert(f.func_pointer);
return f.func_pointer;
}

@ -0,0 +1,93 @@
#include "../../runtime.h"
#define MEM_SIZE (WASM_PAGE_SIZE * 1 << 2)
char CORTEX_M_MEM[MEM_SIZE + sizeof(u64)] = { 0 };
INLINE float get_f32(u32 offset) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
return *(i16*)&CORTEX_M_MEM[offset % MEM_SIZE];
}
INLINE i32 get_i32(u32 offset) {
return *(i32*)&CORTEX_M_MEM[offset % MEM_SIZE];
}
INLINE i64 get_i64(u32 offset) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
return *(i64*)address;
}
INLINE void set_f32(u32 offset, float v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
offset = offset % MEM_SIZE;
void* address = &CORTEX_M_MEM[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id);
awsm_assert(f.func_pointer);
return f.func_pointer;
}

@ -0,0 +1,108 @@
#include "../../runtime.h"
INLINE float get_f32(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(float));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(double));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i8));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i16));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i32));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i32*)address;
}
INLINE i64 get_i64(u32 offset) {
awsm_assert(offset <= memory_size - sizeof(i64));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i64*)address;
}
INLINE void set_f32(u32 offset, float v) {
awsm_assert(offset <= memory_size - sizeof(float));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
awsm_assert(offset <= memory_size - sizeof(double));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
awsm_assert(offset <= memory_size - sizeof(i8));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
awsm_assert(offset <= memory_size - sizeof(i16));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
awsm_assert(offset <= memory_size - sizeof(i32));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
awsm_assert(offset <= memory_size - sizeof(i64));
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id);
awsm_assert(f.func_pointer);
return f.func_pointer;
}

@ -0,0 +1,128 @@
#include "../../runtime.h"
#define MPX_BC(adr, sz) \
{ asm volatile("bndcu " #sz "(%0), %%bnd0" : : "r"(adr)); }
INLINE float get_f32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
// Bounds check
MPX_BC(address, 0x3);
float v = *(float*)address;
return v;
}
INLINE double get_f64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x7);
double v = *(double*)address;
return v;
}
INLINE i8 get_i8(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x0);
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x1);
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x3);
i32 v = *(i32*)address;
return v;
}
INLINE i64 get_i64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x7);
i64 v = *(i64*)address;
return v;
}
INLINE void set_f32(u32 offset, float v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x3);
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x7);
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x0);
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x1);
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x3);
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
MPX_BC(address, 0x7);
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id);
awsm_assert(f.func_pointer);
return f.func_pointer;
}

@ -0,0 +1,78 @@
#include "../../runtime.h"
INLINE float get_f32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(float*)address;
}
INLINE double get_f64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(double*)address;
}
INLINE i8 get_i8(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i8*)address;
}
INLINE i16 get_i16(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i16*)address;
}
INLINE i32 get_i32(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i32*)address;
}
INLINE i64 get_i64(u32 offset) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
return *(i64*)address;
}
INLINE void set_f32(u32 offset, float v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(float*)address = v;
}
INLINE void set_f64(u32 offset, double v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(double*)address = v;
}
INLINE void set_i8(u32 offset, i8 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i8*)address = v;
}
INLINE void set_i16(u32 offset, i16 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i16*)address = v;
}
INLINE void set_i32(u32 offset, i32 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i32*)address = v;
}
INLINE void set_i64(u32 offset, i64 v) {
char* mem_as_chars = (char*)memory;
void* address = &mem_as_chars[offset];
*(i64*)address = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
struct indirect_table_entry f = indirect_table[idx];
return f.func_pointer;
}

@ -0,0 +1,68 @@
#include "../../runtime.h"
#define GS_REL __attribute__((address_space(256)))
INLINE float get_f32(u32 offset) {
return *((GS_REL float*)offset);
}
INLINE double get_f64(u32 offset) {
return *((GS_REL double*)offset);
}
INLINE i8 get_i8(u32 offset) {
return *((GS_REL i8*)offset);
}
INLINE i16 get_i16(u32 offset) {
return *((GS_REL i16*)offset);
}
INLINE i32 get_i32(u32 offset) {
return *((GS_REL i32*)offset);
}
INLINE i64 get_i64(u32 offset) {
return *((GS_REL i64*)offset);
}
INLINE void set_f32(u32 offset, float v) {
GS_REL float* ptr = (GS_REL float*)offset;
*ptr = v;
}
INLINE void set_f64(u32 offset, double v) {
GS_REL double* ptr = (GS_REL double*)offset;
*ptr = v;
}
INLINE void set_i8(u32 offset, i8 v) {
GS_REL i8* ptr = (GS_REL i8*)offset;
*ptr = v;
}
INLINE void set_i16(u32 offset, i16 v) {
GS_REL i16* ptr = (GS_REL i16*)offset;
*ptr = v;
}
INLINE void set_i32(u32 offset, i32 v) {
GS_REL i32* ptr = (GS_REL i32*)offset;
*ptr = v;
}
INLINE void set_i64(u32 offset, i64 v) {
GS_REL i64* ptr = (GS_REL i64*)offset;
*ptr = v;
}
INLINE char* get_function_from_table(u32 idx, u32 type_id) {
awsm_assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = indirect_table[idx];
awsm_assert(f.type_id == type_id);
awsm_assert(f.func_pointer);
return f.func_pointer;
}

@ -1,6 +1,7 @@
WASMCC=${WASI_SDK_PATH}/bin/clang --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot
WASMLINKFLAGS=-Wl,--allow-undefined,-z,stack-size=32768,--threads=1
OPTFLAGS=-O0 -g
ARCH=64bit_nix
# Log all WASI syscalls and arguments to stderr
# RUNTIME_CFLAGS += -DLOG_WASI
@ -60,18 +61,20 @@ bc/%.bc: wasm/%.wasm
../../runtime/thirdparty/dist/lib/libuv_a.a:
make -C ../../runtime/thirdparty libuv.install
UVWASI_CFILES=../../runtime/runtime.c ../../runtime/libc/wasi/wasi_backing.c ../../runtime/libc/wasi/wasi_main.c ../../runtime/libc/wasi/wasi_impl_uvwasi.c ../../runtime/libc/env.c ../../runtime/memory/64bit_nix.c
UVWASI_CFILES=../../runtime/runtime.c ../../runtime/libc/wasi/wasi_backing.c ../../runtime/libc/wasi/wasi_main.c ../../runtime/libc/wasi/wasi_impl_uvwasi.c ../../runtime/libc/env.c ../../runtime/memory/${ARCH}.c
UVWASI_LIBS=../../runtime/thirdparty/dist/lib/libuvwasi_a.a ../../runtime/thirdparty/dist/lib/libuv_a.a
UVWASI_INCLUDES=-I../../runtime/libc/wasi/include -I../../runtime/thirdparty/dist/include
vm/%_vm: bc/%.bc ${UVWASI_CFILES} ${UVWASI_LIBS}
WASM_INSTRUCTIONS=../../runtime/wasm_instructions/common.c ../../runtime/wasm_instructions/memory/${ARCH}.c
vm/%_vm: bc/%.bc ${UVWASI_CFILES} ${UVWASI_LIBS} ${WASM_INSTRUCTIONS}
clang -pthread -ldl -lm ${OPTFLAGS} ${RUNTIME_CFLAGS} ${UVWASI_INCLUDES} $^ -o $@
# Using minimal backend
# vm/%_vm: bc/%.bc ../../runtime/runtime.c ../../runtime/libc/wasi/wasi_backing.c ../../runtime/libc/wasi/wasi_main.c ../../runtime/libc/wasi/wasi_impl_minimal.c ../../runtime/libc/env.c ../../runtime/memory/64bit_nix.c
# clang -pthread -ldl -lm ${OPTFLAGS} ${RUNTIME_CFLAGS} -I../../runtime/libc/wasi/include -I../../runtime/uvwasi/include $< ../../runtime/runtime.c ../../runtime/libc/wasi/wasi_main.c ../../runtime/libc/wasi/wasi_backing.c ../../runtime/libc/wasi/wasi_impl_minimal.c ../../runtime/libc/env.c ../../runtime/memory/64bit_nix.c -o $@
# vm/%_vm: bc/%.bc ../../runtime/runtime.c ../../runtime/libc/wasi/wasi_backing.c ../../runtime/libc/wasi/wasi_main.c ../../runtime/libc/wasi/wasi_impl_minimal.c ../../runtime/libc/env.c ../../runtime/memory/${ARCH}.c
# clang -pthread -ldl -lm ${OPTFLAGS} ${RUNTIME_CFLAGS} -I../../runtime/libc/wasi/include -I../../runtime/uvwasi/include $< ../../runtime/runtime.c ../../runtime/libc/wasi/wasi_main.c ../../runtime/libc/wasi/wasi_backing.c ../../runtime/libc/wasi/wasi_impl_minimal.c ../../runtime/libc/env.c ../../runtime/memory/${ARCH}.c -o $@
.PHONY clean:
rm -f ./wasm/* ./bc/* ./vm/*_vm

@ -1,5 +1,6 @@
ROOT_PATH:=$(shell cd ../.. && realpath .)
RUNTIME_PATH:=${ROOT_PATH}/runtime
ARCH=64bit_nix
CC=clang
OPTFLAGS=-O0 -g -flto
@ -7,7 +8,9 @@ AWSM_CC:=${ROOT_PATH}/target/debug/awsm
RUNTIME_CFILES+=${RUNTIME_PATH}/runtime.c
RUNTIME_CFILES+=${RUNTIME_PATH}/libc/env.c
RUNTIME_CFILES+=${RUNTIME_PATH}/memory/64bit_nix.c
RUNTIME_CFILES+=${RUNTIME_PATH}/memory/${ARCH}.c
WASM_INSTRUCTIONS=${RUNTIME_PATH}/wasm_instructions/common.c ${RUNTIME_PATH}/wasm_instructions/memory/${ARCH}.c
WASMCEPTION_RUNTIME_CFILES=${RUNTIME_CFILES} ${RUNTIME_PATH}/libc/wasmception_backing.c
@ -73,7 +76,7 @@ clean:
@wasmtime $^
# Using wasmception backend
%.wasmception.out: %.wasmception.bc ${WASMCEPTION_RUNTIME_CFILES}
%.wasmception.out: %.wasmception.bc ${WASMCEPTION_RUNTIME_CFILES} ${WASM_INSTRUCTIONS}
@${CC} -lm ${OPTFLAGS} $^ -o $@
# Using uvwasi backend
@ -87,11 +90,11 @@ clean:
@echo "Installing uvwasi"
@make -C ../../runtime/thirdparty uvwasi.install
%.uvwasi.out: %.bc ${UVWASI_CFILES} ${UVWASI_LIBS}
%.uvwasi.out: %.bc ${UVWASI_CFILES} ${UVWASI_LIBS} ${WASM_INSTRUCTIONS}
@${CC} -pthread -ldl -lm ${OPTFLAGS} ${RUNTIME_CFLAGS} ${UVWASI_INCLUDES} $^ -o $@
%.minimal.out: %.bc ${MINIMAL_CFILES} ../../runtime/thirdparty/dist/include
@${CC} -lm ${OPTFLAGS} ${RUNTIME_CFLAGS} ${MINIMAL_INCLUDES} ${MINIMAL_CFILES} $< -o $@
%.minimal.out: %.bc ${MINIMAL_CFILES} ${WASM_INSTRUCTIONS}
@${CC} -lm ${OPTFLAGS} ${RUNTIME_CFLAGS} ${MINIMAL_INCLUDES} $^ -o $@
.PHONY: uvwasi.out
uvwasi.out: $(patsubst %.wat, %.uvwasi.out, $(wildcard *.wat))

@ -3,6 +3,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
;; $default: natural alignment, $1: align=1, $2: align=2, $4: align=4, $8: align=8

@ -4,6 +4,7 @@
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
;; Auxiliary definition
(memory 1)
(export "memory" (memory 0))
(func $dummy)

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $break-inner (export "break-inner") (result i32)
(local i32)

@ -117,6 +117,7 @@
)
(memory 1)
(export "memory" (memory 0))
(func $as-unary-operand (export "as-unary-operand") (result f32)
(block (result f32) (f32.neg (br 0 (f32.const 3.4))))

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-binary-both (export "as-binary-both") (result i32)
(block (result i32) (i32.add (br 0 (i32.const 46))))
)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-binary-left (export "as-binary-left") (result i32)
(block (result i32) (i32.add (br 0 (i32.const 3)) (i32.const 10)))
)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $dummy)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $dummy)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(func $as-call-all (export "as-call-all") (result i32)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(func $as-call-first (export "as-call-first") (result i32)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(func $as-call-last (export "as-call-last") (result i32)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(func $as-call-mid (export "as-call-mid") (result i32)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(type $sig (func (param i32 i32 i32) (result i32)))

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(type $sig (func (param i32 i32 i32) (result i32)))

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(type $sig (func (param i32 i32 i32) (result i32)))

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(type $sig (func (param i32 i32 i32) (result i32)))

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(type $sig (func (param i32 i32 i32) (result i32)))

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-compare-both (export "as-compare-both") (result i32)
(block (result i32) (f64.le (br 0 (i32.const 44))))
)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-compare-left (export "as-compare-left") (result i32)
(block (result i32) (f64.le (br 0 (i32.const 43)) (f64.const 10)))
)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-compare-right (export "as-compare-right") (result i32)
(block (result i32) (f32.ne (f32.const 10) (br 0 (i32.const 42))))

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-convert-operand (export "as-convert-operand") (result i32)
(block (result i32) (i32.wrap_i64 (br 0 (i32.const 41))))
)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(global $a (mut i32) (i32.const 10))
(func $as-global.set-value (export "as-global.set-value") (result i32)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-if-cond (export "as-if-cond") (result i32)
(block (result i32)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-load-address (export "as-load-address") (result f32)
(block (result f32) (f32.load (br 0 (f32.const 1.7))))
)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-loadN-address (export "as-loadN-address") (result i64)
(block (result i64) (i64.load8_s (br 0 (i64.const 30))))
)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-memory.grow-size (export "as-memory.grow-size") (result i32)
(block (result i32) (memory.grow (br 0 (i32.const 40))))
)

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $as-select-all (export "as-select-all") (result i32)
(block (result i32) (select (br 0 (i32.const 8))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $as-select-cond (export "as-select-cond") (result i32)
(block (result i32)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-select-first (export "as-select-first") (param i32 i32) (result i32)
(block (result i32)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-select-second (export "as-select-second") (param i32 i32) (result i32)
(block (result i32)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-store-address (export "as-store-address") (result i32)
(block (result i32)
(f64.store (br 0 (i32.const 30)) (f64.const 7)) (i32.const -1)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-store-both (export "as-store-both") (result i32)
(block (result i32)
(i64.store (br 0 (i32.const 32))) (i32.const -1)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-store-value (export "as-store-value") (result i32)
(block (result i32)
(i64.store (i32.const 2) (br 0 (i32.const 31))) (i32.const -1)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-storeN-address (export "as-storeN-address") (result i32)
(block (result i32)
(i32.store8 (br 0 (i32.const 32)) (i32.const 7)) (i32.const -1)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-storeN-both (export "as-storeN-both") (result i32)
(block (result i32)
(i64.store16 (br 0 (i32.const 34))) (i32.const -1)

@ -1,7 +1,8 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-storeN-value (export "as-storeN-value") (result i32)
(block (result i32)
(i64.store16 (i32.const 2) (br 0 (i32.const 33))) (i32.const -1)

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-f32-f32 (export "type-f32-f32") (block (drop (f32.add (br 0)))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-f32 (export "type-f32") (block (drop (f32.neg (br 0)))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-f64-f64 (export "type-f64-f64") (block (drop (f64.add (br 0)))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-f64 (export "type-f64") (block (drop (f64.neg (br 0)))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-i32-i32 (export "type-i32-i32") (block (drop (i32.add (br 0)))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-i32-value (export "type-i32-value") (result i32)
(block (result i32) (i32.ctz (br 0 (i32.const 1))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-i32 (export "type-i32")
(block (drop (i32.ctz (br 0))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-i64-i64 (export "type-i64-i64") (block (drop (i64.add (br 0)))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-i64-value (export "type-i64-value") (result i64)
(block (result i64) (i64.ctz (br 0 (i64.const 2))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $type-i64 (export "type-i64")
(block (drop (i64.ctz (br 0))))

@ -2,7 +2,7 @@
(memory 2)
(export "memory" (memory 0))
(table $tbl 0 anyfunc)
(table $tbl 0 funcref)
(func $shouldNotUse (export "_start") (result i32)
(block

@ -5,7 +5,7 @@
(memory 1)
(export "memory" (memory 0))
;; (table $tbl 0 anyfunc)
;; (table $tbl 0 funcref)
(func $dummy)

@ -931,6 +931,7 @@
)
(memory 1)
(export "memory" (memory 0))
(func $as-unary-operand (export "as-unary-operand") (result f32)
(block (result f32) (f32.neg (br_table 0 (f32.const 3.4) (i32.const 0))))

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $dummy)

@ -1,5 +1,6 @@
(module
(memory 1)
(export "memory" (memory 0))
(func $dummy)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(type $sig (func (param i32 i32 i32) (result i32)))

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(type $sig (func (param i32 i32 i32) (result i32)))

@ -3,6 +3,7 @@
(import "wasi_snapshot_preview1" "proc_exit"
(func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(type $sig (func (param i32 i32 i32) (result i32)))

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(type $sig (func (param i32 i32 i32) (result i32)))

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-compare-left (export "as-compare-left") (result i32)
(block (result i32)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-compare-right (export "as-compare-right") (result i32)
(block (result i32)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-convert-operand (export "as-convert-operand") (result i32)
(block (result i32)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(global $a (mut i32) (i32.const 10))

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-if-cond (export "as-if-cond") (result i32)
(block (result i32)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-load-address (export "as-load-address") (result f32)
(block (result f32) (f32.load (br_table 0 (f32.const 1.7) (i32.const 1))))

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-loadN-address (export "as-loadN-address") (result i64)
(block (result i64) (i64.load8_s (br_table 0 (i64.const 30) (i32.const 1))))

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $as-loop-first (export "as-loop-first") (result i32)
(loop (result i32)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $dummy)

@ -1,6 +1,7 @@
(module
(import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
(memory 1)
(export "memory" (memory 0))
(func $dummy)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save