From: Brendan Hansen Date: Mon, 1 Nov 2021 00:27:38 +0000 (-0500) Subject: initial commit X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=e890c6515e254d838428b8f1015713cd42e06c09;p=heartbreak.git initial commit --- e890c6515e254d838428b8f1015713cd42e06c09 diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 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 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 index 0000000..a3a56f1 --- /dev/null +++ b/include/bh.h @@ -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 +#include +#include + +#ifdef _BH_LINUX + #include + #include + #include +#endif + +#include +#include +#include // TODO: Replace with needed functions +#include +#include +#include + +#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, ¤t_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 index 0000000..ac090e6 --- /dev/null +++ b/lib/linux_x86_64/include/wasm.h @@ -0,0 +1,723 @@ +// WebAssembly C API + +#ifndef WASM_H +#define WASM_H + +#include +#include +#include +#include +#include + +#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(¶ms); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &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(¶ms, 1, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &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(¶ms, 2, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &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(¶ms, 3, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &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(¶ms); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &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(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &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(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &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(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &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(¶ms); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &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(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &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(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &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(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &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 index 0000000..d700a4f --- /dev/null +++ b/lib/linux_x86_64/include/wasmer.h @@ -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 +#include +#include +#include +#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 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 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 index 0000000..12b79de --- /dev/null +++ b/src/heartbreak.c @@ -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 index 0000000..17f74a6 --- /dev/null +++ b/tests/simp.onyx @@ -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