initial commit
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 1 Nov 2021 00:27:38 +0000 (19:27 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 1 Nov 2021 00:27:38 +0000 (19:27 -0500)
CHANGELOG [new file with mode: 0644]
Makefile [new file with mode: 0644]
include/bh.h [new file with mode: 0644]
lib/linux_x86_64/include/wasm.h [new file with mode: 0644]
lib/linux_x86_64/include/wasmer.h [new file with mode: 0644]
lib/linux_x86_64/lib/libwasmer.a [new file with mode: 0644]
lib/linux_x86_64/lib/libwasmer.so [new file with mode: 0755]
src/heartbreak.c [new file with mode: 0644]
tests/simp.onyx [new file with mode: 0644]

diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644 (file)
index 0000000..fb76763
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,8 @@
+Release v0.0.1a
+Additions:
+
+Removals:
+
+Changes:
+
+Bugfixes:
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..0bcbf71
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+CC=gcc
+WARNINGS=-Wimplicit -Wmisleading-indentation -Wparentheses -Wsequence-point -Wreturn-type -Wshift-negative-value -Wunused-but-set-parameter -Wunused-but-set-variable -Wunused-function -Wunused-label -Wmaybe-uninitialized -Wsign-compare -Wstrict-overflow -Wduplicated-branches -Wduplicated-cond -Wtrigraphs -Waddress -Wlogical-op
+FLAGS=$(WARNINGS) -O3
+
+INCLUDES=-I./include -I./lib/linux_x86_64/include
+LIBS=-L./lib/linux_x86_64/lib -lwasmer -Wl,-rpath=./lib/linux_x86_64/lib
+TARGET=./bin/heartbreak
+
+OBJECT_FILES=./build/heartbreak.o
+
+build/%.o: src/%.c
+       $(CC) $(FLAGS) $(INCLUDES) -o $@ $(LIBS) -c $<
+
+$(TARGET): $(OBJECT_FILES)
+       $(CC) $(FLAGS) -o $@ $< $(LIBS)
\ No newline at end of file
diff --git a/include/bh.h b/include/bh.h
new file mode 100644 (file)
index 0000000..a3a56f1
--- /dev/null
@@ -0,0 +1,2517 @@
+#ifndef BH_H
+#define BH_H
+
+// NOTE: For lseek64
+#define _LARGEFILE64_SOURCE
+
+#if defined(_WIN32) || defined(_WIN64)
+    #define _BH_WINDOWS 1
+#endif
+
+#if defined(__unix__)
+    #define _BH_LINUX 1
+#endif
+
+#include <sys/stat.h>
+#include <malloc.h>
+#include <time.h>
+
+#ifdef _BH_LINUX
+    #include <errno.h>
+    #include <fcntl.h>
+    #include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h> // TODO: Replace with needed functions
+#include <stdint.h>
+#include <assert.h>
+#include <stdio.h>
+
+#if defined(_MSC_VER) && !defined(_WINDOWS_)
+    #include "small_windows.h"
+#endif
+
+//-------------------------------------------------------------------------------------
+// Better types
+//-------------------------------------------------------------------------------------
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef int8_t i8;
+typedef int16_t i16;
+typedef int32_t i32;
+typedef int64_t i64;
+typedef int64_t isize;
+typedef i32 b32;
+typedef void* ptr;
+typedef float f32;
+typedef double f64;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Better character functions
+//-------------------------------------------------------------------------------------
+b32 char_is_alpha(const char a);
+b32 char_is_num(const char a);
+b32 char_is_alphanum(const char a);
+char charset_contains(const char* charset, char ch);
+b32 char_is_whitespace(const char a);
+b32 char_in_range(const char lo, const char hi, const char a);
+i64 chars_match(char* ptr1, char* ptr2);
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Better math functions
+//-------------------------------------------------------------------------------------
+#define bh_max(a, b)         ((a) > (b) ? (a) : (b))
+#define bh_min(a, b)         ((a) < (b) ? (a) : (b))
+#define bh_clamp(v, a, b)    (bh_min((b), bh_max((a), (v))))
+#define bh_abs(x)            ((x) < 0 ? -(x) : (x))
+#define size_of(x)           (isize) sizeof(x)
+
+static inline u64 log2_dumb(u64 n) {
+    switch (n) {
+    case 1 << 0:  return 0;
+    case 1 << 1:  return 1;
+    case 1 << 2:  return 2;
+    case 1 << 3:  return 3;
+    case 1 << 4:  return 4;
+    case 1 << 5:  return 5;
+    case 1 << 6:  return 6;
+    case 1 << 7:  return 7;
+    case 1 << 8:  return 8;
+    case 1 << 9:  return 9;
+    case 1 << 10: return 10;
+    case 1 << 11: return 11;
+    case 1 << 12: return 12;
+    case 1 << 13: return 13;
+    case 1 << 14: return 14;
+    case 1 << 15: return 15;
+    case 1 << 16: return 16;
+    case 1 << 17: return 17;
+    case 1 << 18: return 18;
+    case 1 << 19: return 19;
+    case 1 << 20: return 20;
+    case 1 << 21: return 21;
+    case 1 << 22: return 22;
+    case 1 << 23: return 23;
+    case 1 << 24: return 24;
+    case 1 << 25: return 25;
+    case 1 << 26: return 26;
+    case 1 << 27: return 27;
+    case 1 << 28: return 28;
+    case 1 << 29: return 29;
+    case 1 << 30: return 30;
+    case 1 << 31: return 31;
+
+    default:   return 0;
+    }
+}
+
+
+
+static inline const char* bh_num_suffix(u64 i) {
+    if (i == 11 || i == 12 || i == 13) return "th";
+
+    switch (i % 10) {
+        case 0: return "th";
+        case 1: return "st";
+        case 2: return "nd";
+        case 3: return "rd";
+        case 4: return "th";
+        case 5: return "th";
+        case 6: return "th";
+        case 7: return "th";
+        case 8: return "th";
+        case 9: return "th";
+
+        default: return "";
+    }
+}
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Conversion functions
+//-------------------------------------------------------------------------------------
+
+// Converts an unsigned integer to the unsigned LEB128 format
+u8* uint_to_uleb128(u64 n, i32* output_length);
+u8* int_to_leb128(i64 n, i32* output_length);
+u8* float_to_ieee754(f32 f, b32 reverse);
+u8* double_to_ieee754(f64 f, b32 reverse);
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Helpful macros
+//-------------------------------------------------------------------------------------
+#define bh_offset_of(Type, elem)        ((isize)&(((Type)*) 0)->elem)
+#define bh_align_of(Type)                bh_offset_of(struct { char c; Type member; }, member)
+#define bh_swap(Type, a, b)                do { Type tmp = (a); (a) = (b); (b) = tmp; } while(0)
+
+#define bh_align(x, a) if ((x) % (a) != 0) (x) += (a) - ((x) % (a));
+
+#define bh_pointer_add(ptr, amm)        ((void *)((u8 *) ptr + amm))
+#define BH_BIT(x)                        (1 << (x))
+#define BH_MASK_SET(var, set, mask)     ((set) ? (var) |= (mask) : (var) &= ~(mask))
+
+#define fori(var, lo, hi)                 for (i64 var = (lo); var < (hi); var++)
+#define forir(var, hi, lo)                for (i64 var = (hi); var >= (lo); var--)
+#define forll(T, var, start, step)        for (T* var = (start); var != NULL; var = (T *) var->step)
+
+#if defined(BH_DEBUG) && !defined(_BH_WINDOWS)
+    #define DEBUG_HERE                        __asm("int $3")
+#else
+    #define DEBUG_HERE
+#endif
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Custom allocators
+//-------------------------------------------------------------------------------------
+
+typedef enum bh_allocator_actions {
+    bh_allocator_action_alloc,
+    bh_allocator_action_free,
+    bh_allocator_action_resize,
+} bh_allocator_actions;
+
+#define BH_ALLOCATOR_PROC(name) \
+ptr name(ptr data, bh_allocator_actions action, \
+         isize size, isize alignment, \
+         void* prev_memory, \
+         u64 flags)
+
+typedef BH_ALLOCATOR_PROC(bh__allocator_proc); // NOTE: so bh__allocator_proc can be used instead of that type
+
+typedef struct bh_allocator {
+    bh__allocator_proc* proc; // Procedure that can handle bh_allocator_actions
+    ptr                    data; // Pointer to the other data for the allocator
+} bh_allocator;
+
+typedef enum bh_allocator_flags {
+    bh_allocator_flag_clear = 1    // Sets all memory to be 0
+} bh_allocator_flags;
+
+ptr bh_alloc(bh_allocator a, isize size);
+ptr bh_alloc_aligned(bh_allocator a, isize size, isize alignment);
+ptr bh_resize(bh_allocator a, ptr data, isize new_size);
+ptr bh_resize_aligned(bh_allocator a, ptr data, isize new_size, isize alignment);
+void bh_free(bh_allocator a, ptr data);
+
+#define bh_alloc_item(allocator_, T)                (T *) bh_alloc(allocator_, sizeof(T))
+#define bh_alloc_array(allocator_, T, n)            (T *) bh_alloc(allocator_, sizeof(T) * (n))
+
+// NOTE: This should get optimized out since alignment should be a power of two
+#define bh__align(x, alignment)                        ((((x) / alignment) + 1) * alignment)
+
+
+
+
+// HEAP ALLOCATOR
+// Essentially a wrapper for malloc, free and realloc
+bh_allocator bh_heap_allocator(void);
+BH_ALLOCATOR_PROC(bh_heap_allocator_proc);
+
+
+
+
+
+// ARENA ALLOCATOR
+typedef struct bh_arena {
+    bh_allocator backing;
+    ptr first_arena, current_arena;
+    isize size, arena_size; // in bytes
+} bh_arena;
+
+typedef struct bh__arena_internal {
+    ptr next_arena;
+    void* data; // Not actually a pointer, just used for the offset
+} bh__arena_internal;
+
+void bh_arena_init(bh_arena* alloc, bh_allocator backing, isize arena_size);
+void bh_arena_free(bh_arena* alloc);
+bh_allocator bh_arena_allocator(bh_arena* alloc);
+BH_ALLOCATOR_PROC(bh_arena_allocator_proc);
+
+
+
+
+
+
+// SCRATCH ALLOCATOR
+typedef struct bh_scratch {
+    bh_allocator backing;
+    ptr memory, end, curr;
+} bh_scratch;
+
+void bh_scratch_init(bh_scratch* scratch, bh_allocator backing, isize scratch_size);
+void bh_scratch_free(bh_scratch* scratch);
+bh_allocator bh_scratch_allocator(bh_scratch* scratch);
+BH_ALLOCATOR_PROC(bh_scratch_allocator_proc);
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Allocator based string functions
+//-------------------------------------------------------------------------------------
+
+b32 bh_str_starts_with(char* str, char* start);
+b32 bh_str_ends_with(char* str, char* end);
+char* bh_strdup(bh_allocator a, char* str);
+
+
+
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Better files
+//-------------------------------------------------------------------------------------
+#ifndef BH_NO_FILE
+
+typedef enum bh_file_error {
+    BH_FILE_ERROR_NONE,
+    BH_FILE_ERROR_INVALID,
+    BH_FILE_ERROR_BAD_FD,
+} bh_file_error;
+
+typedef enum bh_file_mode {
+    BH_FILE_MODE_READ = 1 << 0,
+    BH_FILE_MODE_WRITE = 1 << 1,
+    BH_FILE_MODE_APPEND = 1 << 2,
+    BH_FILE_MODE_RW = 1 << 3,
+
+    BH_FILE_MODE_MODES = BH_FILE_MODE_READ | BH_FILE_MODE_WRITE | BH_FILE_MODE_APPEND | BH_FILE_MODE_RW
+} bh_file_mode;
+
+typedef enum bh_file_whence {
+    BH_FILE_WHENCE_BEGIN = SEEK_SET,
+    BH_FILE_WHENCE_CURRENT = SEEK_CUR,
+    BH_FILE_WHENCE_END = SEEK_END,
+} bh_file_whence;
+
+#ifdef _BH_WINDOWS
+    typedef HANDLE bh_file_descriptor;
+#else
+    typedef int bh_file_descriptor;
+#endif
+
+typedef struct bh_file {
+    bh_file_descriptor fd;
+    char const* filename;
+} bh_file;
+
+typedef enum bh_file_standard {
+    BH_FILE_STANDARD_INPUT,
+    BH_FILE_STANDARD_OUTPUT,
+    BH_FILE_STANDARD_ERROR
+} bh_file_standard;
+
+typedef struct bh_file_contents {
+    bh_allocator allocator;
+    const char *filename;
+    isize length;
+    void* data;
+} bh_file_contents;
+
+bh_file_error bh_file_get_standard(bh_file* file, bh_file_standard stand);
+
+bh_file_error bh_file_create(bh_file* file, char const* filename);
+bh_file_error bh_file_open(bh_file* file, char const* filename);
+bh_file_error bh_file_open_mode(bh_file* file, bh_file_mode mode, const char* filename);
+bh_file_error bh_file_new(bh_file* file, bh_file_descriptor fd, const char* filename);
+b32 bh_file_read_at(bh_file* file, i64 offset, void* buffer, isize buff_size, isize* bytes_read);
+b32 bh_file_write_at(bh_file* file, i64 offset, void const* buffer, isize buff_size, isize* bytes_wrote);
+i64 bh_file_seek_to(bh_file* file, i64 offset);
+i64 bh_file_seek_to_end(bh_file* file);
+i64 bh_file_skip(bh_file* file, i64 bytes);
+i64 bh_file_tell(bh_file* file);
+bh_file_error bh_file_close(bh_file* file);
+i32 bh_file_read(bh_file* file, void* buffer, isize buff_size);
+i32 bh_file_write(bh_file* file, void* buffer, isize buff_size);
+i64 bh_file_size(bh_file* file);
+b32 bh_file_exists(char const* filename);
+char* bh_path_get_full_name(char const* filename, bh_allocator a);
+char* bh_path_get_parent(char const* filename, bh_allocator a);
+
+#define bh_file_read_contents(allocator_, x) _Generic((x), \
+    bh_file*: bh_file_read_contents_bh_file, \
+    const char*: bh_file_read_contents_direct, \
+    char*: bh_file_read_contents_direct)((allocator_), x)
+
+bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file);
+bh_file_contents bh_file_read_contents_direct(bh_allocator alloc, const char* filename);
+i32 bh_file_contents_free(bh_file_contents* contents);
+
+#endif
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Alternate printing
+//-------------------------------------------------------------------------------------
+// Barebones implementation of printf. Does not support all format options
+// Currently supports:
+//         %c - chars
+//        %_(u)d - ints where _ is:
+//            nothing - decimal
+//            o - octal
+//            x - hexadecimal
+//        %_(u)l - longs where _ is:
+//            nothing - decimal
+//            o - octal
+//            x - hexadecimal
+//        %f - floating points
+//        %s - null terminated strings
+//        %p - pointers
+//        %% - literal %
+
+typedef struct bh__print_format {
+    u32 base;
+} bh__print_format;
+
+isize bh_printf(char const *fmt, ...);
+isize bh_printf_va(char const *fmt, va_list va);
+isize bh_printf_err(char const *fmt, ...);
+isize bh_printf_err_va(char const *fmt, va_list va);
+isize bh_fprintf(bh_file* f, char const *fmt, ...);
+isize bh_fprintf_va(bh_file* f, char const *fmt, va_list va);
+char* bh_bprintf(char const *fmt, ...);
+char* bh_bprintf_va(char const *fmt, va_list va);
+char* bh_aprintf(bh_allocator alloc, const char* fmt, ...);
+char* bh_aprintf_va(bh_allocator alloc, const char* fmt, va_list va);
+isize bh_snprintf(char *str, isize n, char const *fmt, ...);
+isize bh_snprintf_va(char *str, isize n, char const *fmt, va_list va);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Flexible buffer
+//-------------------------------------------------------------------------------------
+
+typedef struct bh_buffer {
+    bh_allocator allocator;
+    i32 length, capacity;
+    u8* data;
+} bh_buffer;
+
+#ifndef BH_BUFFER_GROW_FORMULA
+#define BH_BUFFER_GROW_FORMULA(x)            ((x) > 0 ? ((x) << 1) : 16)
+#endif
+
+void bh_buffer_init(bh_buffer* buffer, bh_allocator alloc, i32 length);
+void bh_buffer_free(bh_buffer* buffer);
+void bh_buffer_grow(bh_buffer* buffer, i32 length);
+void bh_buffer_append(bh_buffer* buffer, const void * data, i32 length);
+void bh_buffer_concat(bh_buffer* buffer, bh_buffer other);
+void bh_buffer_write_byte(bh_buffer* buffer, u8 byte);
+void bh_buffer_write_u32(bh_buffer* buffer, u32 i);
+void bh_buffer_write_u64(bh_buffer* buffer, u64 i);
+void bh_buffer_align(bh_buffer* buffer, u32 alignment);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// Better dynamically-sized arrays
+//-------------------------------------------------------------------------------------
+#ifndef BH_NO_ARRAY
+
+typedef struct bh__arr {
+    bh_allocator allocator;
+    i32 length, capacity;
+} bh__arr;
+
+#ifndef BH_ARR_GROW_FORMULA
+#define BH_ARR_GROW_FORMULA(x)       ((x) > 0 ? ((x) << 1) : 4)
+#endif
+
+#define bh_arr(T)                    T*
+#define bh__arrhead(arr)             (((bh__arr *)(arr)) - 1)
+
+#define bh_arr_allocator(arr)        (arr ? bh__arrhead(arr)->allocator : bh_heap_allocator())
+#define bh_arr_length(arr)           (arr ? bh__arrhead(arr)->length : 0)
+#define bh_arr_capacity(arr)         (arr ? bh__arrhead(arr)->capacity : 0)
+#define bh_arr_size(arr)             (arr ? bh__arrhead(arr)->capacity * sizeof(*(arr)) : 0)
+#define bh_arr_valid(arr, i)         (arr ? (i32)(i) < bh__arrhead(arr)->length : 0)
+
+#define bh_arr_pop(arr)              ((arr)[--bh__arrhead(arr)->length])
+#define bh_arr_last(arr)             ((arr)[bh__arrhead(arr)->length - 1])
+#define bh_arr_end(arr, i)           ((i) >= &(arr)[bh_arr_length(arr)])
+#define bh_arr_start(arr, i)         ((i) < (arr))
+
+#define bh_arr_new(allocator_, arr, cap)    (bh__arr_grow((allocator_), (void**) &(arr), sizeof(*(arr)), cap))
+#define bh_arr_free(arr)                    (bh__arr_free((void**) &(arr)))
+#define bh_arr_copy(allocator_, arr)        (bh__arr_copy((allocator_), (arr), sizeof(*(arr))))
+
+#define bh_arr_grow(arr, cap)          (bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), cap))
+#define bh_arr_shrink(arr, cap)        (bh__arr_shrink((void **) &(arr), sizeof(*(arr)), cap))
+#define bh_arr_set_length(arr, n)      (bh__arrhead(arr)->length = n)
+
+#define bh_arr_insertn(arr, i, n)      (bh__arr_insertn((void **) &(arr), sizeof(*(arr)), i, n))
+
+#define bh_arr_insert_end(arr, n)      ( \
+    bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), bh_arr_length(arr) + n), \
+    bh__arrhead(arr)->length += n)
+
+#define bh_arr_push(arr, value)       ( \
+    bh_arr_length(arr) + 1 > bh_arr_capacity(arr) ? bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), bh_arr_length(arr) + 1) : 0, \
+    arr[bh__arrhead(arr)->length++] = value)
+
+#define bh_arr_set_at(arr, n, value) ( \
+    bh__arr_grow(bh_arr_allocator(arr), (void **) &(arr), sizeof(*(arr)), (n) + 1), \
+    bh_arr_set_length((arr), bh_max(bh_arr_length(arr), (i32) (n) + 1)), \
+    arr[n] = value)
+
+#define bh_arr_is_empty(arr)          (arr ? bh__arrhead(arr)->length == 0 : 1)
+#define bh_arr_clear(arr)             (arr ? (bh__arrhead(arr)->length = 0) : 0)
+
+#define bh_arr_deleten(arr, i, n)     (bh__arr_deleten((void **) &(arr), sizeof(*(arr)), i, n))
+#define bh_arr_fastdelete(arr, i)     (arr[i] = arr[--bh__arrhead(arr)->length])
+
+#define bh_arr_each(T, var, arr)      for (T* var = (arr); !bh_arr_end((arr), var); var++)
+#define bh_arr_rev_each(T, var, arr)  for (T* var = &bh_arr_last((arr)); !bh_arr_start((arr), var); var--)
+
+#define bh_arr_zero(arr) memset(arr, 0, bh_arr_length(arr) * sizeof(*(arr)));
+
+b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap);
+b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap);
+b32 bh__arr_free(void **arr);
+void* bh__arr_copy(bh_allocator alloc, void *arr, i32 elemsize);
+void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems);
+void bh__arr_deleten(void **arr, i32 elemsize, i32 index, i32 numelems);
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// STRING HASH TABLE FUNCTIONS
+//-------------------------------------------------------------------------------------
+#ifndef BH_NO_TABLE
+
+#ifdef BH_DEFINE
+u64 bh__table_hash_function(const char* str, i32 len, i32 mod) {
+    u64 hash = 5381;
+    i32 c, l = 0;
+    if (len == 0) len = ((u32) 1 << 31) - 1;
+
+    while ((c = *str++) && l++ < len) {
+        hash = (hash << 5) + hash + c;
+    }
+
+    return hash % mod;
+}
+#endif
+
+typedef struct bh_table_iterator {
+    ptr *tab, *endtab;
+    i32 elemsize, arrlen;
+    ptr entry;
+} bh_table_iterator;
+
+typedef struct bh__table {
+    bh_allocator allocator;
+    u64 table_size; // NOTE: u64 since padding will make it 8-bytes no matter what
+    ptr arrs[];
+} bh__table;
+
+#define bh_table(T)        T*
+
+#ifdef BH_TABLE_SIZE_SAFE
+    #define bh_table_init(allocator_, tab, hs)    bh__table_init(allocator_, (bh__table **)&(tab), hs)
+    #define bh_table_free(tab)                    bh__table_free((bh__table **)&(tab))
+    #define bh_table_put(T, tab, key, value)      (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__table_put((bh__table *) tab, sizeof(T), key)) = (T) value))
+    #define bh_table_has(T, tab, key)             (assert(sizeof(T) == sizeof(*(tab))), (bh__table_has((bh__table *) tab, sizeof(T), key)))
+    #define bh_table_get(T, tab, key)             (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__table_get((bh__table *) tab, sizeof(T), key))))
+    #define bh_table_delete(T, tab, key)          (assert(sizeof(T) == sizeof(*(tab))), bh__table_delete((bh__table *) tab, sizeof(T), key))
+    #define bh_table_clear(tab)                   (bh__table_clear((bh__table *) tab))
+
+    #define bh_table_iter_setup(T, tab)           (assert(sizeof(T) == sizeof(*(tab))), bh__table_iter_setup((bh__table *) tab, sizeof(T)))
+    #define bh_table_iter_key(it)                 ((char *)(bh_pointer_add(it.entry, it.elemsize + sizeof(u16))))
+    #define bh_table_iter_value(T, it)            (*(T *)it.entry)
+#else
+    #define bh_table_init(allocator_, tab, hs)    bh__table_init(allocator_, (bh__table **)&(tab), hs)
+    #define bh_table_free(tab)                    bh__table_free((bh__table **)&(tab))
+    #define bh_table_put(T, tab, key, value)      (*((T *) bh__table_put((bh__table *) tab, sizeof(T), key)) = value)
+    #define bh_table_has(T, tab, key)             (bh__table_has((bh__table *) tab, sizeof(T), key))
+    #define bh_table_get(T, tab, key)             (*((T *) bh__table_get((bh__table *) tab, sizeof(T), key)))
+    #define bh_table_delete(T, tab, key)          (bh__table_delete((bh__table *) tab, sizeof(T), key))
+    #define bh_table_clear(tab)                   (bh__table_clear((bh__table *) tab))
+
+    #define bh_table_iter_setup(T, tab)           (bh__table_iter_setup((bh__table *) tab, sizeof(T)))
+    #define bh_table_iter_key(it)                 ((char *)(bh_pointer_add(it.entry, it.elemsize + sizeof(u16))))
+    #define bh_table_iter_value(T, it)            (*(T *)it.entry)
+#endif
+
+#define bh_table_each_start(T, table) { \
+    bh_table_iterator it = bh_table_iter_setup(T, (table)); \
+    while (bh_table_iter_next(&it)) { \
+        const char* key = bh_table_iter_key(it); \
+        T value = bh_table_iter_value(T, it);
+#define bh_table_each_end            } }
+
+b32 bh__table_init(bh_allocator allocator, bh__table **table, i32 table_size);
+b32 bh__table_free(bh__table **table);
+ptr bh__table_put(bh__table *table, i32 elemsize, char *key);
+b32 bh__table_has(bh__table *table, i32 elemsize, char *key);
+ptr bh__table_get(bh__table *table, i32 elemsize, char *key);
+void bh__table_delete(bh__table *table, i32 elemsize, char *key);
+void bh__table_clear(bh__table *table);
+bh_table_iterator bh__table_iter_setup(bh__table *table, i32 elemsize);
+b32 bh_table_iter_next(bh_table_iterator* it);
+
+#endif
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------
+// IMAP (integer to integer map)
+//-------------------------------------------------------------------------------
+#ifndef BH_NO_IMAP
+
+typedef u64 bh_imap_entry_t;
+
+typedef struct bh__imap_lookup_result {
+    i64 hash_index;
+    i64 entry_prev;
+    i64 entry_index;
+} bh__imap_lookup_result;
+
+typedef struct bh__imap_entry {
+    bh_imap_entry_t key, value;
+    i64 next;
+} bh__imap_entry;
+
+typedef struct bh_imap {
+    bh_allocator allocator;
+
+    bh_arr(i64)            hashes;
+    bh_arr(bh__imap_entry) entries;
+} bh_imap;
+
+
+void bh_imap_init(bh_imap* imap, bh_allocator alloc, i32 hash_count);
+void bh_imap_free(bh_imap* imap);
+void bh_imap_put(bh_imap* imap, bh_imap_entry_t key, bh_imap_entry_t value);
+b32 bh_imap_has(bh_imap* imap, bh_imap_entry_t key);
+bh_imap_entry_t bh_imap_get(bh_imap* imap, bh_imap_entry_t key);
+void bh_imap_delete(bh_imap* imap, bh_imap_entry_t key);
+void bh_imap_clear(bh_imap* imap);
+
+#ifdef BH_DEFINE
+#endif // BH_DEFINE
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+// MANAGED HEAP ALLOCATOR
+typedef struct bh_managed_heap {
+    bh_imap ptrs;
+} bh_managed_heap;
+
+void bh_managed_heap_init(bh_managed_heap* mh);
+void bh_managed_heap_free(bh_managed_heap* mh);
+bh_allocator bh_managed_heap_allocator(bh_managed_heap* mh);
+BH_ALLOCATOR_PROC(bh_managed_heap_allocator_proc);
+
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------
+// OTHER COMMON DATA STRUCTURES
+//-------------------------------------------------------------------------------
+#ifndef BH_NO_DATASTRUCTURES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif // BH_NO_DATASTRUCTURES
+
+
+
+
+
+//------------------------------------------------------------------------------
+// TIME / DURATION
+//------------------------------------------------------------------------------
+u64 bh_time_curr();
+u64 bh_time_duration(u64 old);
+
+
+
+
+
+
+
+
+
+
+
+#ifdef BH_DEFINE
+
+#undef BH_DEFINE
+//-------------------------------------------------------------------------------------
+// IMPLEMENTATIONS
+//-------------------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------------------
+// CHAR FUNCTIONS
+//-------------------------------------------------------------------------------------
+
+b32 char_is_alpha(const char a) {
+    return ('a' <= a && a <= 'z') || ('A' <= a && a <= 'Z');
+}
+
+char charset_contains(const char* charset, char ch) {
+    while (*charset) {
+        if (*charset == ch) return ch;
+        charset++;
+    }
+
+    return 0;
+}
+
+b32 char_is_num(const char a) {
+    return ('0' <= a && a <= '9');
+}
+
+b32 char_is_alphanum(const char a) {
+    return char_is_alpha(a) || char_is_num(a);
+}
+
+b32 char_is_whitespace(const char a) {
+    return charset_contains(" \t\r\n", a);
+}
+
+b32 char_in_range(const char lo, const char hi, const char a) {
+    return lo <= a && a <= hi;
+}
+
+i64 chars_match(char* ptr1, char* ptr2) {
+    i64 len = 0;
+    while (*ptr2 != '\0' && *ptr1 == *ptr2) ptr1++, ptr2++, len++;
+    return *ptr2 == '\0' ? len : 0;
+}
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// CUSTOM ALLOCATORS IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+ptr bh_alloc(bh_allocator a, isize size) {
+    return bh_alloc_aligned(a, size, 16);
+}
+
+ptr bh_alloc_aligned(bh_allocator a, isize size, isize alignment) {
+    return a.proc(a.data, bh_allocator_action_alloc, size, alignment, NULL,  0);
+}
+
+ptr bh_resize(bh_allocator a, ptr data, isize new_size) {
+    return bh_resize_aligned(a, data, new_size, 16);
+}
+
+ptr bh_resize_aligned(bh_allocator a, ptr data, isize new_size, isize alignment) {
+    return a.proc(a.data, bh_allocator_action_resize, new_size, alignment, data, 0);
+}
+
+void bh_free(bh_allocator a, ptr data) {
+    if (data != NULL) a.proc(a.data, bh_allocator_action_free, 0, 0, data, 0);
+}
+
+
+
+// HEAP ALLOCATOR IMPLEMENTATION
+bh_allocator bh_heap_allocator(void) {
+    return (bh_allocator) {
+        .proc = bh_heap_allocator_proc,
+        .data = NULL
+    };
+}
+
+BH_ALLOCATOR_PROC(bh_heap_allocator_proc) {
+    ptr retval = NULL;
+
+    switch (action) {
+    case bh_allocator_action_alloc: {
+#if defined(_BH_WINDOWS)
+        retval = _aligned_malloc(size, alignment);
+#elif defined(_BH_LINUX)
+        i32 success = posix_memalign(&retval, alignment, size);
+#endif
+        if (flags & bh_allocator_flag_clear && retval != NULL) {
+            memset(retval, 0, size);
+        }
+    } break;
+
+    case bh_allocator_action_resize: {
+        // TODO: Maybe replace with better custom function
+#if defined(_BH_WINDOWS)
+        retval = _aligned_realloc(prev_memory, size, alignment);
+#elif defined(_BH_LINUX)
+        retval = realloc(prev_memory, size);
+#endif
+    } break;
+
+    case bh_allocator_action_free: {
+#if defined(_BH_WINDOWS)
+        _aligned_free(prev_memory);
+#elif defined(_BH_LINUX)
+        free(prev_memory);
+#endif
+    } break;
+    }
+
+    return retval;
+}
+
+
+
+
+
+
+// MANAGED HEAP ALLOCATOR IMPLEMENTATION
+void bh_managed_heap_init(bh_managed_heap* mh) {
+    bh_imap_init(&mh->ptrs, bh_heap_allocator(), 512);
+}
+
+void bh_managed_heap_free(bh_managed_heap* mh) {
+    bh_arr_each(bh__imap_entry, p, mh->ptrs.entries) {
+#if defined(_BH_WINDOWS)
+        _aligned_free((void *) p->key);
+#elif defined(_BH_LINUX)
+        free((void *) p->key);
+#endif
+    }
+
+    bh_imap_free(&mh->ptrs);
+}
+
+bh_allocator bh_managed_heap_allocator(bh_managed_heap* mh) {
+    return (bh_allocator) {
+        .proc = bh_managed_heap_allocator_proc,
+        .data = mh
+    };
+}
+
+BH_ALLOCATOR_PROC(bh_managed_heap_allocator_proc) {
+    bh_managed_heap* mh = (bh_managed_heap *) data;
+    ptr retval = NULL;
+
+    switch (action) {
+    case bh_allocator_action_alloc: {
+#if defined(_BH_WINDOWS)
+        retval = _aligned_malloc(size, alignment);
+#elif defined(_BH_LINUX)
+        i32 success = posix_memalign(&retval, alignment, size);
+#endif
+
+        if (flags & bh_allocator_flag_clear && retval != NULL) {
+            memset(retval, 0, size);
+        }
+
+        if (retval != NULL)
+            bh_imap_put(&mh->ptrs, (u64) retval, 1);
+    } break;
+
+    case bh_allocator_action_resize: {
+        bh_imap_delete(&mh->ptrs, (u64) prev_memory);
+#if defined(_BH_WINDOWS)
+        retval = _aligned_realloc(prev_memory, size, alignment);
+#elif defined(_BH_LINUX)
+        retval = realloc(prev_memory, size);
+#endif
+        bh_imap_put(&mh->ptrs, (u64) retval, 1);
+    } break;
+
+    case bh_allocator_action_free: {
+        bh_imap_delete(&mh->ptrs, (u64) prev_memory);
+#if defined(_BH_WINDOWS)
+        _aligned_free(prev_memory);
+#elif defined(_BH_LINUX)
+        free(prev_memory);
+#endif
+    } break;
+    }
+
+    return retval;
+}
+
+
+
+
+
+
+
+
+// ARENA ALLOCATOR IMPLEMENTATION
+void bh_arena_init(bh_arena* alloc, bh_allocator backing, isize arena_size) {
+    arena_size = bh_max(arena_size, size_of(ptr));
+    ptr data = bh_alloc(backing, arena_size);
+
+    alloc->backing = backing;
+    alloc->arena_size = arena_size;
+    alloc->size = sizeof(ptr);
+    alloc->first_arena = data;
+    alloc->current_arena = data;
+
+    ((bh__arena_internal *)(alloc->first_arena))->next_arena = NULL;
+}
+
+void bh_arena_free(bh_arena* alloc) {
+    bh__arena_internal *walker = (bh__arena_internal *) alloc->first_arena;
+    bh__arena_internal *trailer = walker;
+    while (walker != NULL) {
+        walker = walker->next_arena;
+        bh_free(alloc->backing, trailer);
+        trailer = walker;
+    }
+
+    alloc->first_arena = NULL;
+    alloc->current_arena = NULL;
+    alloc->arena_size = 0;
+    alloc->size = 0;
+}
+
+bh_allocator bh_arena_allocator(bh_arena* alloc) {
+    return (bh_allocator) {
+        .proc = bh_arena_allocator_proc,
+        .data = alloc,
+    };
+}
+
+BH_ALLOCATOR_PROC(bh_arena_allocator_proc) {
+    bh_arena* alloc_arena = (bh_arena*) data;
+
+    ptr retval = NULL;
+
+    switch (action) {
+    case bh_allocator_action_alloc: {
+        bh_align(size, alignment);
+        bh_align(alloc_arena->size, alignment);
+
+        if (size > alloc_arena->arena_size - size_of(ptr)) {
+            // Size too large for the arena
+            return NULL;
+        }
+
+        if (alloc_arena->size + size >= alloc_arena->arena_size) {
+            bh__arena_internal* new_arena = (bh__arena_internal *) bh_alloc(alloc_arena->backing, alloc_arena->arena_size);
+
+            if (new_arena == NULL) {
+                bh_printf_err("Arena Allocator: couldn't allocate new arena");
+                return NULL;
+            }
+
+            new_arena->next_arena = NULL;
+            ((bh__arena_internal *)(alloc_arena->current_arena))->next_arena = new_arena;
+            alloc_arena->current_arena = new_arena;
+            alloc_arena->size = sizeof(ptr);
+        }
+
+        retval = bh_pointer_add(alloc_arena->current_arena, alloc_arena->size);
+        alloc_arena->size += size;
+    } break;
+
+    case bh_allocator_action_resize: {
+        // Do nothing since this is a fixed allocator
+    } break;
+
+    case bh_allocator_action_free: {
+        // Do nothing since this allocator isn't made for freeing memory
+    } break;
+    }
+
+    return retval;
+}
+
+
+
+
+// SCRATCH ALLOCATOR IMPLEMENTATION
+void bh_scratch_init(bh_scratch* scratch, bh_allocator backing, isize scratch_size) {
+    ptr memory = bh_alloc(backing, scratch_size);
+
+    scratch->backing = backing;
+    scratch->memory = memory;
+    scratch->curr = memory;
+    scratch->end = bh_pointer_add(memory, scratch_size);
+}
+
+void bh_scratch_free(bh_scratch* scratch) {
+    bh_free(scratch->backing, scratch->memory);
+
+    scratch->memory = NULL;
+    scratch->curr = NULL;
+    scratch->end = NULL;
+}
+
+bh_allocator bh_scratch_allocator(bh_scratch* scratch) {
+    return (bh_allocator) {
+        .proc = bh_scratch_allocator_proc,
+        .data = scratch,
+    };
+}
+
+BH_ALLOCATOR_PROC(bh_scratch_allocator_proc) {
+    bh_scratch* scratch = (bh_scratch*) data;
+    ptr retval = NULL;
+
+    switch (action) {
+    case bh_allocator_action_alloc: {
+        if (size > ((u8 *) scratch->end) - ((u8 *) scratch->memory)) {
+            return NULL;
+        }
+
+        retval = scratch->curr;
+        scratch->curr = bh_pointer_add(scratch->curr, size);
+
+        if (scratch->curr >= scratch->end) {
+            scratch->curr = scratch->memory;
+            retval = scratch->curr;
+        }
+    } break;
+
+    case bh_allocator_action_free: break;
+
+    case bh_allocator_action_resize: {
+        if (size > ((u8 *) scratch->end) - ((u8 *) scratch->memory)) {
+            return NULL;
+        }
+
+        retval = scratch->curr;
+        scratch->curr = bh_pointer_add(scratch->curr, size);
+
+        if (scratch->curr >= scratch->end) {
+            scratch->curr = scratch->memory;
+            retval = scratch->curr;
+        }
+
+        // HACK!!!!!: Using size instead of some kind of "old size"
+        memcpy(retval, prev_memory, size);
+    } break;
+    }
+
+    return retval;
+}
+
+
+
+
+//-------------------------------------------------------------------------------------
+// CONVERSION FUNCTIONS IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+u8* uint_to_uleb128(u64 n, i32* output_length) {
+    static u8 buffer[16];
+
+    *output_length = 0;
+    u8* output = buffer;
+    u8 byte;
+    do {
+        byte = n & 0x7f;
+        n >>= 7;
+        if (n != 0) byte |= (1 << 7);
+        *output++ = byte;
+        (*output_length)++;
+    } while (n != 0);
+
+    return buffer;
+}
+
+
+// Converts a signed integer to the signed LEB128 format
+u8* int_to_leb128(i64 n, i32* output_length) {
+    static u8 buffer[16];
+
+    *output_length = 0;
+    u8* output = buffer;
+    b32 more = 1;
+
+    i32 size = 64;
+
+    u8 byte;
+    do {
+        byte = n & 0x7f;
+        n >>= 7;
+
+        more = !(((n == 0) && (byte & 0x40) == 0) || ((n == -1) && (byte & 0x40) != 0));
+        if (more)
+            byte |= 0x80;
+        *output++ = byte;
+        (*output_length)++;
+    } while (more);
+
+    return buffer;
+}
+
+// NOTE: This assumes the underlying implementation of float on the host
+// system is already IEEE-754. This is safe to assume in most cases.
+u8* float_to_ieee754(f32 f, b32 reverse) {
+    static u8 buffer[4];
+
+    u8* fmem = (u8*) &f;
+    if (reverse) {
+        buffer[0] = fmem[3];
+        buffer[1] = fmem[2];
+        buffer[2] = fmem[1];
+        buffer[3] = fmem[0];
+    } else {
+        buffer[0] = fmem[0];
+        buffer[1] = fmem[1];
+        buffer[2] = fmem[2];
+        buffer[3] = fmem[3];
+    }
+
+    return buffer;
+}
+
+u8* double_to_ieee754(f64 f, b32 reverse) {
+    static u8 buffer[8];
+
+    u8* fmem = (u8*) &f;
+    if (reverse) {
+        buffer[0] = fmem[7];
+        buffer[1] = fmem[6];
+        buffer[2] = fmem[5];
+        buffer[3] = fmem[4];
+        buffer[4] = fmem[3];
+        buffer[5] = fmem[2];
+        buffer[6] = fmem[1];
+        buffer[7] = fmem[0];
+    } else {
+        buffer[0] = fmem[0];
+        buffer[1] = fmem[1];
+        buffer[2] = fmem[2];
+        buffer[3] = fmem[3];
+        buffer[4] = fmem[4];
+        buffer[5] = fmem[5];
+        buffer[6] = fmem[6];
+        buffer[7] = fmem[7];
+    }
+
+    return buffer;
+}
+
+
+
+
+//-------------------------------------------------------------------------------------
+// STRING IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+b32 bh_str_starts_with(char* str, char* start) {
+    char* s = str;
+    char* p = start;
+
+    while (*s != '\0' && *p != '\0' && *s == *p) s++, p++;
+
+    return *p == '\0';
+}
+
+b32 bh_str_ends_with(char* str, char* end) {
+    i32 slen = strlen(str);
+    i32 elen = strlen(end);
+
+    char* s = str + slen - 1;
+    char* e = end + elen - 1;
+
+    while (*e == *s && e != end && s != str) e--, s--;
+
+    return *e == *s;
+}
+
+char* bh_strdup(bh_allocator a, char* str) {
+    u32 len = strlen(str);
+    char* buf = bh_alloc(a, len + 1);
+
+    char* t = buf;
+    while ((*t++ = *str++));
+    return buf;
+}
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// FILE IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+#ifndef BH_NO_FILE
+
+static b32 bh__file_seek_wrapper(bh_file_descriptor fd, i64 offset, bh_file_whence whence, i64* new_offset);
+
+bh_file_error bh_file_get_standard(bh_file* file, bh_file_standard stand) {
+    const char* filename = NULL;
+
+#if defined(_BH_WINDOWS)
+    bh_file_descriptor sd_fd;
+
+    switch (stand) {
+    case BH_FILE_STANDARD_INPUT:
+        sd_fd = GetStdHandle(STD_INPUT_HANDLE);
+        filename = "stdin";
+        break;
+    case BH_FILE_STANDARD_OUTPUT:
+        sd_fd = GetStdHandle(STD_OUTPUT_HANDLE);
+        filename = "stdout";
+        break;
+    case BH_FILE_STANDARD_ERROR:
+        sd_fd = GetStdHandle(STD_ERROR_HANDLE);
+        filename = "stderr";
+        break;
+    default:
+        return BH_FILE_ERROR_BAD_FD;
+    }
+    file->fd = sd_fd;
+
+#elif defined(_BH_LINUX)
+    i32 sd_fd = -1;
+
+    switch (stand) {
+    case BH_FILE_STANDARD_INPUT:
+        sd_fd = STDIN_FILENO;
+        filename = "stdin"; // These are constants in the data section so everything should be okay
+        break;
+    case BH_FILE_STANDARD_OUTPUT:
+        sd_fd = STDOUT_FILENO;
+        filename = "stdout";
+        break;
+    case BH_FILE_STANDARD_ERROR:
+        sd_fd = STDERR_FILENO;
+        filename = "stderr";
+        break;
+    default:
+        return BH_FILE_ERROR_BAD_FD;
+    }
+
+    file->fd = sd_fd;
+#endif
+
+
+    file->filename = filename;
+    return BH_FILE_ERROR_NONE;
+}
+
+bh_file_error bh_file_create(bh_file* file, const char* filename) {
+    // Need to do this to avoid compiler complaining about types
+    bh_file_mode write_rw = (bh_file_mode) (BH_FILE_MODE_WRITE | BH_FILE_MODE_RW);
+    return bh_file_open_mode(file, write_rw, filename);
+}
+
+bh_file_error bh_file_open(bh_file* file, const char* filename) {
+    return bh_file_open_mode(file, BH_FILE_MODE_READ, filename);
+}
+
+bh_file_error bh_file_open_mode(bh_file* file, bh_file_mode mode, const char* filename) {
+#if defined(_BH_WINDOWS)
+    DWORD desired_access;
+    DWORD creation_disposition;
+
+    switch (mode & BH_FILE_MODE_MODES) {
+        case BH_FILE_MODE_READ:
+            desired_access = GENERIC_READ;
+            creation_disposition = OPEN_EXISTING;
+            break;
+        case BH_FILE_MODE_WRITE:
+            desired_access = GENERIC_WRITE;
+            creation_disposition = CREATE_ALWAYS;
+            break;
+        case BH_FILE_MODE_APPEND:
+            desired_access = GENERIC_WRITE;
+            creation_disposition = OPEN_ALWAYS;
+            break;
+        case BH_FILE_MODE_READ | BH_FILE_MODE_RW:
+            desired_access = GENERIC_READ | GENERIC_WRITE;
+            creation_disposition = OPEN_EXISTING;
+            break;
+        case BH_FILE_MODE_WRITE | BH_FILE_MODE_RW:
+            desired_access = GENERIC_READ | GENERIC_WRITE;
+            creation_disposition = CREATE_ALWAYS;
+            break;
+        case BH_FILE_MODE_APPEND | BH_FILE_MODE_RW:
+            desired_access = GENERIC_READ | GENERIC_WRITE;
+            creation_disposition = OPEN_ALWAYS;
+            break;
+        default:
+            return BH_FILE_ERROR_INVALID;
+    }
+
+
+    file->fd = CreateFileA(filename,
+                    desired_access,
+                    FILE_SHARE_READ,
+                    NULL,
+                    creation_disposition,
+                    FILE_ATTRIBUTE_NORMAL,
+                    NULL);
+
+    if (file->fd == INVALID_HANDLE_VALUE) {
+        return BH_FILE_ERROR_INVALID;
+    }
+
+    file->filename = filename;
+    return BH_FILE_ERROR_NONE;
+
+#elif defined(_BH_LINUX)
+    i32 os_mode = 0;
+
+    switch (mode & BH_FILE_MODE_MODES) {
+    case BH_FILE_MODE_READ:                       os_mode = O_RDONLY; break;
+    case BH_FILE_MODE_WRITE:                      os_mode = O_WRONLY | O_CREAT | O_TRUNC; break;
+    case BH_FILE_MODE_APPEND:                     os_mode = O_RDONLY | O_APPEND | O_CREAT; break;
+    case BH_FILE_MODE_READ   | BH_FILE_MODE_RW:   os_mode = O_RDWR; break;
+    case BH_FILE_MODE_WRITE  | BH_FILE_MODE_RW:   os_mode = O_RDWR | O_CREAT | O_TRUNC; break;
+    case BH_FILE_MODE_APPEND | BH_FILE_MODE_RW:   os_mode = O_RDWR | O_APPEND | O_CREAT; break;
+    //default: // TODO Handle errors
+    }
+
+    file->fd = open(filename, os_mode,
+        S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH | S_IRGRP | S_IWGRP //+rw-rw-rw-
+    );
+    if (file->fd < 0) {
+        return BH_FILE_ERROR_INVALID;
+    }
+
+    // TODO: Set this using some allocator
+    file->filename = filename;
+
+    return BH_FILE_ERROR_NONE;
+#endif
+}
+
+bh_file_error bh_file_new(bh_file* file, bh_file_descriptor fd, const char* filename) {
+    file->filename = filename; // This may be unsafe
+    file->fd = fd;
+    return BH_FILE_ERROR_NONE;
+}
+
+b32 bh_file_read_at(bh_file* file, i64 offset, void* buffer, isize buff_size, isize* bytes_read) {
+#if defined(_BH_WINDOWS)
+    bh_file_seek_to(file, offset);
+    BOOL res = ReadFile(file->fd, buffer, buff_size, (i32 *) bytes_read, NULL);
+    if (res) return 1;
+    else     return 0;
+
+#elif defined(_BH_LINUX)
+    isize res = pread(file->fd, buffer, buff_size, offset);
+    if (res < 0) return 0;
+    if (bytes_read) *bytes_read = res;
+    return 1;
+#endif
+}
+
+b32 bh_file_write_at(bh_file* file, i64 offset, void const* buffer, isize buff_size, isize* bytes_wrote) {
+    isize res;
+    i64 current_offset = 0;
+    bh__file_seek_wrapper(file->fd, 0, BH_FILE_WHENCE_CURRENT, &current_offset);
+
+#if defined(_BH_WINDOWS)
+    res = (isize) WriteFile(file->fd, buffer, buff_size, (i32 *) bytes_wrote, NULL);
+    return res;
+
+#elif defined(_BH_LINUX)
+    if (current_offset == offset || file->fd == 1 || file->fd == 2) {
+        // Standard in and out do like pwrite()
+        res = write(file->fd, buffer, buff_size);
+    } else {
+        res = pwrite(file->fd, buffer, buff_size, offset);
+    }
+    if (res < 0) return 0;
+    if (bytes_wrote) *bytes_wrote = res;
+
+    return 1;
+#endif
+}
+
+static b32 bh__file_seek_wrapper(bh_file_descriptor fd, i64 offset, bh_file_whence whence, i64* new_offset) {
+#if defined(_BH_WINDOWS)
+    LARGE_INTEGER new_file_pointer;
+    LARGE_INTEGER dest;
+    dest.QuadPart = offset;
+
+    BOOL res = SetFilePointerEx(fd, dest, &new_file_pointer, whence);
+    *new_offset = new_file_pointer.QuadPart;
+
+    return res;
+
+#elif defined(_BH_LINUX)
+    i64 res = lseek64(fd, offset, whence);
+    if (res < 0) return 0;
+    if (new_offset) *new_offset = res;
+    return 1;
+#endif
+}
+
+// Returns new offset
+i64 bh_file_seek_to(bh_file* file, i64 offset) {
+    i64 new_offset = -1;
+    bh__file_seek_wrapper(file->fd, offset, BH_FILE_WHENCE_BEGIN, &new_offset);
+    return new_offset;
+}
+
+i64 bh_file_seek_to_end(bh_file* file) {
+    i64 new_offset = -1;
+    bh__file_seek_wrapper(file->fd, 0, BH_FILE_WHENCE_END, &new_offset);
+    return new_offset;
+}
+
+i64 bh_file_skip(bh_file* file, i64 bytes) {
+    i64 new_offset = 0;
+    bh__file_seek_wrapper(file->fd, bytes, BH_FILE_WHENCE_CURRENT, &new_offset);
+    return new_offset;
+}
+
+i64 bh_file_tell(bh_file* file) {
+    i64 new_offset = 0;
+    bh__file_seek_wrapper(file->fd, 0, BH_FILE_WHENCE_CURRENT, &new_offset);
+    return new_offset;
+}
+
+bh_file_error bh_file_close(bh_file* file) {
+    bh_file_error err = BH_FILE_ERROR_NONE;
+
+#if defined(_BH_WINDOWS)
+    BOOL success = CloseHandle(file->fd);
+    if (!success) err = BH_FILE_ERROR_INVALID;
+
+    return err;
+
+#elif defined(_BH_LINUX)
+    i32 res = close(file->fd);
+    if (res < 0)
+        err = BH_FILE_ERROR_INVALID;
+
+    return err;
+#endif
+}
+
+b32 bh_file_read(bh_file* file, void* buffer, isize buff_size) {
+    return bh_file_read_at(file, bh_file_tell(file), buffer, buff_size, NULL);
+}
+
+b32 bh_file_write(bh_file* file, void* buffer, isize buff_size) {
+    return bh_file_write_at(file, bh_file_tell(file), buffer, buff_size, NULL);
+}
+
+i64 bh_file_size(bh_file* file) {
+    i64 size = 0;
+    i64 prev = bh_file_tell(file);
+    bh_file_seek_to_end(file);
+    size = bh_file_tell(file);
+    bh_file_seek_to(file, prev);
+    return size;
+}
+
+bh_file_contents bh_file_read_contents_bh_file(bh_allocator alloc, bh_file* file) {
+    bh_file_contents fc = {
+        .allocator = alloc,
+        .filename  = bh_strdup(alloc, (char *) file->filename),
+        .length = 0, .data = NULL
+    };
+
+    isize size = bh_file_size(file);
+    if (size <= 0) return fc;
+
+    fc.data = bh_alloc(alloc, size + 1);
+    fc.length = size;
+    bh_file_read_at(file, 0, fc.data, fc.length, NULL);
+    ((u8*) fc.data)[fc.length] = '\0';
+
+    return fc;
+}
+
+bh_file_contents bh_file_read_contents_direct(bh_allocator alloc, const char* filename) {
+    bh_file file;
+    bh_file_open(&file, filename);
+    bh_file_contents fc = bh_file_read_contents(alloc, &file);
+    bh_file_close(&file);
+    return fc;
+}
+
+b32 bh_file_contents_free(bh_file_contents* contents) {
+    bh_free(contents->allocator, contents->data);
+    contents->length = 0;
+    return 1;
+}
+
+b32 bh_file_exists(char const* filename) {
+    struct stat s;
+    return stat(filename, &s) != -1;
+}
+
+char* bh_path_get_full_name(char const* filename, bh_allocator a) {
+#if defined(_BH_WINDOWS)
+    char buffer[4096];
+    GetFullPathNameA(filename, 4096, buffer, NULL);
+
+    i32 len = strlen(buffer);
+    char* result = bh_alloc_array(a, char, len + 1);
+    memmove(result, buffer, len);
+    result[len] = 0;
+
+    return result;
+
+#elif defined(_BH_LINUX)
+    char* p = realpath(filename, NULL);    
+
+    // Check if the file did not exists.
+    // :Cleanup should this return NULL?
+    if (p == NULL) return (char *) filename;
+    
+    i32 len = strlen(p);
+    char* result = bh_alloc_array(a, char, len + 1);
+    memmove(result, p, len);
+    result[len] = 0;
+
+    free(p);
+
+    return result;
+#endif
+}
+
+// NOTE: This assumes the filename is the full path, not relative to anything else.
+char* bh_path_get_parent(char const* filename, bh_allocator a) {
+#if defined(_BH_LINUX)
+    #define DIR_SEPARATOR '/'
+#elif defined(_BH_WINDOWS)
+    #define DIR_SEPARATOR '\\'
+#endif
+
+    char* result = bh_strdup(a, (char *) filename);
+    char* end = result + strlen(result);
+    while (*end != DIR_SEPARATOR && end != result) *end-- = '\0';
+
+    return result;
+
+#undef DIR_SEPARATOR
+}
+
+#endif // ifndef BH_NO_FILE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// ALTERNATE PRINTF IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+isize bh_printf(char const *fmt, ...) {
+    isize res;
+    va_list va;
+    va_start(va, fmt);
+    res = bh_printf_va(fmt, va);
+    va_end(va);
+    return res;
+}
+
+isize bh_printf_va(char const *fmt, va_list va) {
+    bh_file file;
+    bh_file_get_standard(&file, BH_FILE_STANDARD_OUTPUT);
+    return bh_fprintf_va(&file, fmt, va);
+}
+
+isize bh_printf_err(char const *fmt, ...) {
+    isize res;
+    va_list va;
+    va_start(va, fmt);
+    res = bh_printf_err_va(fmt, va);
+    va_end(va);
+    return res;
+}
+
+isize bh_printf_err_va(char const *fmt, va_list va) {
+    bh_file file;
+    bh_file_get_standard(&file, BH_FILE_STANDARD_ERROR);
+    return bh_fprintf_va(&file, fmt, va);
+}
+
+isize bh_fprintf(bh_file* f, char const *fmt, ...) {
+    isize res;
+    va_list va;
+    va_start(va, fmt);
+    res = bh_fprintf_va(f, fmt, va);
+    va_end(va);
+    return res;
+}
+
+isize bh_fprintf_va(bh_file* f, char const *fmt, va_list va) {
+    static char buffer[4096];
+    isize len = bh_snprintf_va(buffer, sizeof(buffer), fmt, va);
+    bh_file_write(f, buffer, len - 1);
+    return len;
+}
+
+char* bh_bprintf(char const *fmt, ...) {
+    char* res;
+    va_list va;
+    va_start(va, fmt);
+    res = bh_bprintf_va(fmt, va);
+    va_end(va);
+    return res;
+}
+
+char* bh_bprintf_va(char const *fmt, va_list va) {
+    static char buffer[4096];
+    isize len = bh_snprintf_va(buffer, sizeof(buffer), fmt, va);
+    buffer[len - 1] = 0;
+    return buffer;
+}
+
+char* bh_aprintf(bh_allocator alloc, const char* fmt, ...) {
+    char* res;
+    va_list va;
+    va_start(va, fmt);
+    res = bh_aprintf_va(alloc, fmt, va);
+    va_end(va);
+    return res;
+}
+
+char* bh_aprintf_va(bh_allocator alloc, const char* fmt, va_list va) {
+    static char buffer[4096];
+    isize len = bh_snprintf_va(buffer, sizeof(buffer), fmt, va);
+    char* res = bh_alloc(alloc, len);
+    memcpy(res, buffer, len);
+    res[len - 1] = 0;
+    return res;
+}
+
+isize bh_snprintf(char *str, isize n, char const *fmt, ...) {
+    isize res;
+    va_list va;
+    va_start(va, fmt);
+    res = bh_snprintf_va(str, n, fmt, va);
+    va_end(va);
+    return res;
+}
+
+isize bh__print_string(char* dest, isize n, char* src) {
+    isize len = 0;
+    while (n-- && (*dest++ = *src++)) len++;
+    return len;
+}
+
+isize bh__printu64(char* str, isize n, bh__print_format format, u64 value) {
+    char buf[128];
+    buf[127] = 0;
+    char* walker = buf + 127;
+    u32 base = format.base ? format.base : 10, tmp;
+
+    while (value > 0) {
+        tmp = value % base;
+        if (tmp > 9) {
+            switch (tmp) {
+            case 10: tmp = 'a'; break;
+            case 11: tmp = 'b'; break;
+            case 12: tmp = 'c'; break;
+            case 13: tmp = 'd'; break;
+            case 14: tmp = 'e'; break;
+            case 15: tmp = 'f'; break;
+            }
+        } else {
+            tmp += '0';
+        }
+
+        *--walker = tmp;
+        value /= base;
+    }
+
+    if (format.base == 16) {
+        *--walker = 'x';
+        *--walker = '0';
+    }
+
+    return bh__print_string(str, n, walker);
+}
+
+isize bh__printi64(char* str, isize n, bh__print_format format, i64 value) {
+    char buf[128];
+    buf[127] = 0;
+    char* walker = buf + 127;
+    u32 base = format.base ? format.base : 10, tmp;
+
+    b32 negative = value < 0 ? 1 : 0;
+    if (negative) value = -value;
+
+    if (value == 0) {
+        *--walker = '0';
+    } else {
+        while (value > 0) {
+            tmp = value % base;
+            if (tmp > 9) {
+                switch (tmp) {
+                case 10: tmp = 'a'; break;
+                case 11: tmp = 'b'; break;
+                case 12: tmp = 'c'; break;
+                case 13: tmp = 'd'; break;
+                case 14: tmp = 'e'; break;
+                case 15: tmp = 'f'; break;
+                }
+            } else {
+                tmp += '0';
+            }
+
+            *--walker = tmp;
+            value /= base;
+        }
+    }
+
+    if (negative) {
+        *--walker = '-';
+    }
+
+    if (format.base == 16) {
+        *--walker = 'x';
+        *--walker = '0';
+    }
+
+    return bh__print_string(str, n, walker);
+}
+
+// TODO: This implementation is VERY VERY BAD AND WRONG. Fix it.
+isize bh__printf64(char* str, isize n, f64 value) {
+    fori (i, 0, 6) value *= 10.0;
+    i64 v = (i64) value;
+
+    isize l1 = bh__printi64(str, n, ((bh__print_format) { .base = 10 }), v / 1000000);
+    str += l1;
+    n -= l1;
+
+    *str = '.';
+    str += 1;
+    n -= 1;
+
+    isize l2 = bh__printi64(str, n, ((bh__print_format) { .base = 10 }), bh_abs(v) % 1000000);
+
+    return l1 + l2 + 1;
+}
+
+// TODO: This is very hacked together but for now it will work.
+isize bh_snprintf_va(char *str, isize n, char const *fmt, va_list va) {
+    char const *text_start = str;
+    isize res;
+
+    while (*fmt) {
+        bh__print_format format = { 0 };
+        isize len = 0;
+
+        while (*fmt && *fmt != '%') {
+            *(str++) = *(fmt++);
+        }
+
+        if (!*fmt) goto end_of_format;
+
+        fmt++;
+
+        switch (*fmt++) {
+        case 'o': format.base = 8; break;
+        case 'x': format.base = 16; break;
+        default: fmt--;
+        }
+
+        switch (*fmt) {
+        case 'c': {
+            char c = (char) va_arg(va, int);
+            *(str++) = c;
+        } break;
+
+        case 'd': {
+            i64 value = (i64) va_arg(va, int);
+            len = bh__printi64(str, n, format, value);
+        } break;
+
+        case 'l': {
+            i64 value = (i64) va_arg(va, long);
+            len = bh__printi64(str, n, format, value);
+        } break;
+
+        case 'p': {
+            u64 value = (u64) va_arg(va, ptr);
+            format.base = 16;
+            len = bh__printu64(str, n, format, value);
+        } break;
+
+        case 's': {
+            char* s = va_arg(va, char *);
+            len = bh__print_string(str, n, s);
+        } break;
+
+        case 'b': { // String with a length (not null terminated)
+            char* s = va_arg(va, char *);
+            i32 l = va_arg(va, int);
+            len = bh__print_string(str, bh_min(l, n), s);
+        } break;
+
+        case 'f': {
+            f64 f = va_arg(va, f64);
+            len = bh__printf64(str, n, f);
+        } break;
+
+        default: fmt--;
+        }
+
+        fmt++;
+
+end_of_format:
+        str += len;
+        n -= len;
+    }
+
+    return str - text_start + 1;
+}
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// FLEXIBLE BUFFER IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+#ifndef BH_NO_BUFFER
+
+void bh_buffer_init(bh_buffer* buffer, bh_allocator alloc, i32 init_size) {
+    buffer->allocator = alloc;
+    buffer->length = 0;
+    buffer->capacity = init_size;
+    buffer->data = bh_alloc(alloc, init_size);
+}
+
+void bh_buffer_free(bh_buffer* buffer) {
+    bh_free(buffer->allocator, buffer->data);
+    buffer->length = 0;
+    buffer->capacity = 0;
+}
+
+void bh_buffer_grow(bh_buffer* buffer, i32 length) {
+    if (buffer == NULL) return;
+
+    if (buffer->capacity >= length) {
+        // NOTE: Already have enough room
+        return;
+    }
+
+    i32 newcap = buffer->capacity;
+    while (newcap < length) newcap = BH_BUFFER_GROW_FORMULA(newcap);
+
+    ptr new_data = bh_resize(buffer->allocator, buffer->data, newcap);
+    if (new_data == NULL) return;
+
+    buffer->capacity = newcap;
+    buffer->data = new_data;
+}
+
+void bh_buffer_append(bh_buffer* buffer, const void * data, i32 length) {
+    if (buffer == NULL) return;
+
+    if (buffer->length + length > buffer->capacity) {
+        bh_buffer_grow(buffer, buffer->length + length);
+    }
+
+    memcpy(buffer->data + buffer->length, data, length);
+    buffer->length += length;
+}
+
+void bh_buffer_concat(bh_buffer* buffer, bh_buffer other) {
+    bh_buffer_append(buffer, other.data, other.length);
+}
+
+void bh_buffer_write_byte(bh_buffer* buffer, u8 byte) {
+    bh_buffer_grow(buffer, buffer->length + 1);
+    buffer->data[buffer->length++] = byte;
+}
+
+void bh_buffer_write_u32(bh_buffer* buffer, u32 i) {
+    bh_buffer_grow(buffer, buffer->length + 4);
+    *((u32 *) bh_pointer_add(buffer->data, buffer->length)) = i;
+    buffer->length += 4;
+}
+
+void bh_buffer_write_u64(bh_buffer* buffer, u64 i) {
+    bh_buffer_grow(buffer, buffer->length + 8);
+    *((u64 *) bh_pointer_add(buffer->data, buffer->length)) = i;
+    buffer->length += 8;
+}
+
+void bh_buffer_align(bh_buffer* buffer, u32 alignment) {
+    if (buffer->length % alignment != 0) {
+        u32 difference = alignment - (buffer->length % alignment);
+        buffer->length += difference;
+
+        bh_buffer_grow(buffer, buffer->length);
+    }
+}
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// ARRAY IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+#ifndef BH_NO_ARRAY
+
+b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap) {
+    bh__arr* arrptr;
+
+    if (*arr == NULL) {
+        if (cap == 0 && elemsize == 0) return 1;
+
+        arrptr = (bh__arr *) bh_alloc(alloc, sizeof(*arrptr) + elemsize * cap);
+        if (arrptr == NULL) return 0;
+
+        arrptr->allocator = alloc;
+        arrptr->capacity = cap;
+        arrptr->length = 0;
+
+    } else {
+        arrptr = bh__arrhead(*arr);
+
+        if (arrptr->capacity < cap) {
+            void* p;
+            i32 newcap = arrptr->capacity;
+            while (newcap < cap) newcap = BH_ARR_GROW_FORMULA(newcap);
+
+            p = bh_resize(arrptr->allocator, arrptr, sizeof(*arrptr) + elemsize * newcap);
+
+            if (p) {
+                arrptr = (bh__arr *) p;
+                arrptr->capacity = newcap;
+            } else {
+                return 0;
+            }
+        }
+    }
+
+    *arr = arrptr + 1;
+    return 1;
+}
+
+b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap) {
+    if (*arr == NULL) return 0;
+
+    bh__arr* arrptr = bh__arrhead(*arr);
+    cap = bh_max(cap, arrptr->length);
+
+    if (arrptr->capacity > cap) {
+        void* p = bh_resize(arrptr->allocator, arrptr, sizeof(*arrptr) + elemsize * cap);
+
+        if (p) {
+            arrptr = (bh__arr *) p;
+            arrptr->capacity = cap;
+        } else {
+            return 0;
+        }
+    }
+
+    *arr = arrptr + 1;
+    return 1;
+}
+
+b32 bh__arr_free(void **arr) {
+    if (*arr == NULL) return 0;
+
+    bh__arr* arrptr = bh__arrhead(*arr);
+    bh_free(arrptr->allocator, arrptr);
+    *arr = NULL;
+    return 1;
+}
+
+void* bh__arr_copy(bh_allocator alloc, void *arr, i32 elemsize) {
+    bh__arr* arrptr = bh__arrhead(arr);
+
+    const i32 cap = arrptr->length;
+
+    void* newarr = NULL;
+    bh__arr_grow(alloc, &newarr, elemsize, cap);
+    bh__arrhead(newarr)->length = cap;
+    bh__arrhead(newarr)->capacity = cap;
+    memcpy(newarr, arr, elemsize * arrptr->length);
+
+    return newarr;
+}
+
+void bh__arr_deleten(void **arr, i32 elemsize, i32 index, i32 numelems) {
+    bh__arr* arrptr = bh__arrhead(*arr);
+
+    if (index >= arrptr->length) return; // Can't delete past the end of the array
+    if (numelems <= 0) return; // Can't delete nothing
+
+    memmove(
+        (char *)(*arr) + elemsize * index,                    // Target
+        (char *)(*arr) + elemsize * (index + numelems),        // Source
+        elemsize * (arrptr->length - (index + numelems)));    // Length
+    arrptr->length -= numelems;
+}
+
+void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems) {
+    if (numelems) {
+        if (*arr == NULL) {
+            bh__arr_grow(bh_arr_allocator(arr), arr, elemsize, numelems); // Making a new array
+            return;
+        }
+
+        bh__arr* arrptr = bh__arrhead(*arr);
+        if (!bh__arr_grow(bh_arr_allocator(arr), arr, elemsize, arrptr->length + numelems)) return; // Fail case
+        arrptr = bh__arrhead(*arr);
+        memmove(
+            (char *)(*arr) + elemsize * (index + numelems),
+            (char *)(*arr) + elemsize * index,
+            elemsize * (arrptr->length - index));
+        arrptr->length += numelems;
+    }
+}
+
+#endif // ifndef BH_NO_ARRAY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+// TABLE IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+#ifndef BH_NO_TABLE
+
+b32 bh__table_init(bh_allocator allocator, bh__table **table, i32 table_size) {
+    *table = bh_alloc(allocator, sizeof(bh__table) + sizeof(ptr) * table_size);
+    if (*table == NULL) return 0;
+
+    (*table)->allocator = allocator;
+    (*table)->table_size = table_size;
+
+    for (i32 i = 0; i < table_size; i++) {
+        (*table)->arrs[i] = NULL;
+    }
+
+    return 1;
+}
+
+b32 bh__table_free(bh__table **table) {
+    if (*table == NULL) return 0;
+
+    for (u64 i = 0; i < (*table)->table_size; i++) {
+        if ((*table)->arrs[i] != NULL) {
+            bh_arr_free((*table)->arrs[i]);
+        }
+    }
+
+    bh_free((*table)->allocator, *table);
+    *table = NULL;
+    return 1;
+}
+
+// Assumes NULL terminated string for key
+ptr bh__table_put(bh__table *table, i32 elemsize, char *key) {
+    elemsize += (elemsize & 1);
+
+    u64 index = bh__table_hash_function(key, 0, table->table_size);
+    u8 arr_was_new = 0;
+
+    ptr arrptr = table->arrs[index];
+    if (arrptr == NULL) {
+        arr_was_new = 1;
+        goto add_new_element;
+    }
+    u64 len = *(u64 *) arrptr;
+    arrptr = bh_pointer_add(arrptr, sizeof(u64));
+
+    u16 key_length = 0;
+    while (len--) {
+        arrptr = bh_pointer_add(arrptr, elemsize);
+        key_length = *(u16 *) arrptr;
+        arrptr = bh_pointer_add(arrptr, sizeof(u16));
+        if (strncmp(key, (char *) arrptr, key_length) == 0) goto found_matching;
+        arrptr = bh_pointer_add(arrptr, key_length);
+    }
+
+add_new_element:
+    arrptr = table->arrs[index];
+    i32 byte_len = bh_arr_length(arrptr);
+    if (byte_len == 0) byte_len = sizeof(u64);
+    key_length = strlen(key) + 1;
+
+    // NOTE: Align to 16 bytes
+    if ((key_length + 2) % 16 != 0) {
+        key_length = ((((key_length + 2) >> 4) + 1) << 4) - 2;
+    }
+
+    bh__arr_grow(table->allocator, &arrptr, 1, byte_len + elemsize + sizeof(u16) + key_length);
+    bh__arrhead(arrptr)->length = byte_len + elemsize + sizeof(u16) + key_length;
+    table->arrs[index] = arrptr;
+
+    if (arr_was_new) {
+        *(u64 *) arrptr = 1;
+    } else {
+        (*(u64 *) arrptr)++;
+    }
+
+    arrptr = bh_pointer_add(arrptr, byte_len + elemsize);
+    *(u16 *) arrptr = key_length;
+    arrptr = bh_pointer_add(arrptr, sizeof(u16));
+    strncpy(arrptr, key, key_length);
+
+found_matching:
+    return bh_pointer_add(arrptr, -(sizeof(u16) + elemsize));
+}
+
+b32 bh__table_has(bh__table *table, i32 elemsize, char *key) {
+    elemsize += (elemsize & 1);
+
+    u64 index = bh__table_hash_function(key, 0, table->table_size);
+
+    ptr arrptr = table->arrs[index];
+    if (arrptr == NULL) return 0;
+
+    u64 len = *(u64 *) arrptr;
+    arrptr = bh_pointer_add(arrptr, sizeof(u64));
+
+    u16 key_length = 0;
+    while (len--) {
+        arrptr = bh_pointer_add(arrptr, elemsize);
+        key_length = *(u16 *) arrptr;
+        arrptr = bh_pointer_add(arrptr, sizeof(u16));
+        if (strncmp(key, (char *) arrptr, key_length) == 0) return 1;
+        arrptr = bh_pointer_add(arrptr, key_length);
+    }
+
+    return 0;
+}
+
+ptr bh__table_get(bh__table *table, i32 elemsize, char *key) {
+    elemsize += (elemsize & 1);
+
+    u64 index = bh__table_hash_function(key, 0, table->table_size);
+
+    ptr arrptr = table->arrs[index];
+    if (arrptr == NULL) return 0;
+
+    u64 len = *(u64 *) arrptr;
+    arrptr = bh_pointer_add(arrptr, sizeof(u64));
+
+    u16 key_length = 0;
+    while (len--) {
+        arrptr = bh_pointer_add(arrptr, elemsize);
+        key_length = *(u16 *) arrptr;
+        arrptr = bh_pointer_add(arrptr, sizeof(u16));
+        if (strncmp(key, (char *) arrptr, key_length) == 0) {
+            return bh_pointer_add(arrptr, -(sizeof(u16) + elemsize));
+        }
+        arrptr = bh_pointer_add(arrptr, key_length);
+    }
+
+    return NULL;
+}
+
+void bh__table_delete(bh__table *table, i32 elemsize, char *key) {
+    elemsize += (elemsize & 1);
+
+    u64 index = bh__table_hash_function(key, 0, table->table_size);
+
+    ptr arrptr = table->arrs[index], walker;
+    if (arrptr == NULL) return; // Didn't exist
+    walker = arrptr;
+
+    i32 byte_offset = 8;
+    i32 delete_len = 0;
+
+    u64 len = *(u64 *) walker;
+    walker = bh_pointer_add(walker, sizeof(u64));
+
+    u16 key_length = 0;
+    while (len--) {
+        walker = bh_pointer_add(walker, elemsize);
+        key_length = *(u16 *) walker;
+        walker = bh_pointer_add(walker, sizeof(u16));
+        if (strncmp(key, (char *) walker, key_length) == 0) {
+            delete_len = elemsize + sizeof(u16) + key_length;
+            goto found_matching;
+        }
+        walker = bh_pointer_add(walker, key_length);
+        byte_offset += elemsize + sizeof(u16) + key_length;
+    }
+
+    // NOTE: Already didn't exist
+    return;
+
+found_matching:
+    bh__arr_deleten((void **) &arrptr, 1, byte_offset, delete_len);
+    table->arrs[index] = arrptr;
+    (*(u64 *) arrptr)--;
+}
+
+void bh__table_clear(bh__table *table) {
+    for (u64 i = 0; i < table->table_size; i++) {
+        if (table->arrs[i] != NULL) {
+            // NOTE: Set length property to 0
+            *((u64 *) table->arrs[i]) = 0;
+            bh_arr_set_length(table->arrs[i], 0);
+        }
+    }
+}
+
+bh_table_iterator bh__table_iter_setup(bh__table *table, i32 elemsize) {
+    elemsize += (elemsize & 1);
+
+    bh_table_iterator it = {
+        .tab = table->arrs,
+        .endtab = table->arrs + table->table_size,
+        .elemsize = elemsize,
+        .entry = NULL
+    };
+    return it;
+}
+
+b32 bh_table_iter_next(bh_table_iterator* it) {
+    if (it->tab == NULL) return 0;
+
+    if (it->entry != NULL) {
+        it->arrlen--;
+        if (it->arrlen <= 0) {
+            it->tab++;
+            goto step_to_next;
+        }
+
+        it->entry = bh_pointer_add(it->entry, it->elemsize);
+        it->entry = bh_pointer_add(it->entry, sizeof(u16) + (*(u16 *) it->entry));
+        return 1;
+    }
+
+step_to_next:
+    // Step forward to find next valid
+    while (it->tab != it->endtab && *it->tab == NULL) {
+        it->tab++;
+    }
+
+    if (it->tab == it->endtab) return 0;
+
+    it->entry = *it->tab;
+    it->arrlen = *(u64 *) it->entry;
+    it->entry = bh_pointer_add(it->entry, sizeof(u64));
+    if (it->arrlen <= 0) {
+        it->tab++;
+        goto step_to_next;
+    }
+    return 1;
+}
+
+#endif // ifndef BH_NO_HASHTABLE
+
+
+
+//-------------------------------------------------------------------------------------
+// IMAP IMPLEMENTATION
+//-------------------------------------------------------------------------------------
+#ifndef BH_NO_IMAP
+void bh_imap_init(bh_imap* imap, bh_allocator alloc, i32 hash_count) {
+    imap->allocator = alloc;
+
+    imap->hashes  = NULL;
+    imap->entries = NULL;
+
+    bh_arr_new(alloc, imap->hashes, hash_count);
+    bh_arr_new(alloc, imap->entries, 4);
+
+    fori(count, 0, hash_count) bh_arr_push(imap->hashes, -1);
+}
+
+void bh_imap_free(bh_imap* imap) {
+    bh_arr_free(imap->hashes);
+    bh_arr_free(imap->entries);
+
+    imap->hashes = NULL;
+    imap->entries = NULL;
+}
+
+bh__imap_lookup_result bh__imap_lookup(bh_imap* imap, bh_imap_entry_t key) {
+    bh__imap_lookup_result lr = { -1, -1, -1 };
+
+    u64 hash = 0xcbf29ce484222325ull ^ key;
+    u64 n = bh_arr_capacity(imap->hashes);
+
+    lr.hash_index  = hash % n;
+    lr.entry_index = imap->hashes[lr.hash_index];
+    while (lr.entry_index >= 0) {
+        if (imap->entries[lr.entry_index].key == key) {
+            return lr;
+        }
+
+        lr.entry_prev  = lr.entry_index;
+        lr.entry_index = imap->entries[lr.entry_index].next;
+    }
+
+    return lr;
+}
+
+void bh_imap_put(bh_imap* imap, bh_imap_entry_t key, bh_imap_entry_t value) {
+    bh__imap_lookup_result lr = bh__imap_lookup(imap, key);
+
+    if (lr.entry_index >= 0) {
+        imap->entries[lr.entry_index].value = value;
+        return;
+    }
+
+    bh__imap_entry entry;
+    entry.key = key;
+    entry.value = value;
+    entry.next = imap->hashes[lr.hash_index];
+    bh_arr_push(imap->entries, entry);
+
+    imap->hashes[lr.hash_index] = bh_arr_length(imap->entries) - 1;
+}
+
+b32 bh_imap_has(bh_imap* imap, bh_imap_entry_t key) {
+    bh__imap_lookup_result lr = bh__imap_lookup(imap, key);
+    return lr.entry_index >= 0;
+}
+
+bh_imap_entry_t bh_imap_get(bh_imap* imap, bh_imap_entry_t key) {
+    bh__imap_lookup_result lr = bh__imap_lookup(imap, key);
+    if (lr.entry_index >= 0) {
+        return imap->entries[lr.entry_index].value;
+    } else {
+        return 0;
+    }
+}
+
+void bh_imap_delete(bh_imap* imap, bh_imap_entry_t key) {
+    bh__imap_lookup_result lr = bh__imap_lookup(imap, key);
+    if (lr.entry_index < 0) return;
+
+    if (lr.entry_prev < 0) {
+        imap->hashes[lr.hash_index] = imap->entries[lr.entry_index].next;
+    } else {
+        imap->entries[lr.entry_prev].next = imap->entries[lr.entry_index].next;
+    }
+
+    // If it's that last thing in the array, just pop off the end
+    if (lr.entry_index == bh_arr_length(imap->entries) - 1) {
+        bh_arr_pop(imap->entries);
+        return;
+    }
+
+    bh_arr_fastdelete(imap->entries, lr.entry_index);
+    bh__imap_lookup_result last = bh__imap_lookup(imap, imap->entries[lr.entry_index].key);
+    if (last.entry_prev >= 0) {
+        imap->entries[last.entry_prev].next = lr.entry_index;
+    } else {
+        imap->hashes[last.hash_index] = lr.entry_index;
+    }
+}
+
+void bh_imap_clear(bh_imap* imap) {
+    // NOTE: Does not clear out an of the data that was in the map
+    bh_arr_each(i64, hash, imap->hashes) *hash = -1;
+    bh_arr_set_length(imap->entries, 0);
+}
+
+#endif // ifndef BH_NO_IMAP
+
+
+
+
+
+u64 bh_time_curr() {
+#if defined(_BH_WINDOWS)
+    LARGE_INTEGER result;
+    QueryPerformanceCounter(&result);
+    return (u64) result.QuadPart;
+
+#elif defined(_BH_LINUX)
+    struct timespec spec;
+    clock_gettime(CLOCK_REALTIME, &spec);
+
+    time_t sec = spec.tv_sec;
+    u64 ms  = spec.tv_nsec / 1000000;
+    if (ms > 999) {
+        sec++;
+        ms = 0;
+    }
+
+    return sec * 1000 + ms;
+#endif
+}
+
+u64 bh_time_duration(u64 old) {
+#if defined(_BH_WINDOWS)
+    u64 curr = bh_time_curr();
+    u64 duration = curr - old;
+    
+    LARGE_INTEGER freq;
+    QueryPerformanceFrequency(&freq);
+    duration *= 1000;
+    duration /= freq.QuadPart;
+    return duration;
+
+#elif defined(_BH_LINUX)
+    u64 curr = bh_time_curr();
+    return curr - old;
+#endif
+}
+
+#endif // ifdef BH_DEFINE
+
+#endif // ifndef BH_H
diff --git a/lib/linux_x86_64/include/wasm.h b/lib/linux_x86_64/include/wasm.h
new file mode 100644 (file)
index 0000000..ac090e6
--- /dev/null
@@ -0,0 +1,723 @@
+// WebAssembly C API
+
+#ifndef WASM_H
+#define WASM_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+
+#ifndef WASM_API_EXTERN
+#ifdef _WIN32
+#define WASM_API_EXTERN __declspec(dllimport)
+#else
+#define WASM_API_EXTERN
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Auxiliaries
+
+// Machine types
+
+inline void assertions() {
+  static_assert(sizeof(float) == sizeof(uint32_t), "incompatible float type");
+  static_assert(sizeof(double) == sizeof(uint64_t), "incompatible double type");
+  static_assert(sizeof(intptr_t) == sizeof(uint32_t) ||
+                sizeof(intptr_t) == sizeof(uint64_t),
+                "incompatible pointer type");
+}
+
+typedef char byte_t;
+typedef float float32_t;
+typedef double float64_t;
+
+
+// Ownership
+
+#define own
+
+// The qualifier `own` is used to indicate ownership of data in this API.
+// It is intended to be interpreted similar to a `const` qualifier:
+//
+// - `own wasm_xxx_t*` owns the pointed-to data
+// - `own wasm_xxx_t` distributes to all fields of a struct or union `xxx`
+// - `own wasm_xxx_vec_t` owns the vector as well as its elements(!)
+// - an `own` function parameter passes ownership from caller to callee
+// - an `own` function result passes ownership from callee to caller
+// - an exception are `own` pointer parameters named `out`, which are copy-back
+//   output parameters passing back ownership from callee to caller
+//
+// Own data is created by `wasm_xxx_new` functions and some others.
+// It must be released with the corresponding `wasm_xxx_delete` function.
+//
+// Deleting a reference does not necessarily delete the underlying object,
+// it merely indicates that this owner no longer uses it.
+//
+// For vectors, `const wasm_xxx_vec_t` is used informally to indicate that
+// neither the vector nor its elements should be modified.
+// TODO: introduce proper `wasm_xxx_const_vec_t`?
+
+
+#define WASM_DECLARE_OWN(name) \
+  typedef struct wasm_##name##_t wasm_##name##_t; \
+  \
+  WASM_API_EXTERN void wasm_##name##_delete(own wasm_##name##_t*);
+
+
+// Vectors
+
+#define WASM_DECLARE_VEC(name, ptr_or_none) \
+  typedef struct wasm_##name##_vec_t { \
+    size_t size; \
+    wasm_##name##_t ptr_or_none* data; \
+  } wasm_##name##_vec_t; \
+  \
+  WASM_API_EXTERN void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out); \
+  WASM_API_EXTERN void wasm_##name##_vec_new_uninitialized( \
+    own wasm_##name##_vec_t* out, size_t); \
+  WASM_API_EXTERN void wasm_##name##_vec_new( \
+    own wasm_##name##_vec_t* out, \
+    size_t, own wasm_##name##_t ptr_or_none const[]); \
+  WASM_API_EXTERN void wasm_##name##_vec_copy( \
+    own wasm_##name##_vec_t* out, const wasm_##name##_vec_t*); \
+  WASM_API_EXTERN void wasm_##name##_vec_delete(own wasm_##name##_vec_t*);
+
+
+// Byte vectors
+
+typedef byte_t wasm_byte_t;
+WASM_DECLARE_VEC(byte, )
+
+typedef wasm_byte_vec_t wasm_name_t;
+
+#define wasm_name wasm_byte_vec
+#define wasm_name_new wasm_byte_vec_new
+#define wasm_name_new_empty wasm_byte_vec_new_empty
+#define wasm_name_new_new_uninitialized wasm_byte_vec_new_uninitialized
+#define wasm_name_copy wasm_byte_vec_copy
+#define wasm_name_delete wasm_byte_vec_delete
+
+static inline void wasm_name_new_from_string(
+  own wasm_name_t* out, own const char* s
+) {
+  wasm_name_new(out, strlen(s), s);
+}
+
+static inline void wasm_name_new_from_string_nt(
+  own wasm_name_t* out, own const char* s
+) {
+  wasm_name_new(out, strlen(s) + 1, s);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Runtime Environment
+
+// Configuration
+
+WASM_DECLARE_OWN(config)
+
+WASM_API_EXTERN own wasm_config_t* wasm_config_new();
+
+// Embedders may provide custom functions for manipulating configs.
+
+
+// Engine
+
+WASM_DECLARE_OWN(engine)
+
+WASM_API_EXTERN own wasm_engine_t* wasm_engine_new();
+WASM_API_EXTERN own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t*);
+
+
+// Store
+
+WASM_DECLARE_OWN(store)
+
+WASM_API_EXTERN own wasm_store_t* wasm_store_new(wasm_engine_t*);
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Type Representations
+
+// Type attributes
+
+typedef uint8_t wasm_mutability_t;
+enum wasm_mutability_enum {
+  WASM_CONST,
+  WASM_VAR,
+};
+
+typedef struct wasm_limits_t {
+  uint32_t min;
+  uint32_t max;
+} wasm_limits_t;
+
+static const uint32_t wasm_limits_max_default = 0xffffffff;
+
+
+// Generic
+
+#define WASM_DECLARE_TYPE(name) \
+  WASM_DECLARE_OWN(name) \
+  WASM_DECLARE_VEC(name, *) \
+  \
+  WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t*);
+
+
+// Value Types
+
+WASM_DECLARE_TYPE(valtype)
+
+typedef uint8_t wasm_valkind_t;
+enum wasm_valkind_enum {
+  WASM_I32,
+  WASM_I64,
+  WASM_F32,
+  WASM_F64,
+  WASM_ANYREF = 128,
+  WASM_FUNCREF,
+};
+
+WASM_API_EXTERN own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t);
+
+WASM_API_EXTERN wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t*);
+
+static inline bool wasm_valkind_is_num(wasm_valkind_t k) {
+  return k < WASM_ANYREF;
+}
+static inline bool wasm_valkind_is_ref(wasm_valkind_t k) {
+  return k >= WASM_ANYREF;
+}
+
+static inline bool wasm_valtype_is_num(const wasm_valtype_t* t) {
+  return wasm_valkind_is_num(wasm_valtype_kind(t));
+}
+static inline bool wasm_valtype_is_ref(const wasm_valtype_t* t) {
+  return wasm_valkind_is_ref(wasm_valtype_kind(t));
+}
+
+
+// Function Types
+
+WASM_DECLARE_TYPE(functype)
+
+WASM_API_EXTERN own wasm_functype_t* wasm_functype_new(
+  own wasm_valtype_vec_t* params, own wasm_valtype_vec_t* results);
+
+WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t*);
+WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t*);
+
+
+// Global Types
+
+WASM_DECLARE_TYPE(globaltype)
+
+WASM_API_EXTERN own wasm_globaltype_t* wasm_globaltype_new(
+  own wasm_valtype_t*, wasm_mutability_t);
+
+WASM_API_EXTERN const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t*);
+WASM_API_EXTERN wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t*);
+
+
+// Table Types
+
+WASM_DECLARE_TYPE(tabletype)
+
+WASM_API_EXTERN own wasm_tabletype_t* wasm_tabletype_new(
+  own wasm_valtype_t*, const wasm_limits_t*);
+
+WASM_API_EXTERN const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t*);
+WASM_API_EXTERN const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t*);
+
+
+// Memory Types
+
+WASM_DECLARE_TYPE(memorytype)
+
+WASM_API_EXTERN own wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t*);
+
+WASM_API_EXTERN const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t*);
+
+
+// Extern Types
+
+WASM_DECLARE_TYPE(externtype)
+
+typedef uint8_t wasm_externkind_t;
+enum wasm_externkind_enum {
+  WASM_EXTERN_FUNC,
+  WASM_EXTERN_GLOBAL,
+  WASM_EXTERN_TABLE,
+  WASM_EXTERN_MEMORY,
+};
+
+WASM_API_EXTERN wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t*);
+
+WASM_API_EXTERN wasm_externtype_t* wasm_functype_as_externtype(wasm_functype_t*);
+WASM_API_EXTERN wasm_externtype_t* wasm_globaltype_as_externtype(wasm_globaltype_t*);
+WASM_API_EXTERN wasm_externtype_t* wasm_tabletype_as_externtype(wasm_tabletype_t*);
+WASM_API_EXTERN wasm_externtype_t* wasm_memorytype_as_externtype(wasm_memorytype_t*);
+
+WASM_API_EXTERN wasm_functype_t* wasm_externtype_as_functype(wasm_externtype_t*);
+WASM_API_EXTERN wasm_globaltype_t* wasm_externtype_as_globaltype(wasm_externtype_t*);
+WASM_API_EXTERN wasm_tabletype_t* wasm_externtype_as_tabletype(wasm_externtype_t*);
+WASM_API_EXTERN wasm_memorytype_t* wasm_externtype_as_memorytype(wasm_externtype_t*);
+
+WASM_API_EXTERN const wasm_externtype_t* wasm_functype_as_externtype_const(const wasm_functype_t*);
+WASM_API_EXTERN const wasm_externtype_t* wasm_globaltype_as_externtype_const(const wasm_globaltype_t*);
+WASM_API_EXTERN const wasm_externtype_t* wasm_tabletype_as_externtype_const(const wasm_tabletype_t*);
+WASM_API_EXTERN const wasm_externtype_t* wasm_memorytype_as_externtype_const(const wasm_memorytype_t*);
+
+WASM_API_EXTERN const wasm_functype_t* wasm_externtype_as_functype_const(const wasm_externtype_t*);
+WASM_API_EXTERN const wasm_globaltype_t* wasm_externtype_as_globaltype_const(const wasm_externtype_t*);
+WASM_API_EXTERN const wasm_tabletype_t* wasm_externtype_as_tabletype_const(const wasm_externtype_t*);
+WASM_API_EXTERN const wasm_memorytype_t* wasm_externtype_as_memorytype_const(const wasm_externtype_t*);
+
+
+// Import Types
+
+WASM_DECLARE_TYPE(importtype)
+
+WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new(
+  own wasm_name_t* module, own wasm_name_t* name, own wasm_externtype_t*);
+
+WASM_API_EXTERN const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*);
+WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*);
+WASM_API_EXTERN const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*);
+
+
+// Export Types
+
+WASM_DECLARE_TYPE(exporttype)
+
+WASM_API_EXTERN own wasm_exporttype_t* wasm_exporttype_new(
+  own wasm_name_t*, own wasm_externtype_t*);
+
+WASM_API_EXTERN const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t*);
+WASM_API_EXTERN const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t*);
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Runtime Objects
+
+// Values
+
+struct wasm_ref_t;
+
+typedef struct wasm_val_t {
+  wasm_valkind_t kind;
+  union {
+    int32_t i32;
+    int64_t i64;
+    float32_t f32;
+    float64_t f64;
+    struct wasm_ref_t* ref;
+  } of;
+} wasm_val_t;
+
+WASM_API_EXTERN void wasm_val_delete(own wasm_val_t* v);
+WASM_API_EXTERN void wasm_val_copy(own wasm_val_t* out, const wasm_val_t*);
+
+WASM_DECLARE_VEC(val, )
+
+
+// References
+
+#define WASM_DECLARE_REF_BASE(name) \
+  WASM_DECLARE_OWN(name) \
+  \
+  WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); \
+  WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); \
+  \
+  WASM_API_EXTERN void* wasm_##name##_get_host_info(const wasm_##name##_t*); \
+  WASM_API_EXTERN void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \
+  WASM_API_EXTERN void wasm_##name##_set_host_info_with_finalizer( \
+    wasm_##name##_t*, void*, void (*)(void*));
+
+#define WASM_DECLARE_REF(name) \
+  WASM_DECLARE_REF_BASE(name) \
+  \
+  WASM_API_EXTERN wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t*); \
+  WASM_API_EXTERN wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t*); \
+  WASM_API_EXTERN const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t*); \
+  WASM_API_EXTERN const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t*);
+
+#define WASM_DECLARE_SHARABLE_REF(name) \
+  WASM_DECLARE_REF(name) \
+  WASM_DECLARE_OWN(shared_##name) \
+  \
+  WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \
+  WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*);
+
+
+WASM_DECLARE_REF_BASE(ref)
+
+
+// Frames
+
+WASM_DECLARE_OWN(frame)
+WASM_DECLARE_VEC(frame, *)
+WASM_API_EXTERN own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*);
+
+WASM_API_EXTERN struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*);
+WASM_API_EXTERN uint32_t wasm_frame_func_index(const wasm_frame_t*);
+WASM_API_EXTERN size_t wasm_frame_func_offset(const wasm_frame_t*);
+WASM_API_EXTERN size_t wasm_frame_module_offset(const wasm_frame_t*);
+
+
+// Traps
+
+typedef wasm_name_t wasm_message_t;  // null terminated
+
+WASM_DECLARE_REF(trap)
+
+WASM_API_EXTERN own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*);
+
+WASM_API_EXTERN void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out);
+WASM_API_EXTERN own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*);
+WASM_API_EXTERN void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out);
+
+
+// Foreign Objects
+
+WASM_DECLARE_REF(foreign)
+
+WASM_API_EXTERN own wasm_foreign_t* wasm_foreign_new(wasm_store_t*);
+
+
+// Modules
+
+WASM_DECLARE_SHARABLE_REF(module)
+
+WASM_API_EXTERN own wasm_module_t* wasm_module_new(
+  wasm_store_t*, const wasm_byte_vec_t* binary);
+
+WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary);
+
+WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out);
+WASM_API_EXTERN void wasm_module_exports(const wasm_module_t*, own wasm_exporttype_vec_t* out);
+
+WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out);
+WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*);
+
+
+// Function Instances
+
+WASM_DECLARE_REF(func)
+
+typedef own wasm_trap_t* (*wasm_func_callback_t)(
+  const wasm_val_vec_t* args, own wasm_val_vec_t* results);
+typedef own wasm_trap_t* (*wasm_func_callback_with_env_t)(
+  void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results);
+
+WASM_API_EXTERN own wasm_func_t* wasm_func_new(
+  wasm_store_t*, const wasm_functype_t*, wasm_func_callback_t);
+WASM_API_EXTERN own wasm_func_t* wasm_func_new_with_env(
+  wasm_store_t*, const wasm_functype_t* type, wasm_func_callback_with_env_t,
+  void* env, void (*finalizer)(void*));
+
+WASM_API_EXTERN own wasm_functype_t* wasm_func_type(const wasm_func_t*);
+WASM_API_EXTERN size_t wasm_func_param_arity(const wasm_func_t*);
+WASM_API_EXTERN size_t wasm_func_result_arity(const wasm_func_t*);
+
+WASM_API_EXTERN own wasm_trap_t* wasm_func_call(
+  const wasm_func_t*, const wasm_val_vec_t* args, wasm_val_vec_t* results);
+
+
+// Global Instances
+
+WASM_DECLARE_REF(global)
+
+WASM_API_EXTERN own wasm_global_t* wasm_global_new(
+  wasm_store_t*, const wasm_globaltype_t*, const wasm_val_t*);
+
+WASM_API_EXTERN own wasm_globaltype_t* wasm_global_type(const wasm_global_t*);
+
+WASM_API_EXTERN void wasm_global_get(const wasm_global_t*, own wasm_val_t* out);
+WASM_API_EXTERN void wasm_global_set(wasm_global_t*, const wasm_val_t*);
+
+
+// Table Instances
+
+WASM_DECLARE_REF(table)
+
+typedef uint32_t wasm_table_size_t;
+
+WASM_API_EXTERN own wasm_table_t* wasm_table_new(
+  wasm_store_t*, const wasm_tabletype_t*, wasm_ref_t* init);
+
+WASM_API_EXTERN own wasm_tabletype_t* wasm_table_type(const wasm_table_t*);
+
+WASM_API_EXTERN own wasm_ref_t* wasm_table_get(const wasm_table_t*, wasm_table_size_t index);
+WASM_API_EXTERN bool wasm_table_set(wasm_table_t*, wasm_table_size_t index, wasm_ref_t*);
+
+WASM_API_EXTERN wasm_table_size_t wasm_table_size(const wasm_table_t*);
+WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init);
+
+
+// Memory Instances
+
+WASM_DECLARE_REF(memory)
+
+typedef uint32_t wasm_memory_pages_t;
+
+static const size_t MEMORY_PAGE_SIZE = 0x10000;
+
+WASM_API_EXTERN own wasm_memory_t* wasm_memory_new(wasm_store_t*, const wasm_memorytype_t*);
+
+WASM_API_EXTERN own wasm_memorytype_t* wasm_memory_type(const wasm_memory_t*);
+
+WASM_API_EXTERN byte_t* wasm_memory_data(wasm_memory_t*);
+WASM_API_EXTERN size_t wasm_memory_data_size(const wasm_memory_t*);
+
+WASM_API_EXTERN wasm_memory_pages_t wasm_memory_size(const wasm_memory_t*);
+WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta);
+
+
+// Externals
+
+WASM_DECLARE_REF(extern)
+WASM_DECLARE_VEC(extern, *)
+
+WASM_API_EXTERN wasm_externkind_t wasm_extern_kind(const wasm_extern_t*);
+WASM_API_EXTERN own wasm_externtype_t* wasm_extern_type(const wasm_extern_t*);
+
+WASM_API_EXTERN wasm_extern_t* wasm_func_as_extern(wasm_func_t*);
+WASM_API_EXTERN wasm_extern_t* wasm_global_as_extern(wasm_global_t*);
+WASM_API_EXTERN wasm_extern_t* wasm_table_as_extern(wasm_table_t*);
+WASM_API_EXTERN wasm_extern_t* wasm_memory_as_extern(wasm_memory_t*);
+
+WASM_API_EXTERN wasm_func_t* wasm_extern_as_func(wasm_extern_t*);
+WASM_API_EXTERN wasm_global_t* wasm_extern_as_global(wasm_extern_t*);
+WASM_API_EXTERN wasm_table_t* wasm_extern_as_table(wasm_extern_t*);
+WASM_API_EXTERN wasm_memory_t* wasm_extern_as_memory(wasm_extern_t*);
+
+WASM_API_EXTERN const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t*);
+WASM_API_EXTERN const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t*);
+WASM_API_EXTERN const wasm_extern_t* wasm_table_as_extern_const(const wasm_table_t*);
+WASM_API_EXTERN const wasm_extern_t* wasm_memory_as_extern_const(const wasm_memory_t*);
+
+WASM_API_EXTERN const wasm_func_t* wasm_extern_as_func_const(const wasm_extern_t*);
+WASM_API_EXTERN const wasm_global_t* wasm_extern_as_global_const(const wasm_extern_t*);
+WASM_API_EXTERN const wasm_table_t* wasm_extern_as_table_const(const wasm_extern_t*);
+WASM_API_EXTERN const wasm_memory_t* wasm_extern_as_memory_const(const wasm_extern_t*);
+
+
+// Module Instances
+
+WASM_DECLARE_REF(instance)
+
+WASM_API_EXTERN own wasm_instance_t* wasm_instance_new(
+  wasm_store_t*, const wasm_module_t*, const wasm_extern_vec_t* imports,
+  own wasm_trap_t**
+);
+
+WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out);
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Convenience
+
+// Vectors
+
+#define WASM_EMPTY_VEC {0, NULL}
+#define WASM_ARRAY_VEC(array) {sizeof(array)/sizeof(*(array)), array}
+
+
+// Value Type construction short-hands
+
+static inline own wasm_valtype_t* wasm_valtype_new_i32() {
+  return wasm_valtype_new(WASM_I32);
+}
+static inline own wasm_valtype_t* wasm_valtype_new_i64() {
+  return wasm_valtype_new(WASM_I64);
+}
+static inline own wasm_valtype_t* wasm_valtype_new_f32() {
+  return wasm_valtype_new(WASM_F32);
+}
+static inline own wasm_valtype_t* wasm_valtype_new_f64() {
+  return wasm_valtype_new(WASM_F64);
+}
+
+static inline own wasm_valtype_t* wasm_valtype_new_anyref() {
+  return wasm_valtype_new(WASM_ANYREF);
+}
+static inline own wasm_valtype_t* wasm_valtype_new_funcref() {
+  return wasm_valtype_new(WASM_FUNCREF);
+}
+
+
+// Function Types construction short-hands
+
+static inline own wasm_functype_t* wasm_functype_new_0_0() {
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new_empty(&params);
+  wasm_valtype_vec_new_empty(&results);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_1_0(
+  own wasm_valtype_t* p
+) {
+  wasm_valtype_t* ps[1] = {p};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new(&params, 1, ps);
+  wasm_valtype_vec_new_empty(&results);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_2_0(
+  own wasm_valtype_t* p1, own wasm_valtype_t* p2
+) {
+  wasm_valtype_t* ps[2] = {p1, p2};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new(&params, 2, ps);
+  wasm_valtype_vec_new_empty(&results);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_3_0(
+  own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3
+) {
+  wasm_valtype_t* ps[3] = {p1, p2, p3};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new(&params, 3, ps);
+  wasm_valtype_vec_new_empty(&results);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_0_1(
+  own wasm_valtype_t* r
+) {
+  wasm_valtype_t* rs[1] = {r};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new_empty(&params);
+  wasm_valtype_vec_new(&results, 1, rs);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_1_1(
+  own wasm_valtype_t* p, own wasm_valtype_t* r
+) {
+  wasm_valtype_t* ps[1] = {p};
+  wasm_valtype_t* rs[1] = {r};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new(&params, 1, ps);
+  wasm_valtype_vec_new(&results, 1, rs);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_2_1(
+  own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* r
+) {
+  wasm_valtype_t* ps[2] = {p1, p2};
+  wasm_valtype_t* rs[1] = {r};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new(&params, 2, ps);
+  wasm_valtype_vec_new(&results, 1, rs);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_3_1(
+  own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3,
+  own wasm_valtype_t* r
+) {
+  wasm_valtype_t* ps[3] = {p1, p2, p3};
+  wasm_valtype_t* rs[1] = {r};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new(&params, 3, ps);
+  wasm_valtype_vec_new(&results, 1, rs);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_0_2(
+  own wasm_valtype_t* r1, own wasm_valtype_t* r2
+) {
+  wasm_valtype_t* rs[2] = {r1, r2};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new_empty(&params);
+  wasm_valtype_vec_new(&results, 2, rs);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_1_2(
+  own wasm_valtype_t* p, own wasm_valtype_t* r1, own wasm_valtype_t* r2
+) {
+  wasm_valtype_t* ps[1] = {p};
+  wasm_valtype_t* rs[2] = {r1, r2};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new(&params, 1, ps);
+  wasm_valtype_vec_new(&results, 2, rs);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_2_2(
+  own wasm_valtype_t* p1, own wasm_valtype_t* p2,
+  own wasm_valtype_t* r1, own wasm_valtype_t* r2
+) {
+  wasm_valtype_t* ps[2] = {p1, p2};
+  wasm_valtype_t* rs[2] = {r1, r2};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new(&params, 2, ps);
+  wasm_valtype_vec_new(&results, 2, rs);
+  return wasm_functype_new(&params, &results);
+}
+
+static inline own wasm_functype_t* wasm_functype_new_3_2(
+  own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3,
+  own wasm_valtype_t* r1, own wasm_valtype_t* r2
+) {
+  wasm_valtype_t* ps[3] = {p1, p2, p3};
+  wasm_valtype_t* rs[2] = {r1, r2};
+  wasm_valtype_vec_t params, results;
+  wasm_valtype_vec_new(&params, 3, ps);
+  wasm_valtype_vec_new(&results, 2, rs);
+  return wasm_functype_new(&params, &results);
+}
+
+
+// Value construction short-hands
+
+static inline void wasm_val_init_ptr(own wasm_val_t* out, void* p) {
+#if UINTPTR_MAX == UINT32_MAX
+  out->kind = WASM_I32;
+  out->of.i32 = (intptr_t)p;
+#elif UINTPTR_MAX == UINT64_MAX
+  out->kind = WASM_I64;
+  out->of.i64 = (intptr_t)p;
+#endif
+}
+
+static inline void* wasm_val_ptr(const wasm_val_t* val) {
+#if UINTPTR_MAX == UINT32_MAX
+  return (void*)(intptr_t)val->of.i32;
+#elif UINTPTR_MAX == UINT64_MAX
+  return (void*)(intptr_t)val->of.i64;
+#endif
+}
+
+#define WASM_I32_VAL(i) (wasm_val_t) {.kind = WASM_I32, .of = {.i32 = i}}
+#define WASM_I64_VAL(i) (wasm_val_t) {.kind = WASM_I64, .of = {.i64 = i}}
+#define WASM_F32_VAL(z) (wasm_val_t) {.kind = WASM_F32, .of = {.f32 = z}}
+#define WASM_F64_VAL(z) (wasm_val_t) {.kind = WASM_F64, .of = {.f64 = z}}
+#define WASM_REF_VAL(r) (wasm_val_t) {.kind = WASM_ANYREF, .of = {.ref = r}}
+#define WASM_INIT_VAL   (wasm_val_t) {.kind = WASM_ANYREF, .of = {.ref = NULL}}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+#undef own
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // #ifdef WASM_H
diff --git a/lib/linux_x86_64/include/wasmer.h b/lib/linux_x86_64/include/wasmer.h
new file mode 100644 (file)
index 0000000..d700a4f
--- /dev/null
@@ -0,0 +1,896 @@
+// The Wasmer C/C++ header file compatible with the [`wasm-c-api`]
+// standard API, as `wasm.h` (included here).
+//
+// This file is automatically generated by `lib/c-api/build.rs` of the
+// [`wasmer-c-api`] Rust crate.
+//
+// # Stability
+//
+// The [`wasm-c-api`] standard API is a _living_ standard. There is no
+// commitment for stability yet. We (Wasmer) will try our best to keep
+// backward compatibility as much as possible. Nonetheless, some
+// necessary API aren't yet standardized, and as such, we provide a
+// custom API, e.g. `wasi_*` types and functions.
+//
+// The documentation makes it clear whether a function is unstable.
+// 
+// When a type or a function will be deprecated, it will be marked as
+// such with the appropriated compiler warning, and will be removed at
+// the next release round.
+//
+// # Documentation
+//
+// At the time of writing, the [`wasm-c-api`] standard has no
+// documentation. This file also does not include inline
+// documentation. However, we have made (and we continue to make) an
+// important effort to document everything. [See the documentation
+// online][documentation]. Please refer to this page for the real
+// canonical documentation. It also contains numerous examples.
+//
+// To generate the documentation locally, run `cargo doc --open` from
+// within the [`wasmer-c-api`] Rust crate.
+//
+// [`wasm-c-api`]: https://github.com/WebAssembly/wasm-c-api
+// [`wasmer-c-api`]: https://github.com/wasmerio/wasmer/tree/master/lib/c-api
+// [documentation]: https://wasmerio.github.io/wasmer/crates/wasmer_c_api/
+
+#if !defined(WASMER_H_PRELUDE)
+
+#define WASMER_H_PRELUDE
+
+// Define the `ARCH_X86_X64` constant.
+#if defined(MSVC) && defined(_M_AMD64)
+#  define ARCH_X86_64
+#elif (defined(GCC) || defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__)
+#  define ARCH_X86_64
+#endif
+
+// Compatibility with non-Clang compilers.
+#if !defined(__has_attribute)
+#  define __has_attribute(x) 0
+#endif
+
+// Compatibility with non-Clang compilers.
+#if !defined(__has_declspec_attribute)
+#  define __has_declspec_attribute(x) 0
+#endif
+
+// Define the `DEPRECATED` macro.
+#if defined(GCC) || defined(__GNUC__) || __has_attribute(deprecated)
+#  define DEPRECATED(message) __attribute__((deprecated(message)))
+#elif defined(MSVC) || __has_declspec_attribute(deprecated)
+#  define DEPRECATED(message) __declspec(deprecated(message))
+#endif
+
+// The `universal` feature has been enabled for this build.
+#define WASMER_UNIVERSAL_ENABLED
+
+// The `compiler` feature has been enabled for this build.
+#define WASMER_COMPILER_ENABLED
+
+// The `wasi` feature has been enabled for this build.
+#define WASMER_WASI_ENABLED
+
+// The `middlewares` feature has been enabled for this build.
+#define WASMER_MIDDLEWARES_ENABLED
+
+// This file corresponds to the following Wasmer version.
+#define WASMER_VERSION "2.0.0"
+#define WASMER_VERSION_MAJOR 2
+#define WASMER_VERSION_MINOR 0
+#define WASMER_VERSION_PATCH 0
+#define WASMER_VERSION_PRE ""
+
+#endif // WASMER_H_PRELUDE
+
+
+//
+// OK, here we go. The code below is automatically generated.
+//
+
+
+#ifndef WASMER_H
+#define WASMER_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "wasm.h"
+
+#if defined(WASMER_WASI_ENABLED)
+typedef enum wasi_version_t {
+#if defined(WASMER_WASI_ENABLED)
+  INVALID_VERSION = -1,
+#endif
+#if defined(WASMER_WASI_ENABLED)
+  LATEST = 0,
+#endif
+#if defined(WASMER_WASI_ENABLED)
+  SNAPSHOT0 = 1,
+#endif
+#if defined(WASMER_WASI_ENABLED)
+  SNAPSHOT1 = 2,
+#endif
+} wasi_version_t;
+#endif
+
+#if defined(WASMER_COMPILER_ENABLED)
+typedef enum wasmer_compiler_t {
+  CRANELIFT = 0,
+  LLVM = 1,
+  SINGLEPASS = 2,
+} wasmer_compiler_t;
+#endif
+
+typedef enum wasmer_engine_t {
+  UNIVERSAL = 0,
+  DYLIB = 1,
+  STATICLIB = 2,
+} wasmer_engine_t;
+
+typedef enum wasmer_parser_operator_t {
+  Unreachable,
+  Nop,
+  Block,
+  Loop,
+  If,
+  Else,
+  Try,
+  Catch,
+  CatchAll,
+  Delegate,
+  Throw,
+  Rethrow,
+  Unwind,
+  End,
+  Br,
+  BrIf,
+  BrTable,
+  Return,
+  Call,
+  CallIndirect,
+  ReturnCall,
+  ReturnCallIndirect,
+  Drop,
+  Select,
+  TypedSelect,
+  LocalGet,
+  LocalSet,
+  LocalTee,
+  GlobalGet,
+  GlobalSet,
+  I32Load,
+  I64Load,
+  F32Load,
+  F64Load,
+  I32Load8S,
+  I32Load8U,
+  I32Load16S,
+  I32Load16U,
+  I64Load8S,
+  I64Load8U,
+  I64Load16S,
+  I64Load16U,
+  I64Load32S,
+  I64Load32U,
+  I32Store,
+  I64Store,
+  F32Store,
+  F64Store,
+  I32Store8,
+  I32Store16,
+  I64Store8,
+  I64Store16,
+  I64Store32,
+  MemorySize,
+  MemoryGrow,
+  I32Const,
+  I64Const,
+  F32Const,
+  F64Const,
+  RefNull,
+  RefIsNull,
+  RefFunc,
+  I32Eqz,
+  I32Eq,
+  I32Ne,
+  I32LtS,
+  I32LtU,
+  I32GtS,
+  I32GtU,
+  I32LeS,
+  I32LeU,
+  I32GeS,
+  I32GeU,
+  I64Eqz,
+  I64Eq,
+  I64Ne,
+  I64LtS,
+  I64LtU,
+  I64GtS,
+  I64GtU,
+  I64LeS,
+  I64LeU,
+  I64GeS,
+  I64GeU,
+  F32Eq,
+  F32Ne,
+  F32Lt,
+  F32Gt,
+  F32Le,
+  F32Ge,
+  F64Eq,
+  F64Ne,
+  F64Lt,
+  F64Gt,
+  F64Le,
+  F64Ge,
+  I32Clz,
+  I32Ctz,
+  I32Popcnt,
+  I32Add,
+  I32Sub,
+  I32Mul,
+  I32DivS,
+  I32DivU,
+  I32RemS,
+  I32RemU,
+  I32And,
+  I32Or,
+  I32Xor,
+  I32Shl,
+  I32ShrS,
+  I32ShrU,
+  I32Rotl,
+  I32Rotr,
+  I64Clz,
+  I64Ctz,
+  I64Popcnt,
+  I64Add,
+  I64Sub,
+  I64Mul,
+  I64DivS,
+  I64DivU,
+  I64RemS,
+  I64RemU,
+  I64And,
+  I64Or,
+  I64Xor,
+  I64Shl,
+  I64ShrS,
+  I64ShrU,
+  I64Rotl,
+  I64Rotr,
+  F32Abs,
+  F32Neg,
+  F32Ceil,
+  F32Floor,
+  F32Trunc,
+  F32Nearest,
+  F32Sqrt,
+  F32Add,
+  F32Sub,
+  F32Mul,
+  F32Div,
+  F32Min,
+  F32Max,
+  F32Copysign,
+  F64Abs,
+  F64Neg,
+  F64Ceil,
+  F64Floor,
+  F64Trunc,
+  F64Nearest,
+  F64Sqrt,
+  F64Add,
+  F64Sub,
+  F64Mul,
+  F64Div,
+  F64Min,
+  F64Max,
+  F64Copysign,
+  I32WrapI64,
+  I32TruncF32S,
+  I32TruncF32U,
+  I32TruncF64S,
+  I32TruncF64U,
+  I64ExtendI32S,
+  I64ExtendI32U,
+  I64TruncF32S,
+  I64TruncF32U,
+  I64TruncF64S,
+  I64TruncF64U,
+  F32ConvertI32S,
+  F32ConvertI32U,
+  F32ConvertI64S,
+  F32ConvertI64U,
+  F32DemoteF64,
+  F64ConvertI32S,
+  F64ConvertI32U,
+  F64ConvertI64S,
+  F64ConvertI64U,
+  F64PromoteF32,
+  I32ReinterpretF32,
+  I64ReinterpretF64,
+  F32ReinterpretI32,
+  F64ReinterpretI64,
+  I32Extend8S,
+  I32Extend16S,
+  I64Extend8S,
+  I64Extend16S,
+  I64Extend32S,
+  I32TruncSatF32S,
+  I32TruncSatF32U,
+  I32TruncSatF64S,
+  I32TruncSatF64U,
+  I64TruncSatF32S,
+  I64TruncSatF32U,
+  I64TruncSatF64S,
+  I64TruncSatF64U,
+  MemoryInit,
+  DataDrop,
+  MemoryCopy,
+  MemoryFill,
+  TableInit,
+  ElemDrop,
+  TableCopy,
+  TableFill,
+  TableGet,
+  TableSet,
+  TableGrow,
+  TableSize,
+  MemoryAtomicNotify,
+  MemoryAtomicWait32,
+  MemoryAtomicWait64,
+  AtomicFence,
+  I32AtomicLoad,
+  I64AtomicLoad,
+  I32AtomicLoad8U,
+  I32AtomicLoad16U,
+  I64AtomicLoad8U,
+  I64AtomicLoad16U,
+  I64AtomicLoad32U,
+  I32AtomicStore,
+  I64AtomicStore,
+  I32AtomicStore8,
+  I32AtomicStore16,
+  I64AtomicStore8,
+  I64AtomicStore16,
+  I64AtomicStore32,
+  I32AtomicRmwAdd,
+  I64AtomicRmwAdd,
+  I32AtomicRmw8AddU,
+  I32AtomicRmw16AddU,
+  I64AtomicRmw8AddU,
+  I64AtomicRmw16AddU,
+  I64AtomicRmw32AddU,
+  I32AtomicRmwSub,
+  I64AtomicRmwSub,
+  I32AtomicRmw8SubU,
+  I32AtomicRmw16SubU,
+  I64AtomicRmw8SubU,
+  I64AtomicRmw16SubU,
+  I64AtomicRmw32SubU,
+  I32AtomicRmwAnd,
+  I64AtomicRmwAnd,
+  I32AtomicRmw8AndU,
+  I32AtomicRmw16AndU,
+  I64AtomicRmw8AndU,
+  I64AtomicRmw16AndU,
+  I64AtomicRmw32AndU,
+  I32AtomicRmwOr,
+  I64AtomicRmwOr,
+  I32AtomicRmw8OrU,
+  I32AtomicRmw16OrU,
+  I64AtomicRmw8OrU,
+  I64AtomicRmw16OrU,
+  I64AtomicRmw32OrU,
+  I32AtomicRmwXor,
+  I64AtomicRmwXor,
+  I32AtomicRmw8XorU,
+  I32AtomicRmw16XorU,
+  I64AtomicRmw8XorU,
+  I64AtomicRmw16XorU,
+  I64AtomicRmw32XorU,
+  I32AtomicRmwXchg,
+  I64AtomicRmwXchg,
+  I32AtomicRmw8XchgU,
+  I32AtomicRmw16XchgU,
+  I64AtomicRmw8XchgU,
+  I64AtomicRmw16XchgU,
+  I64AtomicRmw32XchgU,
+  I32AtomicRmwCmpxchg,
+  I64AtomicRmwCmpxchg,
+  I32AtomicRmw8CmpxchgU,
+  I32AtomicRmw16CmpxchgU,
+  I64AtomicRmw8CmpxchgU,
+  I64AtomicRmw16CmpxchgU,
+  I64AtomicRmw32CmpxchgU,
+  V128Load,
+  V128Store,
+  V128Const,
+  I8x16Splat,
+  I8x16ExtractLaneS,
+  I8x16ExtractLaneU,
+  I8x16ReplaceLane,
+  I16x8Splat,
+  I16x8ExtractLaneS,
+  I16x8ExtractLaneU,
+  I16x8ReplaceLane,
+  I32x4Splat,
+  I32x4ExtractLane,
+  I32x4ReplaceLane,
+  I64x2Splat,
+  I64x2ExtractLane,
+  I64x2ReplaceLane,
+  F32x4Splat,
+  F32x4ExtractLane,
+  F32x4ReplaceLane,
+  F64x2Splat,
+  F64x2ExtractLane,
+  F64x2ReplaceLane,
+  I8x16Eq,
+  I8x16Ne,
+  I8x16LtS,
+  I8x16LtU,
+  I8x16GtS,
+  I8x16GtU,
+  I8x16LeS,
+  I8x16LeU,
+  I8x16GeS,
+  I8x16GeU,
+  I16x8Eq,
+  I16x8Ne,
+  I16x8LtS,
+  I16x8LtU,
+  I16x8GtS,
+  I16x8GtU,
+  I16x8LeS,
+  I16x8LeU,
+  I16x8GeS,
+  I16x8GeU,
+  I32x4Eq,
+  I32x4Ne,
+  I32x4LtS,
+  I32x4LtU,
+  I32x4GtS,
+  I32x4GtU,
+  I32x4LeS,
+  I32x4LeU,
+  I32x4GeS,
+  I32x4GeU,
+  I64x2Eq,
+  I64x2Ne,
+  I64x2LtS,
+  I64x2GtS,
+  I64x2LeS,
+  I64x2GeS,
+  F32x4Eq,
+  F32x4Ne,
+  F32x4Lt,
+  F32x4Gt,
+  F32x4Le,
+  F32x4Ge,
+  F64x2Eq,
+  F64x2Ne,
+  F64x2Lt,
+  F64x2Gt,
+  F64x2Le,
+  F64x2Ge,
+  V128Not,
+  V128And,
+  V128AndNot,
+  V128Or,
+  V128Xor,
+  V128Bitselect,
+  V128AnyTrue,
+  I8x16Abs,
+  I8x16Neg,
+  I8x16AllTrue,
+  I8x16Bitmask,
+  I8x16Shl,
+  I8x16ShrS,
+  I8x16ShrU,
+  I8x16Add,
+  I8x16AddSatS,
+  I8x16AddSatU,
+  I8x16Sub,
+  I8x16SubSatS,
+  I8x16SubSatU,
+  I8x16MinS,
+  I8x16MinU,
+  I8x16MaxS,
+  I8x16MaxU,
+  I8x16Popcnt,
+  I16x8Abs,
+  I16x8Neg,
+  I16x8AllTrue,
+  I16x8Bitmask,
+  I16x8Shl,
+  I16x8ShrS,
+  I16x8ShrU,
+  I16x8Add,
+  I16x8AddSatS,
+  I16x8AddSatU,
+  I16x8Sub,
+  I16x8SubSatS,
+  I16x8SubSatU,
+  I16x8Mul,
+  I16x8MinS,
+  I16x8MinU,
+  I16x8MaxS,
+  I16x8MaxU,
+  I16x8ExtAddPairwiseI8x16S,
+  I16x8ExtAddPairwiseI8x16U,
+  I32x4Abs,
+  I32x4Neg,
+  I32x4AllTrue,
+  I32x4Bitmask,
+  I32x4Shl,
+  I32x4ShrS,
+  I32x4ShrU,
+  I32x4Add,
+  I32x4Sub,
+  I32x4Mul,
+  I32x4MinS,
+  I32x4MinU,
+  I32x4MaxS,
+  I32x4MaxU,
+  I32x4DotI16x8S,
+  I32x4ExtAddPairwiseI16x8S,
+  I32x4ExtAddPairwiseI16x8U,
+  I64x2Abs,
+  I64x2Neg,
+  I64x2AllTrue,
+  I64x2Bitmask,
+  I64x2Shl,
+  I64x2ShrS,
+  I64x2ShrU,
+  I64x2Add,
+  I64x2Sub,
+  I64x2Mul,
+  F32x4Ceil,
+  F32x4Floor,
+  F32x4Trunc,
+  F32x4Nearest,
+  F64x2Ceil,
+  F64x2Floor,
+  F64x2Trunc,
+  F64x2Nearest,
+  F32x4Abs,
+  F32x4Neg,
+  F32x4Sqrt,
+  F32x4Add,
+  F32x4Sub,
+  F32x4Mul,
+  F32x4Div,
+  F32x4Min,
+  F32x4Max,
+  F32x4PMin,
+  F32x4PMax,
+  F64x2Abs,
+  F64x2Neg,
+  F64x2Sqrt,
+  F64x2Add,
+  F64x2Sub,
+  F64x2Mul,
+  F64x2Div,
+  F64x2Min,
+  F64x2Max,
+  F64x2PMin,
+  F64x2PMax,
+  I32x4TruncSatF32x4S,
+  I32x4TruncSatF32x4U,
+  F32x4ConvertI32x4S,
+  F32x4ConvertI32x4U,
+  I8x16Swizzle,
+  I8x16Shuffle,
+  V128Load8Splat,
+  V128Load16Splat,
+  V128Load32Splat,
+  V128Load32Zero,
+  V128Load64Splat,
+  V128Load64Zero,
+  I8x16NarrowI16x8S,
+  I8x16NarrowI16x8U,
+  I16x8NarrowI32x4S,
+  I16x8NarrowI32x4U,
+  I16x8ExtendLowI8x16S,
+  I16x8ExtendHighI8x16S,
+  I16x8ExtendLowI8x16U,
+  I16x8ExtendHighI8x16U,
+  I32x4ExtendLowI16x8S,
+  I32x4ExtendHighI16x8S,
+  I32x4ExtendLowI16x8U,
+  I32x4ExtendHighI16x8U,
+  I64x2ExtendLowI32x4S,
+  I64x2ExtendHighI32x4S,
+  I64x2ExtendLowI32x4U,
+  I64x2ExtendHighI32x4U,
+  I16x8ExtMulLowI8x16S,
+  I16x8ExtMulHighI8x16S,
+  I16x8ExtMulLowI8x16U,
+  I16x8ExtMulHighI8x16U,
+  I32x4ExtMulLowI16x8S,
+  I32x4ExtMulHighI16x8S,
+  I32x4ExtMulLowI16x8U,
+  I32x4ExtMulHighI16x8U,
+  I64x2ExtMulLowI32x4S,
+  I64x2ExtMulHighI32x4S,
+  I64x2ExtMulLowI32x4U,
+  I64x2ExtMulHighI32x4U,
+  V128Load8x8S,
+  V128Load8x8U,
+  V128Load16x4S,
+  V128Load16x4U,
+  V128Load32x2S,
+  V128Load32x2U,
+  V128Load8Lane,
+  V128Load16Lane,
+  V128Load32Lane,
+  V128Load64Lane,
+  V128Store8Lane,
+  V128Store16Lane,
+  V128Store32Lane,
+  V128Store64Lane,
+  I8x16RoundingAverageU,
+  I16x8RoundingAverageU,
+  I16x8Q15MulrSatS,
+  F32x4DemoteF64x2Zero,
+  F64x2PromoteLowF32x4,
+  F64x2ConvertLowI32x4S,
+  F64x2ConvertLowI32x4U,
+  I32x4TruncSatF64x2SZero,
+  I32x4TruncSatF64x2UZero,
+} wasmer_parser_operator_t;
+
+#if defined(WASMER_WASI_ENABLED)
+typedef struct wasi_config_t wasi_config_t;
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+typedef struct wasi_env_t wasi_env_t;
+#endif
+
+typedef struct wasmer_cpu_features_t wasmer_cpu_features_t;
+
+typedef struct wasmer_features_t wasmer_features_t;
+
+typedef struct wasmer_metering_t wasmer_metering_t;
+
+typedef struct wasmer_middleware_t wasmer_middleware_t;
+
+#if defined(WASMER_WASI_ENABLED)
+typedef struct wasmer_named_extern_t wasmer_named_extern_t;
+#endif
+
+typedef struct wasmer_target_t wasmer_target_t;
+
+typedef struct wasmer_triple_t wasmer_triple_t;
+
+#if defined(WASMER_WASI_ENABLED)
+typedef struct wasmer_named_extern_vec_t {
+  uintptr_t size;
+  struct wasmer_named_extern_t **data;
+} wasmer_named_extern_vec_t;
+#endif
+
+typedef uint64_t (*wasmer_metering_cost_function_t)(enum wasmer_parser_operator_t wasm_operator);
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#if defined(WASMER_WASI_ENABLED)
+void wasi_config_arg(struct wasi_config_t *config, const char *arg);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasi_config_capture_stderr(struct wasi_config_t *config);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasi_config_capture_stdout(struct wasi_config_t *config);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasi_config_env(struct wasi_config_t *config, const char *key, const char *value);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasi_config_inherit_stderr(struct wasi_config_t *config);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasi_config_inherit_stdin(struct wasi_config_t *config);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasi_config_inherit_stdout(struct wasi_config_t *config);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+bool wasi_config_mapdir(struct wasi_config_t *config, const char *alias, const char *dir);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+struct wasi_config_t *wasi_config_new(const char *program_name);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+bool wasi_config_preopen_dir(struct wasi_config_t *config, const char *dir);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasi_env_delete(struct wasi_env_t *_state);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+struct wasi_env_t *wasi_env_new(struct wasi_config_t *config);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+intptr_t wasi_env_read_stderr(struct wasi_env_t *env, char *buffer, uintptr_t buffer_len);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+intptr_t wasi_env_read_stdout(struct wasi_env_t *env, char *buffer, uintptr_t buffer_len);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+bool wasi_get_imports(const wasm_store_t *store,
+                      const wasm_module_t *module,
+                      const struct wasi_env_t *wasi_env,
+                      wasm_extern_vec_t *imports);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+wasm_func_t *wasi_get_start_function(wasm_instance_t *instance);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+bool wasi_get_unordered_imports(const wasm_store_t *store,
+                                const wasm_module_t *module,
+                                const struct wasi_env_t *wasi_env,
+                                struct wasmer_named_extern_vec_t *imports);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+enum wasi_version_t wasi_get_wasi_version(const wasm_module_t *module);
+#endif
+
+void wasm_config_canonicalize_nans(wasm_config_t *config, bool enable);
+
+void wasm_config_push_middleware(wasm_config_t *config, struct wasmer_middleware_t *middleware);
+
+#if defined(WASMER_COMPILER_ENABLED)
+void wasm_config_set_compiler(wasm_config_t *config, enum wasmer_compiler_t compiler);
+#endif
+
+void wasm_config_set_engine(wasm_config_t *config, enum wasmer_engine_t engine);
+
+void wasm_config_set_features(wasm_config_t *config, struct wasmer_features_t *features);
+
+void wasm_config_set_target(wasm_config_t *config, struct wasmer_target_t *target);
+
+bool wasmer_cpu_features_add(struct wasmer_cpu_features_t *cpu_features,
+                             const wasm_name_t *feature);
+
+void wasmer_cpu_features_delete(struct wasmer_cpu_features_t *_cpu_features);
+
+struct wasmer_cpu_features_t *wasmer_cpu_features_new(void);
+
+bool wasmer_features_bulk_memory(struct wasmer_features_t *features, bool enable);
+
+void wasmer_features_delete(struct wasmer_features_t *_features);
+
+bool wasmer_features_memory64(struct wasmer_features_t *features, bool enable);
+
+bool wasmer_features_module_linking(struct wasmer_features_t *features, bool enable);
+
+bool wasmer_features_multi_memory(struct wasmer_features_t *features, bool enable);
+
+bool wasmer_features_multi_value(struct wasmer_features_t *features, bool enable);
+
+struct wasmer_features_t *wasmer_features_new(void);
+
+bool wasmer_features_reference_types(struct wasmer_features_t *features, bool enable);
+
+bool wasmer_features_simd(struct wasmer_features_t *features, bool enable);
+
+bool wasmer_features_tail_call(struct wasmer_features_t *features, bool enable);
+
+bool wasmer_features_threads(struct wasmer_features_t *features, bool enable);
+
+bool wasmer_is_compiler_available(enum wasmer_compiler_t compiler);
+
+bool wasmer_is_engine_available(enum wasmer_engine_t engine);
+
+bool wasmer_is_headless(void);
+
+int wasmer_last_error_length(void);
+
+int wasmer_last_error_message(char *buffer, int length);
+
+struct wasmer_middleware_t *wasmer_metering_as_middleware(struct wasmer_metering_t *metering);
+
+void wasmer_metering_delete(struct wasmer_metering_t *_metering);
+
+uint64_t wasmer_metering_get_remaining_points(const wasm_instance_t *instance);
+
+struct wasmer_metering_t *wasmer_metering_new(uint64_t initial_limit,
+                                              wasmer_metering_cost_function_t cost_function);
+
+bool wasmer_metering_points_are_exhausted(const wasm_instance_t *instance);
+
+void wasmer_metering_set_remaining_points(const wasm_instance_t *instance, uint64_t new_limit);
+
+void wasmer_module_name(const wasm_module_t *module, wasm_name_t *out);
+
+bool wasmer_module_set_name(wasm_module_t *module, const wasm_name_t *name);
+
+#if defined(WASMER_WASI_ENABLED)
+const wasm_name_t *wasmer_named_extern_module(const struct wasmer_named_extern_t *named_extern);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+const wasm_name_t *wasmer_named_extern_name(const struct wasmer_named_extern_t *named_extern);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+const wasm_extern_t *wasmer_named_extern_unwrap(const struct wasmer_named_extern_t *named_extern);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasmer_named_extern_vec_copy(struct wasmer_named_extern_vec_t *out_ptr,
+                                  const struct wasmer_named_extern_vec_t *in_ptr);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasmer_named_extern_vec_delete(struct wasmer_named_extern_vec_t *ptr);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasmer_named_extern_vec_new(struct wasmer_named_extern_vec_t *out,
+                                 uintptr_t length,
+                                 struct wasmer_named_extern_t *const *init);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasmer_named_extern_vec_new_empty(struct wasmer_named_extern_vec_t *out);
+#endif
+
+#if defined(WASMER_WASI_ENABLED)
+void wasmer_named_extern_vec_new_uninitialized(struct wasmer_named_extern_vec_t *out,
+                                               uintptr_t length);
+#endif
+
+void wasmer_target_delete(struct wasmer_target_t *_target);
+
+struct wasmer_target_t *wasmer_target_new(struct wasmer_triple_t *triple,
+                                          struct wasmer_cpu_features_t *cpu_features);
+
+void wasmer_triple_delete(struct wasmer_triple_t *_triple);
+
+struct wasmer_triple_t *wasmer_triple_new(const wasm_name_t *triple);
+
+struct wasmer_triple_t *wasmer_triple_new_from_host(void);
+
+const char *wasmer_version(void);
+
+uint8_t wasmer_version_major(void);
+
+uint8_t wasmer_version_minor(void);
+
+uint8_t wasmer_version_patch(void);
+
+const char *wasmer_version_pre(void);
+
+void wat2wasm(const wasm_byte_vec_t *wat, wasm_byte_vec_t *out);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#endif /* WASMER_H */
diff --git a/lib/linux_x86_64/lib/libwasmer.a b/lib/linux_x86_64/lib/libwasmer.a
new file mode 100644 (file)
index 0000000..65ac123
Binary files /dev/null and b/lib/linux_x86_64/lib/libwasmer.a differ
diff --git a/lib/linux_x86_64/lib/libwasmer.so b/lib/linux_x86_64/lib/libwasmer.so
new file mode 100755 (executable)
index 0000000..0fd937a
Binary files /dev/null and b/lib/linux_x86_64/lib/libwasmer.so differ
diff --git a/src/heartbreak.c b/src/heartbreak.c
new file mode 100644 (file)
index 0000000..12b79de
--- /dev/null
@@ -0,0 +1,215 @@
+#define BH_DEFINE
+#include "bh.h"
+
+#include "wasm.h"
+#include "wasmer.h"
+
+b32 wasm_name_equals(const wasm_name_t* name1, const wasm_name_t* name2) {
+    if (name1->size != name2->size) return 0;
+    return !strncmp(name1->data, name2->data, name1->size);
+}
+
+b32 wasm_name_equals_string(const wasm_name_t* name1, const char* name2) {
+    u32 name2_size = strlen(name2);
+    if (name1->size != name2_size) return 0;
+    return !strncmp(name1->data, name2, name1->size);
+}
+
+#define _NUM_VALS(...) (sizeof((wasm_valkind_t[]) {__VA_ARGS__})/sizeof(wasm_valkind_t))
+#define VALS(...) { _NUM_VALS(__VA_ARGS__), __VA_ARGS__ }
+
+typedef struct {
+    u32 count;
+    wasm_valkind_t types[20];
+} WasmValkindBuffer;
+
+typedef struct {
+    char* name;
+    wasm_func_callback_t func;
+
+    WasmValkindBuffer params;
+    WasmValkindBuffer results;
+} WasmFuncDefinition;
+
+#define WASM_FUNCS \
+    WASM_FUNC(init, VALS(), VALS(WASM_I32)) \
+    WASM_FUNC(add,  VALS(WASM_I32, WASM_I32), VALS(WASM_I32))
+
+#define HEARTBREAK_FUNC(name) wasm_trap_t* __heartbreak_interface_ ## name (const wasm_val_vec_t* params, wasm_val_vec_t* results)
+
+HEARTBREAK_FUNC(init) {
+    results->data[0] = WASM_I32_VAL(1234);
+
+    return NULL;
+}
+
+HEARTBREAK_FUNC(add) {
+    results->data[0] = WASM_I32_VAL(params->data[0].of.i32 + params->data[1].of.i32);
+    return NULL;
+}
+
+void run_wasm_file(bh_buffer wasm_bytes) {
+    wasm_config_t*   config = NULL;
+    wasi_config_t*   wasi_config = NULL;
+    wasi_env_t*      wasi_env = NULL;
+
+    wasm_engine_t*   engine = NULL;
+    wasm_store_t*    store = NULL;
+    wasm_module_t*   module = NULL;
+    wasm_instance_t* instance = NULL;
+
+    config = wasm_config_new();
+    if (!config) goto error_handling;
+
+    // Prefer the LLVM compile because it is faster. This should be configurable from the command line and/or a top-level directive.
+    if (wasmer_is_compiler_available(LLVM)) {
+        wasm_config_set_compiler(config, LLVM);
+    }
+
+    wasi_config = wasi_config_new("onyx");
+    wasi_config_preopen_dir(wasi_config, "./");
+
+    wasi_env  = wasi_env_new(wasi_config);
+    if (!wasi_env) goto error_handling;
+
+    engine = wasm_engine_new_with_config(config);
+    if (!engine) goto error_handling;
+
+    store  = wasm_store_new(engine);
+    if (!store) goto error_handling;
+
+    wasm_byte_vec_t wasm_data;
+    wasm_data.size = wasm_bytes.length;
+    wasm_data.data = wasm_bytes.data;
+
+    module = wasm_module_new(store, &wasm_data);
+    if (!module) goto error_handling;
+
+    wasmer_named_extern_vec_t wasi_imports;
+    wasi_get_unordered_imports(store, module, wasi_env, &wasi_imports);
+
+    #define WASM_FUNC(name, params_types, result_types) (WasmFuncDefinition) { #name, __heartbreak_interface_ ## name, params_types, result_types },
+    static WasmFuncDefinition defs[] = {
+        WASM_FUNCS
+        { NULL }
+    };
+    #undef WASM_FUNC
+
+    u32 defs_count = sizeof(defs) / sizeof(WasmFuncDefinition);
+    wasm_name_t heartbreak_name;
+    wasm_name_new_from_string(&heartbreak_name, "heartbreak");
+
+    wasm_importtype_vec_t module_imports;    // @Free
+    wasm_module_imports(module, &module_imports);
+
+    wasm_extern_vec_t imports;
+    wasm_extern_vec_new_uninitialized(&imports, module_imports.size); // @Free
+
+    fori (i, 0, (i32) module_imports.size) {
+        const wasm_name_t* module_name = wasm_importtype_module(module_imports.data[i]);
+        const wasm_name_t* import_name = wasm_importtype_name(module_imports.data[i]);
+
+        wasm_extern_t* import = NULL;
+        
+        // First try WASI
+        fori (j, 0, (i32) wasi_imports.size) {
+            const wasm_name_t* wasi_module_name = wasmer_named_extern_module(wasi_imports.data[j]);
+            const wasm_name_t* wasi_import_name = wasmer_named_extern_name(wasi_imports.data[j]);
+            if (wasm_name_equals(module_name, wasi_module_name) && wasm_name_equals(import_name, wasi_import_name)) {
+                import = (wasm_extern_t *) wasmer_named_extern_unwrap(wasi_imports.data[j]);
+                goto import_found;
+            }
+        }
+
+        // Otherwise, try heartbreak
+        if (!wasm_name_equals(&heartbreak_name, module_name)) goto bad_import;
+
+        fori (j, 0, (i32) defs_count) {
+            if (wasm_name_equals_string(import_name, defs[j].name)) {
+                wasm_valtype_vec_t wasm_params;
+                wasm_valtype_vec_new_uninitialized(&wasm_params, defs[j].params.count);
+                fori (k, 0, defs[j].params.count) wasm_params.data[k] = wasm_valtype_new(defs[j].params.types[k]);
+
+                wasm_valtype_vec_t wasm_results;
+                wasm_valtype_vec_new_uninitialized(&wasm_results, defs[j].results.count);
+                fori (k, 0, defs[j].results.count) wasm_results.data[k] = wasm_valtype_new(defs[j].results.types[k]);
+
+                wasm_functype_t* wasm_functype = wasm_functype_new(&wasm_params, &wasm_results);
+
+                wasm_func_t* wasm_func = wasm_func_new(store, wasm_functype, defs[i].func);
+                import = wasm_func_as_extern(wasm_func);
+                goto import_found;
+            }
+        }
+
+        goto bad_import;
+
+    import_found:
+        // bh_printf("Found import %b.%b.\n", module_name->data, module_name->size, import_name->data, import_name->size);
+        imports.data[i] = import;
+        continue;
+
+    bad_import:
+        bh_printf("Couldn't find import %b.%b.\n", module_name->data, module_name->size, import_name->data, import_name->size);
+        return;
+    }
+
+    wasm_trap_t* traps = NULL;
+
+    instance = wasm_instance_new(store, module, &imports, &traps);
+    if (!instance) goto error_handling;
+
+    // Find the start function
+    i32 start_function_idx = -1;
+    wasm_exporttype_vec_t export_types;
+    wasm_module_exports(module, &export_types);
+    fori (i, 0, (i64) export_types.size) {
+        wasm_exporttype_t* export_type = export_types.data[i];
+        const wasm_name_t* export_name = wasm_exporttype_name(export_type);
+        
+        if (!strncmp(export_name->data, "_start", 6)) {
+            start_function_idx = i;
+            break;
+        }
+    }
+
+    wasm_extern_vec_t exports;
+    wasm_instance_exports(instance, &exports);
+
+    wasm_extern_t* start_extern = exports.data[start_function_idx];
+    wasm_func_t*   start_func   = wasm_extern_as_func(start_extern);
+
+    wasm_val_vec_t args;
+    wasm_val_vec_t results;
+    wasm_val_vec_new_uninitialized(&args, 0);
+
+    wasm_func_call(start_func, &args, &results);
+
+    goto cleanup;
+
+error_handling:
+    bh_printf("An error occured trying to run the WASM module...\n");
+
+cleanup:
+    if (instance)    wasm_instance_delete(instance);
+    if (module)      wasm_module_delete(module);
+    if (store)       wasm_store_delete(store);
+    if (engine)      wasm_engine_delete(engine);
+    return;
+}
+
+int main(int argc, char* argv[]) {
+    if (argc < 2) {
+        bh_printf("Expected a .wasm file to run.\n");
+        return 1;
+    }
+
+    bh_allocator heap_allocator = bh_heap_allocator();
+    bh_file_contents wasm_file = bh_file_read_contents_direct(heap_allocator, argv[1]);
+    run_wasm_file((bh_buffer) {
+        .data   = wasm_file.data,
+        .length = wasm_file.length,
+    });
+
+    return 0;
+}
\ No newline at end of file
diff --git a/tests/simp.onyx b/tests/simp.onyx
new file mode 100644 (file)
index 0000000..17f74a6
--- /dev/null
@@ -0,0 +1,13 @@
+#load "core/std"
+
+use package core
+
+heartbreak_init :: () -> i32 #foreign "heartbreak" "init" ---
+heartbreak_add  :: (x, y: i32) -> i32 #foreign "heartbreak" "add" ---
+
+main :: (_) => {
+    printf("Simp test is working!\n");
+
+    heartbreak_init() |> println();
+    heartbreak_add(3, 5) |> println();
+}
\ No newline at end of file