From 63883a4370b98c2884ec8b9f9e7448144d7c852a Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Fri, 2 Aug 2024 08:37:39 +0200 Subject: [PATCH] Restructure build system --- .github/workflows/ci.yml | 4 +- .gitignore | 2 + bootstrap/build.c | 440 ++++++++++++ bootstrap/lib.h | 1468 ++++++++++++++++++++++++++++++++++++++ bootstrap/main.c | 1383 +---------------------------------- compile.sh | 28 - debug.sh | 31 - project.sh | 5 + run_tests.sh | 88 --- 9 files changed, 1920 insertions(+), 1529 deletions(-) create mode 100644 bootstrap/build.c create mode 100644 bootstrap/lib.h delete mode 100755 compile.sh delete mode 100755 debug.sh create mode 100755 project.sh delete mode 100755 run_tests.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04f3e1e..25bd0a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@v4 - name: Build and test run: | - ./run_tests.sh 1 + ./project.sh test all macos_build_and_test: runs-on: macos-latest timeout-minutes: 15 @@ -26,4 +26,4 @@ jobs: uses: actions/checkout@v4 - name: Build and test run: | - ./run_tests.sh 1 + ./project.sh test all diff --git a/.gitignore b/.gitignore index 90ba29a..99e1859 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ build/ nest/ *.data +project +project.dSYM/ diff --git a/bootstrap/build.c b/bootstrap/build.c new file mode 100644 index 0000000..37c39da --- /dev/null +++ b/bootstrap/build.c @@ -0,0 +1,440 @@ +#include "lib.h" + +#define build_dir "build" + +typedef enum OptimizationMode : u8 +{ + O0, + O1, + O2, + O3, + Os, + Oz, + OPTIMIZATION_COUNT, +} OptimizationMode; +declare_slice(OptimizationMode); + +typedef enum Compiler : u8 +{ + gcc, + clang, + COMPILER_COUNT, +} Compiler; +declare_slice(Compiler); + +global const Compiler default_compiler = clang; + +typedef enum Linkage: u8 +{ + LINKAGE_DYNAMIC, + LINKAGE_STATIC, + LINKAGE_COUNT, +} Linkage; +declare_slice(Linkage); + +struct CompileOptions +{ + char* out_path; + char* in_path; + OptimizationMode optimization_mode:3; + u8 debug_info:1; + u8 error_on_warning:1; + Compiler compiler:1; + Linkage linkage:1; +}; +typedef struct CompileOptions CompileOptions; +decl_vbp(char); + +fn u8 is_debug(OptimizationMode optimization_mode, u8 debug_info) +{ + return (optimization_mode == O0) & (debug_info != 0); +} + +fn void compile_c(const CompileOptions *const options, char** envp) +{ + VirtualBufferP(char) argument_stack = {}; + auto* args = &argument_stack; + char* compiler; + + switch (options->compiler) + { + case gcc: + compiler = "/usr/bin/gcc"; + break; + case clang: + compiler = "/usr/bin/clang"; + break; + case COMPILER_COUNT: + unreachable(); + } + + *vb_add(args, 1) = compiler; + *vb_add(args, 1) = options->in_path; + *vb_add(args, 1) = "-o"; + *vb_add(args, 1) = options->out_path; + + if (options->debug_info) + { + *vb_add(args, 1) = "-g"; + } + + switch (options->optimization_mode) + { + case O0: + *vb_add(args, 1) = "-O0"; + break; + case O1: + *vb_add(args, 1) = "-O1"; + break; + case O2: + *vb_add(args, 1) = "-O2"; + break; + case O3: + *vb_add(args, 1) = "-O3"; + break; + case Os: + *vb_add(args, 1) = "-Os"; + break; + case Oz: + *vb_add(args, 1) = "-Oz"; + break; + case OPTIMIZATION_COUNT: + unreachable(); + } + + if (options->error_on_warning) + { + *vb_add(args, 1) = "-Werror"; + } + + char* general_options[] = { + "-std=gnu2x", + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wno-nested-anon-types", + "-Wno-keyword-macro", + "-Wno-gnu-auto-type", + "-Wno-auto-decl-extensions", + "-Wno-gnu-empty-initializer", + "-Wno-fixed-enum-extension", + "-pedantic", + "-fno-exceptions", + "-fno-stack-protector", + "-ferror-limit=1", + }; + memcpy(vb_add(args, array_length(general_options)), general_options, sizeof(general_options)); + + if (!is_debug(options->optimization_mode, options->debug_info)) + { + *vb_add(args, 1) = "-DNDEBUG=1"; + } + + if (options->linkage == LINKAGE_STATIC) + { + char* static_options[] = { "-ffreestanding", "-nostdlib", "-static", "-DSTATIC", }; + memcpy(vb_add(args, array_length(static_options)), static_options, sizeof(static_options)); + } + + if (options->compiler == clang) + { + *vb_add(args, 1) = "-MJ"; + *vb_add(args, 1) = build_dir "/" "compile_commands.json"; + } + + *vb_add(args, 1) = 0; + + run_command((CStringSlice) { .pointer = args->pointer, .length = args->length }, envp); +} + +typedef enum ExecutionEngine +{ + EXECUTION_ENGINE_INTERPRETER, + EXECUTION_ENGINE_C, + EXECUTION_ENGINE_COUNT, +} ExecutionEngine; +declare_slice(ExecutionEngine); + +fn void compile_and_run(const CompileOptions* const options, char** envp, ExecutionEngine execution_engine, u8 debug, char* nest_source_path) +{ + compile_c(options, envp); + CStringSlice args = {}; + char* execution_engine_string; + switch (execution_engine) + { + case EXECUTION_ENGINE_C: + execution_engine_string = "c"; + break; + case EXECUTION_ENGINE_INTERPRETER: + execution_engine_string = "i"; + break; + case EXECUTION_ENGINE_COUNT: + unreachable(); + } + +#define common_compile_and_run_args \ + options->out_path, \ + nest_source_path, \ + execution_engine_string, \ + 0, + + if (debug) + { +#ifdef __linux__ + args = (CStringSlice) array_to_slice(((char*[]){ + "/home/david/source/gf/gf2", + "-ex", + "set auto-solib-add off", + "-ex", + "r", + "--args", + common_compile_and_run_args + })); +#elif defined(__APPLE__) + args = (CStringSlice) array_to_slice(((char*[]){ + "lldb", + "--", + common_compile_and_run_args + })); +#endif + } + else + { + args = (CStringSlice) array_to_slice(((char*[]){ + common_compile_and_run_args + })); + } + + run_command(args, envp); +} + +typedef enum Command : u8 +{ + COMMAND_DEBUG, + COMMAND_RUN_TESTS, + COMMAND_COUNT, +} Command; + +struct TestOptions +{ + Slice(Linkage) linkages; + Slice(OptimizationMode) optimization_modes; + Slice(String) test_paths; + Slice(ExecutionEngine) execution_engines; +}; +typedef struct TestOptions TestOptions; + +fn String linkage_name(Linkage linkage) +{ + switch (linkage) + { + case LINKAGE_STATIC: + return strlit("static"); + case LINKAGE_DYNAMIC: + return strlit("dynamic"); + case LINKAGE_COUNT: + unreachable(); + } +} + +fn String optimization_name(OptimizationMode optimization_mode) +{ + switch (optimization_mode) + { + case O0: + return strlit("O0"); + case O1: + return strlit("O1"); + case O2: + return strlit("O2"); + case O3: + return strlit("O3"); + case Os: + return strlit("Os"); + case Oz: + return strlit("Oz"); + case OPTIMIZATION_COUNT: + unreachable(); + } +} + +global const auto compiler_source_path = "bootstrap/main.c"; + +fn void run_tests(Arena* arena, TestOptions const * const test_options, char** envp) +{ + CompileOptions compile_options = {}; + compile_options.compiler = default_compiler; + compile_options.debug_info = 1; + compile_options.in_path = compiler_source_path; + + for (u32 linkage_i = 0; linkage_i < test_options->linkages.length; linkage_i += 1) + { + compile_options.linkage = test_options->linkages.pointer[linkage_i]; + auto linkage_string = linkage_name(compile_options.linkage); + + for (u32 optimization_i = 0; optimization_i < test_options->optimization_modes.length; optimization_i += 1) + { + compile_options.optimization_mode = test_options->optimization_modes.pointer[optimization_i]; + auto optimization_string = optimization_name(compile_options.optimization_mode); + + print("\n===========================\n"); + print("TESTS (linkage={s}, optimization={s})\n", linkage_string, optimization_string); + print("===========================\n\n"); + + String compiler_path = arena_join_string(arena, ((Slice(String)) array_to_slice(((String[]){ + strlit(build_dir "/"), + strlit("nest"), + optimization_string, + linkage_string, + })))); + compile_options.out_path = string_to_c(compiler_path); + + compile_c(&compile_options, envp); + + print("\n===========================\n"); + print("COMPILER BUILD [OK]\n"); + print("===========================\n\n"); + + for (u32 test_i = 0; test_i < test_options->test_paths.length; test_i += 1) + { + String test_path = test_options->test_paths.pointer[test_i]; + char* test_path_c = string_to_c(test_path); + + for (u32 engine_i = 0; engine_i < test_options->execution_engines.length; engine_i += 1) + { + ExecutionEngine execution_engine = test_options->execution_engines.pointer[engine_i]; + char* execution_engine_arg; + switch (execution_engine) + { + case EXECUTION_ENGINE_C: + execution_engine_arg = "c"; + break; + case EXECUTION_ENGINE_INTERPRETER: + execution_engine_arg = "i"; + break; + case EXECUTION_ENGINE_COUNT: + unreachable(); + } + + char* arguments[] = { + compile_options.out_path, + test_path_c, + execution_engine_arg, + 0, + }; + + run_command((CStringSlice) array_to_slice(arguments), envp); + } + } + } + } +} + +int main(int argc, char* argv[], char** envp) +{ + if (argc < 2) + { + print("Expected some arguments\n"); + return 1; + } + + ExecutionEngine preferred_execution_engine = EXECUTION_ENGINE_COUNT; + Command command = COMMAND_COUNT; + u8 test_every_config = 0; + + for (int i = 1; i < argc; i += 1) + { + char* c_argument = argv[i]; + auto argument = cstr(c_argument); + if (s_equal(argument, strlit("i"))) + { + preferred_execution_engine = EXECUTION_ENGINE_INTERPRETER; + } + else if (s_equal(argument, strlit("c"))) + { + preferred_execution_engine = EXECUTION_ENGINE_C; + } + else if (s_equal(argument, strlit("test"))) + { + command = COMMAND_RUN_TESTS; + } + else if (s_equal(argument, strlit("debug"))) + { + command = COMMAND_DEBUG; + } + else if (s_equal(argument, strlit("all"))) + { + test_every_config = 1; + } + } + + if (command == COMMAND_COUNT) + { + print("Expected a command\n"); + return 1; + } + + if ((command == COMMAND_DEBUG) | ((command == COMMAND_RUN_TESTS) & (test_every_config == 0))) + { + preferred_execution_engine = EXECUTION_ENGINE_INTERPRETER; + } + + switch (command) + { + case COMMAND_DEBUG: + compile_and_run(&(CompileOptions) { + .in_path = compiler_source_path, + .out_path = build_dir "/" "nest", + .compiler = default_compiler, + .debug_info = 1, + .error_on_warning = 0, + .optimization_mode = O0, + .linkage = LINKAGE_STATIC, + }, envp, EXECUTION_ENGINE_INTERPRETER, 1, "tests/first.nat"); + break; + case COMMAND_RUN_TESTS: + { + Arena* arena = arena_init_default(KB(64)); + Linkage all_linkages[] = { LINKAGE_DYNAMIC, LINKAGE_STATIC }; + static_assert(array_length(all_linkages) == LINKAGE_COUNT); + OptimizationMode all_optimization_modes[] = { O0, O1, O2, O3, Os, Oz }; + static_assert(array_length(all_optimization_modes) == OPTIMIZATION_COUNT); + String all_test_paths[] = { + strlit("tests/first.nat"), + }; + ExecutionEngine all_execution_engines[] = { EXECUTION_ENGINE_INTERPRETER, EXECUTION_ENGINE_C }; + static_assert(array_length(all_execution_engines) == EXECUTION_ENGINE_COUNT); + + Slice(String) test_selection = (Slice(String)) array_to_slice(all_test_paths); + Slice(Linkage) linkage_selection; + Slice(OptimizationMode) optimization_selection; + Slice(ExecutionEngine) execution_engine_selection; + + if (test_every_config) + { +#ifdef __linux__ + linkage_selection = (Slice(Linkage)) array_to_slice(all_linkages); +#else + linkage_selection = (Slice(Linkage)) { .pointer = &all_linkages[0], .length = 1 }; +#endif + optimization_selection = (Slice(OptimizationMode)) array_to_slice(all_optimization_modes); + execution_engine_selection = (Slice(ExecutionEngine)) array_to_slice(all_execution_engines); + } + else + { + linkage_selection = (Slice(Linkage)) { .pointer = &all_linkages[0], .length = 1 }; + optimization_selection = (Slice(OptimizationMode)) { .pointer = &all_optimization_modes[0], .length = 1 }; + execution_engine_selection = (Slice(ExecutionEngine)) { .pointer = &preferred_execution_engine, .length = 1 }; + } + + run_tests(arena, &(TestOptions) { + .linkages = linkage_selection, + .optimization_modes = optimization_selection, + .test_paths = test_selection, + .execution_engines = execution_engine_selection, + }, envp); + } break; + case COMMAND_COUNT: + unreachable(); + } +} diff --git a/bootstrap/lib.h b/bootstrap/lib.h new file mode 100644 index 0000000..4afa343 --- /dev/null +++ b/bootstrap/lib.h @@ -0,0 +1,1468 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef NDEBUG +#define _DEBUG 0 +#else +#define _DEBUG 1 +#endif + +#ifdef STATIC +#define LINK_LIBC 0 +#else +#define LINK_LIBC 1 +#endif + +#if LINK_LIBC +#include +#include +#include +#endif + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef float f32; +typedef double f64; + +typedef u64 Hash; + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define fn static +#define method __attribute__((visibility("internal"))) +#define global static +#define forceinline __attribute__((always_inline)) +#define expect(x, b) __builtin_expect(x, b) +#define breakpoint() __builtin_debugtrap() +#define fail() trap() +#define trap() bad_exit("Trap reached", __FILE__, __LINE__) +#define array_length(arr) sizeof(arr) / sizeof((arr)[0]) +#define KB(n) ((n) * 1024) +#define MB(n) ((n) * 1024 * 1024) +#define GB(n) ((u64)(n) * 1024 * 1024 * 1024) +#define TB(n) ((u64)(n) * 1024 * 1024 * 1024 * 1024) +#define unused(x) (void)(x) +#define may_be_unused __attribute__((unused)) + +#if _DEBUG +#define assert(x) if (__builtin_expect(!(x), 0)) { bad_exit("Assert failed", __FILE__, __LINE__); } +#else +#define assert(x) __builtin_expect(!(x), 0) +#endif + +#ifdef unreachable +#undef unreachable +#endif + +#if _DEBUG +#define unreachable() bad_exit("Unreachable triggered", __FILE__, __LINE__) +#else +#define unreachable() __builtin_unreachable() +#endif + +#define static_assert(x) _Static_assert((x), "Static assert failed!") +#define alignof(x) _Alignof(x) +#define auto __auto_type + +#define bad_exit(message, file, line) do { print(message " at {cstr}:{u32}\n", file, line); __builtin_trap(); } while(0) +#define todo() do { print("TODO at {cstr}:{u32}\n", __FILE__, __LINE__); __builtin_trap(); } while(0) + +may_be_unused fn void print(const char* format, ...); + +#if __APPLE__ + const global u64 page_size = KB(16); +#else + const global u64 page_size = KB(4); +#endif + + +const may_be_unused global u8 brace_open = '{'; +const may_be_unused global u8 brace_close = '}'; + +const may_be_unused global u8 parenthesis_open = '('; +const may_be_unused global u8 parenthesis_close = ')'; + +const may_be_unused global u8 bracket_open = '['; +const may_be_unused global u8 bracket_close = ']'; + +may_be_unused fn u8 log2_alignment(u64 alignment) +{ + assert(alignment != 0); + assert((alignment & (alignment - 1)) == 0); + u64 left = (sizeof(alignment) * 8) - 1; + u64 right = __builtin_clzl(alignment); + u8 result = left - right; + return result; +} + +// Lehmer's generator +// https://lemire.me/blog/2019/03/19/the-fastest-conventional-random-number-generator-that-can-pass-big-crush/ +may_be_unused global __uint128_t rn_state; +may_be_unused fn u64 generate_random_number() +{ + rn_state *= 0xda942042e4dd58b5; + return rn_state >> 64; +} + +may_be_unused fn u64 round_up_to_next_power_of_2(u64 n) +{ + n -= 1; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n |= n >> 32; + n += 1; + return n; +} + +#if LINK_LIBC == 0 +void* memcpy(void* __restrict dst, void* __restrict src, u64 size) +{ + auto* destination = (u8*)dst; + auto* source = (u8*)src; + + for (u64 i = 0; i < size; i += 1) + { + destination[i] = source[i]; + } + + return dst; +} + +void* memset(void* dst, u8 n, u64 size) +{ + auto* destination = (u8*)dst; + for (u64 i = 0; i < size; i += 1) + { + destination[i] = n; + } + + return dst; +} + +fn int memcmp(const void* left, const void* right, u64 n) +{ + const u8 *l=(const u8*)left, *r=(const u8*)right; + for (; n && *l == *r; n--, l++, r++); + return n ? *l - *r : 0; +} + +fn u64 strlen (const char* c_string) +{ + auto* it = c_string; + while (*it) + { + it += 1; + } + return it - c_string; +} +#endif +#define slice_from_pointer_range(T, start, end) (Slice(T)) { .pointer = start, .length = (u64)(end - start), } + +#define strlit(s) (String){ .pointer = (u8*)(s), .length = sizeof(s) - 1, } +#define ch_to_str(ch) (String){ .pointer = &ch, .length = 1 } +#define array_to_slice(arr) { .pointer = (arr), .length = array_length(arr) } +#define pointer_to_bytes(p) (String) { .pointer = (u8*)(p), .length = sizeof(*p) } +#define struct_to_bytes(s) pointer_to_bytes(&(s)) +#define string_to_c(s) ((char*)((s).pointer)) +#define cstr(s) ((String) { .pointer = (u8*)(s), .length = strlen(s), } ) + +#define case_to_name(prefix, e) case prefix ## e: return strlit(#e) + +#define Slice(T) Slice_ ## T +#define SliceP(T) SliceP_ ## T +#define declare_slice_ex(T, StructName) struct StructName \ +{\ + T* pointer;\ + u64 length;\ +};\ +typedef struct StructName StructName + +#define declare_slice(T) declare_slice_ex(T, Slice(T)) +#define declare_slice_p(T) declare_slice_ex(T*, SliceP(T)) + +#define s_get(s, i) (s).pointer[i] +#define s_get_pointer(s, i) &((s).pointer[i]) +#define s_get_slice(T, s, start, end) (Slice(T)){ .pointer = ((s).pointer) + (start), .length = (end) - (start) } +#define s_equal(a, b) ((a).length == (b).length && memcmp((a).pointer, (b).pointer, sizeof(*((a).pointer))) == 0) + +declare_slice(u8); +typedef Slice(u8) String; +// Array of strings +declare_slice(String); +declare_slice_p(char); +typedef SliceP_char CStringSlice; + +// fn s32 string_first_ch(String string, u8 ch) +// { +// s32 result = -1; +// for (u64 i = 0; i < string.length; i += 1) +// { +// if (string.pointer[i] == ch) +// { +// result = i; +// break; +// } +// } +// +// return result; +// } + +fn s32 string_last_ch(String string, u8 ch) +{ + s32 result = -1; + u64 i = string.length; + while (i > 0) + { + i -= 1; + if (string.pointer[i] == ch) + { + result = i; + break; + } + } + + return result; +} + +// fn String string_dir(String string) +// { +// String result = {}; +// auto index = string_last_ch(string, '/'); +// if (index != -1) +// { +// result = s_get_slice(u8, string, 0, index); +// } +// +// return result; +// } + +may_be_unused fn String string_base(String string) +{ + String result = {}; + auto index = string_last_ch(string, '/'); + if (index != -1) + { + result = s_get_slice(u8, string, index + 1, string.length); + } + + return result; +} + +may_be_unused fn String string_no_extension(String string) +{ + String result = {}; + auto index = string_last_ch(string, '.'); + if (index != -1) + { + result = s_get_slice(u8, string, 0, index); + } + + return result; +} + +fn u64 parse_decimal(String string) +{ + u64 value = 0; + for (u64 i = 0; i < string.length; i += 1) + { + u8 ch = s_get(string, i); + assert(((ch >= '0') & (ch <= '9'))); + value = (value * 10) + (ch - '0'); + } + + return value; +} + +fn u64 safe_flag(u64 value, u64 flag) +{ + u64 result = value & ((u64)0 - flag); + return result; +} + +may_be_unused fn u8 get_next_ch_safe(String string, u64 index) +{ + u64 next_index = index + 1; + u64 is_in_range = next_index < string.length; + u64 safe_index = safe_flag(next_index, is_in_range); + u8 unsafe_result = string.pointer[safe_index]; + u64 safe_result = safe_flag(unsafe_result, is_in_range); + assert(safe_result < 256); + return (u8)safe_result; +} + +may_be_unused fn u32 is_space(u8 ch, u8 next_ch) +{ + u32 is_comment = (ch == '/') & (next_ch == '/'); + u32 is_whitespace = ch == ' '; + u32 is_vertical_tab = ch == 0x0b; + u32 is_horizontal_tab = ch == '\t'; + u32 is_line_feed = ch == '\n'; + u32 is_carry_return = ch == '\r'; + u32 result = (((is_vertical_tab | is_horizontal_tab) | (is_line_feed | is_carry_return)) | (is_comment | is_whitespace)); + return result; +} + +fn u64 is_lower(u8 ch) +{ + return (ch >= 'a') & (ch <= 'z'); +} + +fn u64 is_upper(u8 ch) +{ + return (ch >= 'A') & (ch <= 'Z'); +} + +fn u64 is_alphabetic(u8 ch) +{ + return is_lower(ch) | is_upper(ch); +} + +fn u64 is_decimal_digit(u8 ch) +{ + return (ch >= '0') & (ch <= '9'); +} + +// fn u64 is_hex_digit(u8 ch) +// { +// return (is_decimal_digit(ch) | ((ch == 'a' | ch == 'A') | (ch == 'b' | ch == 'B'))) | (((ch == 'c' | ch == 'C') | (ch == 'd' | ch == 'D')) | ((ch == 'e' | ch == 'E') | (ch == 'f' | ch == 'F'))); +// } + + +fn u64 is_identifier_start(u8 ch) +{ + u64 alphabetic = is_alphabetic(ch); + u64 is_underscore = ch == '_'; + return alphabetic | is_underscore; +} + +may_be_unused fn u64 is_identifier_ch(u8 ch) +{ + u64 identifier_start = is_identifier_start(ch); + u64 decimal = is_decimal_digit(ch); + return identifier_start | decimal; +} + +global const Hash fnv_offset = 14695981039346656037ull; +global const u64 fnv_prime = 1099511628211ull; + +fn Hash hash_byte(Hash source, u8 ch) +{ + source ^= ch; + source *= fnv_prime; + return source; +} + +may_be_unused fn Hash hash_bytes(String bytes) +{ + u64 result = fnv_offset; + for (u64 i = 0; i < bytes.length; i += 1) + { + result = hash_byte(result, bytes.pointer[i]); + } + + return result; +} + +#if LINK_LIBC == 0 +#ifdef __linux__ +may_be_unused fn forceinline long syscall0(long n) +{ + unsigned long ret; + __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n) : "rcx", "r11", "memory"); + return ret; +} + +may_be_unused fn forceinline long syscall1(long n, long a1) +{ + unsigned long ret; + __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory"); + return ret; +} + +may_be_unused fn forceinline long syscall2(long n, long a1, long a2) +{ + unsigned long ret; + __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2) + : "rcx", "r11", "memory"); + return ret; +} + +may_be_unused fn forceinline long syscall3(long n, long a1, long a2, long a3) +{ + unsigned long ret; + __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), + "d"(a3) : "rcx", "r11", "memory"); + return ret; +} + +may_be_unused fn forceinline long syscall4(long n, long a1, long a2, long a3, long a4) +{ + unsigned long ret; + register long r10 __asm__("r10") = a4; + __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), + "d"(a3), "r"(r10): "rcx", "r11", "memory"); + return ret; +} + +may_be_unused fn forceinline long syscall5(long n, long a1, long a2, long a3, long a4, long a5) +{ + unsigned long ret; + register long r10 __asm__("r10") = a4; + register long r8 __asm__("r8") = a5; + __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), + "d"(a3), "r"(r10), "r"(r8) : "rcx", "r11", "memory"); + return ret; +} + +may_be_unused fn forceinline long syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) +{ + unsigned long ret; + register long r10 __asm__("r10") = a4; + register long r8 __asm__("r8") = a5; + register long r9 __asm__("r9") = a6; + __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), + "d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory"); + return ret; +} + +enum SyscallX86_64 : u64 { + syscall_x86_64_read = 0, + syscall_x86_64_write = 1, + syscall_x86_64_open = 2, + syscall_x86_64_close = 3, + syscall_x86_64_stat = 4, + syscall_x86_64_fstat = 5, + syscall_x86_64_lstat = 6, + syscall_x86_64_poll = 7, + syscall_x86_64_lseek = 8, + syscall_x86_64_mmap = 9, + syscall_x86_64_mprotect = 10, + syscall_x86_64_munmap = 11, + syscall_x86_64_brk = 12, + syscall_x86_64_rt_sigaction = 13, + syscall_x86_64_rt_sigprocmask = 14, + syscall_x86_64_rt_sigreturn = 15, + syscall_x86_64_ioctl = 16, + syscall_x86_64_pread64 = 17, + syscall_x86_64_pwrite64 = 18, + syscall_x86_64_readv = 19, + syscall_x86_64_writev = 20, + syscall_x86_64_access = 21, + syscall_x86_64_pipe = 22, + syscall_x86_64_select = 23, + syscall_x86_64_sched_yield = 24, + syscall_x86_64_mremap = 25, + syscall_x86_64_msync = 26, + syscall_x86_64_mincore = 27, + syscall_x86_64_madvise = 28, + syscall_x86_64_shmget = 29, + syscall_x86_64_shmat = 30, + syscall_x86_64_shmctl = 31, + syscall_x86_64_dup = 32, + syscall_x86_64_dup2 = 33, + syscall_x86_64_pause = 34, + syscall_x86_64_nanosleep = 35, + syscall_x86_64_getitimer = 36, + syscall_x86_64_alarm = 37, + syscall_x86_64_setitimer = 38, + syscall_x86_64_getpid = 39, + syscall_x86_64_sendfile = 40, + syscall_x86_64_socket = 41, + syscall_x86_64_connect = 42, + syscall_x86_64_accept = 43, + syscall_x86_64_sendto = 44, + syscall_x86_64_recvfrom = 45, + syscall_x86_64_sendmsg = 46, + syscall_x86_64_recvmsg = 47, + syscall_x86_64_shutdown = 48, + syscall_x86_64_bind = 49, + syscall_x86_64_listen = 50, + syscall_x86_64_getsockname = 51, + syscall_x86_64_getpeername = 52, + syscall_x86_64_socketpair = 53, + syscall_x86_64_setsockopt = 54, + syscall_x86_64_getsockopt = 55, + syscall_x86_64_clone = 56, + syscall_x86_64_fork = 57, + syscall_x86_64_vfork = 58, + syscall_x86_64_execve = 59, + syscall_x86_64_exit = 60, + syscall_x86_64_wait4 = 61, + syscall_x86_64_kill = 62, + syscall_x86_64_uname = 63, + syscall_x86_64_semget = 64, + syscall_x86_64_semop = 65, + syscall_x86_64_semctl = 66, + syscall_x86_64_shmdt = 67, + syscall_x86_64_msgget = 68, + syscall_x86_64_msgsnd = 69, + syscall_x86_64_msgrcv = 70, + syscall_x86_64_msgctl = 71, + syscall_x86_64_fcntl = 72, + syscall_x86_64_flock = 73, + syscall_x86_64_fsync = 74, + syscall_x86_64_fdatasync = 75, + syscall_x86_64_truncate = 76, + syscall_x86_64_ftruncate = 77, + syscall_x86_64_getdents = 78, + syscall_x86_64_getcwd = 79, + syscall_x86_64_chdir = 80, + syscall_x86_64_fchdir = 81, + syscall_x86_64_rename = 82, + syscall_x86_64_mkdir = 83, + syscall_x86_64_rmdir = 84, + syscall_x86_64_creat = 85, + syscall_x86_64_link = 86, + syscall_x86_64_unlink = 87, + syscall_x86_64_symlink = 88, + syscall_x86_64_readlink = 89, + syscall_x86_64_chmod = 90, + syscall_x86_64_fchmod = 91, + syscall_x86_64_chown = 92, + syscall_x86_64_fchown = 93, + syscall_x86_64_lchown = 94, + syscall_x86_64_umask = 95, + syscall_x86_64_gettimeofday = 96, + syscall_x86_64_getrlimit = 97, + syscall_x86_64_getrusage = 98, + syscall_x86_64_sysinfo = 99, + syscall_x86_64_times = 100, + syscall_x86_64_ptrace = 101, + syscall_x86_64_getuid = 102, + syscall_x86_64_syslog = 103, + syscall_x86_64_getgid = 104, + syscall_x86_64_setuid = 105, + syscall_x86_64_setgid = 106, + syscall_x86_64_geteuid = 107, + syscall_x86_64_getegid = 108, + syscall_x86_64_setpgid = 109, + syscall_x86_64_getppid = 110, + syscall_x86_64_getpgrp = 111, + syscall_x86_64_setsid = 112, + syscall_x86_64_setreuid = 113, + syscall_x86_64_setregid = 114, + syscall_x86_64_getgroups = 115, + syscall_x86_64_setgroups = 116, + syscall_x86_64_setresuid = 117, + syscall_x86_64_getresuid = 118, + syscall_x86_64_setresgid = 119, + syscall_x86_64_getresgid = 120, + syscall_x86_64_getpgid = 121, + syscall_x86_64_setfsuid = 122, + syscall_x86_64_setfsgid = 123, + syscall_x86_64_getsid = 124, + syscall_x86_64_capget = 125, + syscall_x86_64_capset = 126, + syscall_x86_64_rt_sigpending = 127, + syscall_x86_64_rt_sigtimedwait = 128, + syscall_x86_64_rt_sigqueueinfo = 129, + syscall_x86_64_rt_sigsuspend = 130, + syscall_x86_64_sigaltstack = 131, + syscall_x86_64_utime = 132, + syscall_x86_64_mknod = 133, + syscall_x86_64_uselib = 134, + syscall_x86_64_personality = 135, + syscall_x86_64_ustat = 136, + syscall_x86_64_statfs = 137, + syscall_x86_64_fstatfs = 138, + syscall_x86_64_sysfs = 139, + syscall_x86_64_getpriority = 140, + syscall_x86_64_setpriority = 141, + syscall_x86_64_sched_setparam = 142, + syscall_x86_64_sched_getparam = 143, + syscall_x86_64_sched_setscheduler = 144, + syscall_x86_64_sched_getscheduler = 145, + syscall_x86_64_sched_get_priority_max = 146, + syscall_x86_64_sched_get_priority_min = 147, + syscall_x86_64_sched_rr_get_interval = 148, + syscall_x86_64_mlock = 149, + syscall_x86_64_munlock = 150, + syscall_x86_64_mlockall = 151, + syscall_x86_64_munlockall = 152, + syscall_x86_64_vhangup = 153, + syscall_x86_64_modify_ldt = 154, + syscall_x86_64_pivot_root = 155, + syscall_x86_64__sysctl = 156, + syscall_x86_64_prctl = 157, + syscall_x86_64_arch_prctl = 158, + syscall_x86_64_adjtimex = 159, + syscall_x86_64_setrlimit = 160, + syscall_x86_64_chroot = 161, + syscall_x86_64_sync = 162, + syscall_x86_64_acct = 163, + syscall_x86_64_settimeofday = 164, + syscall_x86_64_mount = 165, + syscall_x86_64_umount2 = 166, + syscall_x86_64_swapon = 167, + syscall_x86_64_swapoff = 168, + syscall_x86_64_reboot = 169, + syscall_x86_64_sethostname = 170, + syscall_x86_64_setdomainname = 171, + syscall_x86_64_iopl = 172, + syscall_x86_64_ioperm = 173, + syscall_x86_64_create_module = 174, + syscall_x86_64_init_module = 175, + syscall_x86_64_delete_module = 176, + syscall_x86_64_get_kernel_syms = 177, + syscall_x86_64_query_module = 178, + syscall_x86_64_quotactl = 179, + syscall_x86_64_nfsservctl = 180, + syscall_x86_64_getpmsg = 181, + syscall_x86_64_putpmsg = 182, + syscall_x86_64_afs_syscall = 183, + syscall_x86_64_tuxcall = 184, + syscall_x86_64_security = 185, + syscall_x86_64_gettid = 186, + syscall_x86_64_readahead = 187, + syscall_x86_64_setxattr = 188, + syscall_x86_64_lsetxattr = 189, + syscall_x86_64_fsetxattr = 190, + syscall_x86_64_getxattr = 191, + syscall_x86_64_lgetxattr = 192, + syscall_x86_64_fgetxattr = 193, + syscall_x86_64_listxattr = 194, + syscall_x86_64_llistxattr = 195, + syscall_x86_64_flistxattr = 196, + syscall_x86_64_removexattr = 197, + syscall_x86_64_lremovexattr = 198, + syscall_x86_64_fremovexattr = 199, + syscall_x86_64_tkill = 200, + syscall_x86_64_time = 201, + syscall_x86_64_futex = 202, + syscall_x86_64_sched_setaffinity = 203, + syscall_x86_64_sched_getaffinity = 204, + syscall_x86_64_set_thread_area = 205, + syscall_x86_64_io_setup = 206, + syscall_x86_64_io_destroy = 207, + syscall_x86_64_io_getevents = 208, + syscall_x86_64_io_submit = 209, + syscall_x86_64_io_cancel = 210, + syscall_x86_64_get_thread_area = 211, + syscall_x86_64_lookup_dcookie = 212, + syscall_x86_64_epoll_create = 213, + syscall_x86_64_epoll_ctl_old = 214, + syscall_x86_64_epoll_wait_old = 215, + syscall_x86_64_remap_file_pages = 216, + syscall_x86_64_getdents64 = 217, + syscall_x86_64_set_tid_address = 218, + syscall_x86_64_restart_syscall = 219, + syscall_x86_64_semtimedop = 220, + syscall_x86_64_fadvise64 = 221, + syscall_x86_64_timer_create = 222, + syscall_x86_64_timer_settime = 223, + syscall_x86_64_timer_gettime = 224, + syscall_x86_64_timer_getoverrun = 225, + syscall_x86_64_timer_delete = 226, + syscall_x86_64_clock_settime = 227, + syscall_x86_64_clock_gettime = 228, + syscall_x86_64_clock_getres = 229, + syscall_x86_64_clock_nanosleep = 230, + syscall_x86_64_exit_group = 231, + syscall_x86_64_epoll_wait = 232, + syscall_x86_64_epoll_ctl = 233, + syscall_x86_64_tgkill = 234, + syscall_x86_64_utimes = 235, + syscall_x86_64_vserver = 236, + syscall_x86_64_mbind = 237, + syscall_x86_64_set_mempolicy = 238, + syscall_x86_64_get_mempolicy = 239, + syscall_x86_64_mq_open = 240, + syscall_x86_64_mq_unlink = 241, + syscall_x86_64_mq_timedsend = 242, + syscall_x86_64_mq_timedreceive = 243, + syscall_x86_64_mq_notify = 244, + syscall_x86_64_mq_getsetattr = 245, + syscall_x86_64_kexec_load = 246, + syscall_x86_64_waitid = 247, + syscall_x86_64_add_key = 248, + syscall_x86_64_request_key = 249, + syscall_x86_64_keyctl = 250, + syscall_x86_64_ioprio_set = 251, + syscall_x86_64_ioprio_get = 252, + syscall_x86_64_inotify_init = 253, + syscall_x86_64_inotify_add_watch = 254, + syscall_x86_64_inotify_rm_watch = 255, + syscall_x86_64_migrate_pages = 256, + syscall_x86_64_openat = 257, + syscall_x86_64_mkdirat = 258, + syscall_x86_64_mknodat = 259, + syscall_x86_64_fchownat = 260, + syscall_x86_64_futimesat = 261, + syscall_x86_64_fstatat64 = 262, + syscall_x86_64_unlinkat = 263, + syscall_x86_64_renameat = 264, + syscall_x86_64_linkat = 265, + syscall_x86_64_symlinkat = 266, + syscall_x86_64_readlinkat = 267, + syscall_x86_64_fchmodat = 268, + syscall_x86_64_faccessat = 269, + syscall_x86_64_pselect6 = 270, + syscall_x86_64_ppoll = 271, + syscall_x86_64_unshare = 272, + syscall_x86_64_set_robust_list = 273, + syscall_x86_64_get_robust_list = 274, + syscall_x86_64_splice = 275, + syscall_x86_64_tee = 276, + syscall_x86_64_sync_file_range = 277, + syscall_x86_64_vmsplice = 278, + syscall_x86_64_move_pages = 279, + syscall_x86_64_utimensat = 280, + syscall_x86_64_epoll_pwait = 281, + syscall_x86_64_signalfd = 282, + syscall_x86_64_timerfd_create = 283, + syscall_x86_64_eventfd = 284, + syscall_x86_64_fallocate = 285, + syscall_x86_64_timerfd_settime = 286, + syscall_x86_64_timerfd_gettime = 287, + syscall_x86_64_accept4 = 288, + syscall_x86_64_signalfd4 = 289, + syscall_x86_64_eventfd2 = 290, + syscall_x86_64_epoll_create1 = 291, + syscall_x86_64_dup3 = 292, + syscall_x86_64_pipe2 = 293, + syscall_x86_64_inotify_init1 = 294, + syscall_x86_64_preadv = 295, + syscall_x86_64_pwritev = 296, + syscall_x86_64_rt_tgsigqueueinfo = 297, + syscall_x86_64_perf_event_open = 298, + syscall_x86_64_recvmmsg = 299, + syscall_x86_64_fanotify_init = 300, + syscall_x86_64_fanotify_mark = 301, + syscall_x86_64_prlimit64 = 302, + syscall_x86_64_name_to_handle_at = 303, + syscall_x86_64_open_by_handle_at = 304, + syscall_x86_64_clock_adjtime = 305, + syscall_x86_64_syncfs = 306, + syscall_x86_64_sendmmsg = 307, + syscall_x86_64_setns = 308, + syscall_x86_64_getcpu = 309, + syscall_x86_64_process_vm_readv = 310, + syscall_x86_64_process_vm_writev = 311, + syscall_x86_64_kcmp = 312, + syscall_x86_64_finit_module = 313, + syscall_x86_64_sched_setattr = 314, + syscall_x86_64_sched_getattr = 315, + syscall_x86_64_renameat2 = 316, + syscall_x86_64_seccomp = 317, + syscall_x86_64_getrandom = 318, + syscall_x86_64_memfd_create = 319, + syscall_x86_64_kexec_file_load = 320, + syscall_x86_64_bpf = 321, + syscall_x86_64_execveat = 322, + syscall_x86_64_userfaultfd = 323, + syscall_x86_64_membarrier = 324, + syscall_x86_64_mlock2 = 325, + syscall_x86_64_copy_file_range = 326, + syscall_x86_64_preadv2 = 327, + syscall_x86_64_pwritev2 = 328, + syscall_x86_64_pkey_mprotect = 329, + syscall_x86_64_pkey_alloc = 330, + syscall_x86_64_pkey_free = 331, + syscall_x86_64_statx = 332, + syscall_x86_64_io_pgetevents = 333, + syscall_x86_64_rseq = 334, + syscall_x86_64_pidfd_send_signal = 424, + syscall_x86_64_io_uring_setup = 425, + syscall_x86_64_io_uring_enter = 426, + syscall_x86_64_io_uring_register = 427, + syscall_x86_64_open_tree = 428, + syscall_x86_64_move_mount = 429, + syscall_x86_64_fsopen = 430, + syscall_x86_64_fsconfig = 431, + syscall_x86_64_fsmount = 432, + syscall_x86_64_fspick = 433, + syscall_x86_64_pidfd_open = 434, + syscall_x86_64_clone3 = 435, + syscall_x86_64_close_range = 436, + syscall_x86_64_openat2 = 437, + syscall_x86_64_pidfd_getfd = 438, + syscall_x86_64_faccessat2 = 439, + syscall_x86_64_process_madvise = 440, + syscall_x86_64_epoll_pwait2 = 441, + syscall_x86_64_mount_setattr = 442, + syscall_x86_64_quotactl_fd = 443, + syscall_x86_64_landlock_create_ruleset = 444, + syscall_x86_64_landlock_add_rule = 445, + syscall_x86_64_landlock_restrict_self = 446, + syscall_x86_64_memfd_secret = 447, + syscall_x86_64_process_mrelease = 448, + syscall_x86_64_futex_waitv = 449, + syscall_x86_64_set_mempolicy_home_node = 450, + syscall_x86_64_cachestat = 451, + syscall_x86_64_fchmodat2 = 452, + syscall_x86_64_map_shadow_stack = 453, + syscall_x86_64_futex_wake = 454, + syscall_x86_64_futex_wait = 455, + syscall_x86_64_futex_requeue = 456, +}; +#endif +#endif + +may_be_unused fn void* syscall_mmap(void* address, size_t length, int protection_flags, int map_flags, int fd, signed long offset) +{ +#if LINK_LIBC + return mmap(address, length, protection_flags, map_flags, fd, offset); +#else +#ifdef __linux__ + return (void*) syscall6(syscall_x86_64_mmap, (unsigned long)address, length, protection_flags, map_flags, fd, offset); +#else +#error "Unsupported operating system for static linking" +#endif +#endif +} + +may_be_unused fn int syscall_mprotect(void *address, size_t length, int protection_flags) +{ +#if LINK_LIBC + return mprotect(address, length, protection_flags); +#else +#ifdef __linux__ + return syscall3(syscall_x86_64_mprotect, (unsigned long)address, length, protection_flags); +#else + return mprotect(address, length, protection_flags); +#endif +#endif +} + +may_be_unused fn int syscall_open(const char *file_path, int flags, int mode) +{ +#if LINK_LIBC + return open(file_path, flags, mode); +#else +#ifdef __linux__ + return syscall3(syscall_x86_64_open, (unsigned long)file_path, flags, mode); +#else + return open(file_path, flags, mode); +#endif +#endif +} + +may_be_unused fn int syscall_close(int fd) +{ +#if LINK_LIBC + return close(fd); +#else +#ifdef __linux__ + return syscall1(syscall_x86_64_close, fd); +#else + return close(fd); +#endif +#endif +} + +fn int syscall_fstat(int fd, struct stat *buffer) +{ +#if LINK_LIBC + return fstat(fd, buffer); +#else +#ifdef __linux__ + return syscall2(syscall_x86_64_fstat, fd, (unsigned long)buffer); +#else + return fstat(fd, buffer); +#endif +#endif +} + +may_be_unused fn u64 file_get_size(int fd) +{ + struct stat stat_buffer; + int stat_result = syscall_fstat(fd, &stat_buffer); + assert(stat_result == 0); + u64 size = stat_buffer.st_size; + return size; +} + +may_be_unused fn ssize_t syscall_read(int fd, void* buffer, size_t bytes) +{ +#if LINK_LIBC + return read(fd, buffer, bytes); +#else +#ifdef __linux__ + return syscall3(syscall_x86_64_read, fd, (unsigned long)buffer, bytes); +#else + return read(fd, buffer, bytes); +#endif +#endif +} + +may_be_unused fn ssize_t syscall_write(int fd, const void *buffer, size_t bytes) +{ +#if LINK_LIBC + return write(fd, buffer, bytes); +#else +#ifdef __linux__ + return syscall3(syscall_x86_64_write, fd, (unsigned long)buffer, bytes); +#else + return write(fd, buffer, bytes); +#endif +#endif +} + +may_be_unused fn int syscall_mkdir(const char* path, u32 mode) +{ +#if LINK_LIBC + return mkdir(path, mode); +#else + return syscall2(syscall_x86_64_mkdir, (unsigned long)path, mode); +#endif +} + +may_be_unused fn int syscall_rmdir(const char* path) +{ +#if LINK_LIBC + return rmdir(path); +#else + return syscall1(syscall_x86_64_rmdir, (unsigned long)path); +#endif +} + +may_be_unused fn int syscall_unlink(const char* path) +{ +#if LINK_LIBC + return unlink(path); +#else + return syscall1(syscall_x86_64_unlink, (unsigned long)path); +#endif +} + +may_be_unused fn pid_t syscall_fork() +{ +#if LINK_LIBC + return fork(); +#else + return syscall0(syscall_x86_64_fork); +#endif + +} + +may_be_unused fn signed long syscall_execve(const char* path, char *const argv[], char *const envp[]) +{ +#if LINK_LIBC + return execve(path, argv, envp); +#else + return syscall3(syscall_x86_64_execve, (unsigned long)path, (unsigned long)argv, (unsigned long)envp); +#endif +} +may_be_unused fn pid_t syscall_waitpid(pid_t pid, int* status, int options) +{ +#if LINK_LIBC + return waitpid(pid, status, options); +#else + return syscall4(syscall_x86_64_wait4, pid, (unsigned long)status, options, 0); +#endif +} + +may_be_unused [[noreturn]] [[gnu::cold]] fn void syscall_exit(int status) +{ +#if LINK_LIBC + _exit(status); +#else +#ifdef __linux__ + (void)syscall1(231, status); + trap(); +#else + _exit(status); +#endif +#endif +} + +fn u8* reserve(u64 size) +{ + int protection_flags = PROT_NONE; + int map_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; + u8* result = (u8*)syscall_mmap(0, size, protection_flags, map_flags, -1, 0); + assert(result != MAP_FAILED); + return result; +} + +fn void commit(void* address, u64 size) +{ + int result = syscall_mprotect(address, size, PROT_READ | PROT_WRITE); + assert(result == 0); +} + +fn u64 align_forward(u64 value, u64 alignment) +{ + u64 mask = alignment - 1; + u64 result = (value + mask) & ~mask; + return result; +} + +fn u32 format_hexadecimal(String buffer, u64 hexadecimal) +{ + u64 value = hexadecimal; + if (value) + { + u8 reverse_buffer[16]; + u8 reverse_index = 0; + + while (value) + { + u8 digit_value = value % 16; + u8 ascii_ch = digit_value >= 10 ? (digit_value + 'a' - 10) : (digit_value + '0'); + value /= 16; + reverse_buffer[reverse_index] = ascii_ch; + reverse_index += 1; + } + + u32 index = 0; + + while (reverse_index > 0) + { + reverse_index -= 1; + buffer.pointer[index] = reverse_buffer[reverse_index]; + index += 1; + } + + return index; + } + else + { + buffer.pointer[0] = '0'; + return 1; + } +} + +fn u32 format_decimal(String buffer, u64 decimal) +{ + u64 value = decimal; + if (value) + { + u8 reverse_buffer[64]; + u8 reverse_index = 0; + + while (value) + { + u8 digit_value = (value % 10); + u8 ascii_ch = digit_value + '0'; + value /= 10; + reverse_buffer[reverse_index] = ascii_ch; + reverse_index += 1; + } + + u32 index = 0; + while (reverse_index > 0) + { + reverse_index -= 1; + buffer.pointer[index] = reverse_buffer[reverse_index]; + index += 1; + } + + return index; + } + else + { + buffer.pointer[0] = '0'; + return 1; + } +} + +#define SILENT (0) + +may_be_unused fn void print(const char* format, ...) +{ +#if SILENT == 0 + u8 stack_buffer[4096]; + va_list args; + va_start(args, format); + String buffer = { .pointer = stack_buffer, .length = array_length(stack_buffer) }; + u8* it = (u8*)format; + u64 buffer_i = 0; + + while (*it) + { + while (*it && *it != brace_open) + { + s_get(buffer, buffer_i) = *it; + buffer_i += 1; + it += 1; + } + + if (*it == brace_open) + { + it += 1; + char next_ch = *it; + + if (next_ch == brace_open) + { + trap(); + } + else + { + switch (next_ch) + { + case 'c': + { + int done = 0; + it += 1; + if (*it == 's') + { + it += 1; + if (*it == 't') + { + it += 1; + if (*it == 'r') + { + it += 1; + done = 1; + auto* cstring = va_arg(args, const char*); + while (*cstring) + { + buffer.pointer[buffer_i] = *cstring; + buffer_i += 1; + cstring += 1; + } + } + } + } + assert(done); + } break; + case 's': + { + it += 1; + + if (is_decimal_digit(*it)) + { + trap(); + } + else + { + String string = va_arg(args, String); + memcpy(buffer.pointer + buffer_i, string.pointer, string.length); + buffer_i += string.length; + } + + } break; + case 'u': + { + it += 1; + + u8* bit_count_start = it; + while (is_decimal_digit(*it)) + { + it += 1; + } + + u8* bit_count_end = it; + u64 bit_count = parse_decimal(slice_from_pointer_range(u8, (u8*)bit_count_start, (u8*)bit_count_end)); + + typedef enum IntegerFormat : u8 + { + INTEGER_FORMAT_HEXADECIMAL, + INTEGER_FORMAT_DECIMAL, + INTEGER_FORMAT_OCTAL, + INTEGER_FORMAT_BINARY, + } IntegerFormat; + + IntegerFormat format = INTEGER_FORMAT_DECIMAL; + + if (*it == ':') + { + it += 1; + switch (*it) + { + case 'x': + format = INTEGER_FORMAT_HEXADECIMAL; + break; + case 'd': + format = INTEGER_FORMAT_DECIMAL; + break; + case 'o': + format = INTEGER_FORMAT_OCTAL; + break; + case 'b': + format = INTEGER_FORMAT_BINARY; + break; + default: + trap(); + } + + it += 1; + } + + u64 original_value; + switch (bit_count) + { + case 8: + case 16: + case 32: + original_value = va_arg(args, u32); + break; + case 64: + original_value = va_arg(args, u64); + break; + default: + trap(); + } + + auto buffer_slice = s_get_slice(u8, buffer, buffer_i, buffer.length); + + switch (format) + { + case INTEGER_FORMAT_HEXADECIMAL: + { + auto written_characters = format_hexadecimal(buffer_slice, original_value); + buffer_i += written_characters; + } break; + case INTEGER_FORMAT_DECIMAL: + { + auto written_characters = format_decimal(buffer_slice, original_value); + buffer_i += written_characters; + } break; + case INTEGER_FORMAT_OCTAL: + case INTEGER_FORMAT_BINARY: + trap(); + } + } break; + default: + buffer.pointer[buffer_i] = '{'; + buffer_i += 1; + continue; + } + + if (*it != brace_close) + { + fail(); + } + + it += 1; + } + } + } + + String final_string = s_get_slice(u8, buffer, 0, buffer_i); + syscall_write(1, final_string.pointer, final_string.length); +#endif +} + +global u64 minimum_granularity = page_size; +// global u64 middle_granularity = MB(2); +global u64 default_size = GB(4); + +struct Arena +{ + u64 reserved_size; + u64 committed; + u64 commit_position; + u64 granularity; + u8 reserved[4 * 8]; +}; + +typedef struct Arena Arena; +static_assert(sizeof(Arena) == 64); + +fn Arena* arena_init(u64 reserved_size, u64 granularity, u64 initial_size) +{ + Arena* arena = (Arena*)reserve(reserved_size); + commit(arena, initial_size); + *arena = (Arena){ + .reserved_size = reserved_size, + .committed = initial_size, + .commit_position = sizeof(Arena), + .granularity = granularity, + }; + return arena; +} + +fn Arena* arena_init_default(u64 initial_size) +{ + return arena_init(default_size, minimum_granularity, initial_size); +} + +fn u8* arena_allocate_bytes(Arena* arena, u64 size, u64 alignment) +{ + u64 aligned_offset = align_forward(arena->commit_position, alignment); + u64 aligned_size_after = aligned_offset + size; + + if (aligned_size_after > arena->committed) + { + u64 committed_size = align_forward(aligned_size_after, arena->granularity); + u64 size_to_commit = committed_size - arena->committed; + void* commit_pointer = (u8*)arena + arena->committed; + commit(commit_pointer, size_to_commit); + arena->committed = committed_size; + } + + auto* result = (u8*)arena + aligned_offset; + arena->commit_position = aligned_size_after; + assert(arena->commit_position <= arena->committed); + return result; +} + +fn String arena_join_string(Arena* arena, Slice(String) pieces) +{ + u64 size = 0; + for (u64 i = 0; i < pieces.length; i += 1) + { + String piece = pieces.pointer[i]; + size += piece.length; + } + + u8* pointer = arena_allocate_bytes(arena, size + 1, 1); + auto* it = pointer; + for (u64 i = 0; i < pieces.length; i += 1) + { + String piece = pieces.pointer[i]; + memcpy(it, piece.pointer, piece.length); + it += piece.length; + } + assert((u64)(it - pointer) == size); + *it = 0; + + return (String) { .pointer = pointer, .length = size }; +} + +#define arena_allocate(arena, T, count) (T*)(arena_allocate_bytes(arena, sizeof(T) * count, alignof(T))) +#define arena_allocate_slice(arena, T, count) (Slice(T)){ .pointer = arena_allocate(arena, T, count), .length = count } + +may_be_unused fn void arena_reset(Arena* arena) +{ + arena->commit_position = sizeof(Arena); + memset(arena + 1, 0, arena->committed - sizeof(Arena)); +} + +#define transmute(D, source) *(D*)&source + +fn void run_command(CStringSlice arguments, char* envp[]) +{ + print("Running command:\n"); + assert(arguments.pointer[arguments.length - 1] == 0); + for (u32 i = 0; i < arguments.length - 1; i += 1) + { + char* argument = arguments.pointer[i]; + print("{cstr} ", argument); + } + print("\n"); + pid_t pid = syscall_fork(); + + if (pid == -1) + { + trap(); + } + + if (pid == 0) + { + // close(pipes[0]); + // fcntl(pipes[1], F_SETFD, FD_CLOEXEC); + auto result = syscall_execve(arguments.pointer[0], arguments.pointer, envp); +#if LINK_LIBC + print("Execve failed! Error: {cstr}\n", strerror(errno)); +#else + trap(); +#endif + unused(result); + trap(); + } + else + { + int status = 0; + int options = 0; + pid_t result = syscall_waitpid(pid, &status, options); + if (result == pid) + { + WIFEXITED(status); + auto exit_code = WEXITSTATUS(status); + if (exit_code != 0) + { + trap(); + } + } + else + { + trap(); + } + } +} + +#define VirtualBuffer(T) VirtualBuffer_ ## T +#define VirtualBufferP(T) VirtualBufferPointerTo_ ## T + +#define decl_vb_ex(T, StructName) \ +struct StructName \ +{\ + T* pointer;\ + u32 length;\ + u32 capacity;\ +};\ +typedef struct StructName StructName + +#define decl_vb(T) decl_vb_ex(T, VirtualBuffer(T)) +#define decl_vbp(T) decl_vb_ex(T*, VirtualBufferP(T)) + +decl_vb(u8); +decl_vbp(u8); + +fn void vb_generic_ensure_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count) +{ + u32 old_capacity = vb->capacity; + u32 wanted_capacity = vb->length + item_count; + + if (old_capacity < wanted_capacity) + { + if (old_capacity == 0) + { + vb->pointer = reserve(item_size * UINT32_MAX); + } + + u32 old_page_capacity = align_forward(old_capacity * item_size, minimum_granularity); + u32 new_page_capacity = align_forward(wanted_capacity * item_size, minimum_granularity); + + u32 commit_size = new_page_capacity - old_page_capacity; + void* commit_pointer = vb->pointer + old_page_capacity; + + commit(commit_pointer, commit_size); + + u32 new_capacity = new_page_capacity / item_size; + vb->capacity = new_capacity; + } +} + +fn u8* vb_generic_add_assume_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count) +{ + u32 index = vb->length; + assert(vb->capacity >= index + item_count); + vb->length = index + item_count; + return vb->pointer + (index * item_size); +} + +// fn u8* vb_generic_append_assume_capacity(VirtualBuffer(u8)* vb, void* item_pointer, u32 item_size, u32 item_count) +// { +// u8* new_memory = vb_generic_add_assume_capacity(vb, item_size, item_count); +// memcpy(new_memory, item_pointer, item_size * item_count); +// return new_memory; +// } + +fn u8* vb_generic_add(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count) +{ + vb_generic_ensure_capacity(vb, item_size, item_count); + return vb_generic_add_assume_capacity(vb, item_size, item_count); +} + + +// fn u8* vb_generic_append(VirtualBuffer(u8)* vb, void* item_pointer, u32 item_size, u32 item_count) +// { +// vb_generic_ensure_capacity(vb, item_size, item_count); +// return vb_generic_append_assume_capacity(vb, item_pointer, item_size, item_count); +// } + +#define vb_add(a, count) (typeof((a)->pointer)) vb_generic_add((VirtualBuffer(u8)*)(a), sizeof(*((a)->pointer)), count) +#define vb_append_one(a, item) (typeof((a)->pointer)) vb_generic_append((VirtualBuffer(u8)*)(a), &(item), sizeof(*((a)->pointer)), 1) diff --git a/bootstrap/main.c b/bootstrap/main.c index 239700c..a60b06b 100644 --- a/bootstrap/main.c +++ b/bootstrap/main.c @@ -1,1306 +1,4 @@ -#include -#include -#include - -#include -#include -#include -#include - -#ifdef STATIC -#define LINK_LIBC 0 -#else -#define LINK_LIBC 1 -#endif - -#if LINK_LIBC -#include -#include -#include -#endif - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -typedef float f32; -typedef double f64; - -typedef u64 Hash; - -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - -#define fn static -#define method __attribute__((visibility("internal"))) -#define global static -#define forceinline __attribute__((always_inline)) -#define expect(x, b) __builtin_expect(x, b) -#define breakpoint() __builtin_debugtrap() -#define fail() trap() -#define trap() bad_ex(__FILE__, __LINE__) -#define array_length(arr) sizeof(arr) / sizeof((arr)[0]) -#define KB(n) ((n) * 1024) -#define MB(n) ((n) * 1024 * 1024) -#define GB(n) ((u64)(n) * 1024 * 1024 * 1024) -#define TB(n) ((u64)(n) * 1024 * 1024 * 1024 * 1024) -#define unused(x) (void)(x) -#define may_be_unused __attribute__((unused)) -#if LINK_LIBC -#define assert(x) if (__builtin_expect(!(x), 0)) { print("Assert failed! ERRNO: "); print(strerror(errno)); print("\n"); trap(); } -#else -#define assert(x) if (__builtin_expect(!(x), 0)) { print("Assert failed!\n"); trap(); } -#endif -#define static_assert(x) _Static_assert((x), "Static assert failed!") -#define alignof(x) _Alignof(x) -#define auto __auto_type - -#define bad_ex(file, line) do { print("Bad exit at {cstr}:{u32}\n", file, line); __builtin_trap(); } while(0) -#define todo() do { print("TODO at {cstr}:{u32}\n", __FILE__, __LINE__); __builtin_trap(); } while(0) - -may_be_unused fn void print(const char* format, ...); - -#if __APPLE__ - const global u64 page_size = KB(16); -#else - const global u64 page_size = KB(4); -#endif - - -const may_be_unused global u8 brace_open = '{'; -const may_be_unused global u8 brace_close = '}'; - -const may_be_unused global u8 parenthesis_open = '('; -const may_be_unused global u8 parenthesis_close = ')'; - -const may_be_unused global u8 bracket_open = '['; -const may_be_unused global u8 bracket_close = ']'; - -fn u8 log2_alignment(u64 alignment) -{ - assert(alignment != 0); - assert((alignment & (alignment - 1)) == 0); - u64 left = (sizeof(alignment) * 8) - 1; - u64 right = __builtin_clzl(alignment); - u8 result = left - right; - return result; -} - -// Lehmer's generator -// https://lemire.me/blog/2019/03/19/the-fastest-conventional-random-number-generator-that-can-pass-big-crush/ -// __uint128_t rn_state; -// fn u64 generate_random_number() -// { -// rn_state *= 0xda942042e4dd58b5; -// return rn_state >> 64; -// } - -fn u64 round_up_to_next_power_of_2(u64 n) -{ - n -= 1; - n |= n >> 1; - n |= n >> 2; - n |= n >> 4; - n |= n >> 8; - n |= n >> 16; - n |= n >> 32; - n += 1; - return n; -} - -#if LINK_LIBC == 0 -void* memcpy(void* __restrict dst, void* __restrict src, u64 size) -{ - auto* destination = (u8*)dst; - auto* source = (u8*)src; - - for (u64 i = 0; i < size; i += 1) - { - destination[i] = source[i]; - } - - return dst; -} - -void* memset(void* dst, u8 n, u64 size) -{ - auto* destination = (u8*)dst; - for (u64 i = 0; i < size; i += 1) - { - destination[i] = n; - } - - return dst; -} - -fn int memcmp(const void* left, const void* right, u64 n) -{ - const u8 *l=(const u8*)left, *r=(const u8*)right; - for (; n && *l == *r; n--, l++, r++); - return n ? *l - *r : 0; -} - -fn u64 strlen (const char* c_string) -{ - auto* it = c_string; - while (*it) - { - it += 1; - } - return it - c_string; -} -#endif -#define slice_from_pointer_range(T, start, end) (Slice(T)) { .pointer = start, .length = (u64)(end - start), } - -#define strlit(s) (String){ .pointer = (u8*)s, .length = sizeof(s) - 1, } -#define ch_to_str(ch) (String){ .pointer = &ch, .length = 1 } -#define array_to_slice(arr) { .pointer = (arr), .length = array_length(arr) } -#define pointer_to_bytes(p) (String) { .pointer = (u8*)(p), .length = sizeof(*p) } -#define struct_to_bytes(s) pointer_to_bytes(&(s)) - -#define case_to_name(prefix, e) case prefix ## e: return strlit(#e) - -#define Slice(T) Slice_ ## T -#define SliceP(T) SliceP_ ## T -#define declare_slice_ex(T, StructName) struct StructName \ -{\ - T* pointer;\ - u64 length;\ -};\ -typedef struct StructName StructName - -#define declare_slice(T) declare_slice_ex(T, Slice(T)) -#define declare_slice_p(T) declare_slice_ex(T*, SliceP(T)) - -#define s_get(s, i) (s).pointer[i] -#define s_get_pointer(s, i) &((s).pointer[i]) -#define s_get_slice(T, s, start, end) (Slice(T)){ .pointer = ((s).pointer) + (start), .length = (end) - (start) } -#define s_equal(a, b) ((a).length == (b).length && memcmp((a).pointer, (b).pointer, sizeof(*((a).pointer))) == 0) - -declare_slice(u8); -typedef Slice(u8) String; -// Array of strings -declare_slice(String); - -// fn s32 string_first_ch(String string, u8 ch) -// { -// s32 result = -1; -// for (u64 i = 0; i < string.length; i += 1) -// { -// if (string.pointer[i] == ch) -// { -// result = i; -// break; -// } -// } -// -// return result; -// } - -fn s32 string_last_ch(String string, u8 ch) -{ - s32 result = -1; - u64 i = string.length; - while (i > 0) - { - i -= 1; - if (string.pointer[i] == ch) - { - result = i; - break; - } - } - - return result; -} - -// fn String string_dir(String string) -// { -// String result = {}; -// auto index = string_last_ch(string, '/'); -// if (index != -1) -// { -// result = s_get_slice(u8, string, 0, index); -// } -// -// return result; -// } - -fn String string_base(String string) -{ - String result = {}; - auto index = string_last_ch(string, '/'); - if (index != -1) - { - result = s_get_slice(u8, string, index + 1, string.length); - } - - return result; -} - -fn String string_no_extension(String string) -{ - String result = {}; - auto index = string_last_ch(string, '.'); - if (index != -1) - { - result = s_get_slice(u8, string, 0, index); - } - - return result; -} - -fn u64 parse_decimal(String string) -{ - u64 value = 0; - for (u64 i = 0; i < string.length; i += 1) - { - u8 ch = s_get(string, i); - assert(((ch >= '0') & (ch <= '9'))); - value = (value * 10) + (ch - '0'); - } - - return value; -} - -fn u64 safe_flag(u64 value, u64 flag) -{ - u64 result = value & ((u64)0 - flag); - return result; -} - -fn u8 get_next_ch_safe(String string, u64 index) -{ - u64 next_index = index + 1; - u64 is_in_range = next_index < string.length; - u64 safe_index = safe_flag(next_index, is_in_range); - u8 unsafe_result = string.pointer[safe_index]; - u64 safe_result = safe_flag(unsafe_result, is_in_range); - assert(safe_result < 256); - return (u8)safe_result; -} - -fn u32 is_space(u8 ch, u8 next_ch) -{ - u32 is_comment = (ch == '/') & (next_ch == '/'); - u32 is_whitespace = ch == ' '; - u32 is_vertical_tab = ch == 0x0b; - u32 is_horizontal_tab = ch == '\t'; - u32 is_line_feed = ch == '\n'; - u32 is_carry_return = ch == '\r'; - u32 result = (((is_vertical_tab | is_horizontal_tab) | (is_line_feed | is_carry_return)) | (is_comment | is_whitespace)); - return result; -} - -fn u64 is_lower(u8 ch) -{ - return (ch >= 'a') & (ch <= 'z'); -} - -fn u64 is_upper(u8 ch) -{ - return (ch >= 'A') & (ch <= 'Z'); -} - -fn u64 is_alphabetic(u8 ch) -{ - return is_lower(ch) | is_upper(ch); -} - -fn u64 is_decimal_digit(u8 ch) -{ - return (ch >= '0') & (ch <= '9'); -} - -// fn u64 is_hex_digit(u8 ch) -// { -// return (is_decimal_digit(ch) | ((ch == 'a' | ch == 'A') | (ch == 'b' | ch == 'B'))) | (((ch == 'c' | ch == 'C') | (ch == 'd' | ch == 'D')) | ((ch == 'e' | ch == 'E') | (ch == 'f' | ch == 'F'))); -// } - - -fn u64 is_identifier_start(u8 ch) -{ - u64 alphabetic = is_alphabetic(ch); - u64 is_underscore = ch == '_'; - return alphabetic | is_underscore; -} - -fn u64 is_identifier_ch(u8 ch) -{ - u64 identifier_start = is_identifier_start(ch); - u64 decimal = is_decimal_digit(ch); - return identifier_start | decimal; -} - -global const Hash fnv_offset = 14695981039346656037ull; -global const u64 fnv_prime = 1099511628211ull; - -fn Hash hash_byte(Hash source, u8 ch) -{ - source ^= ch; - source *= fnv_prime; - return source; -} - -fn Hash hash_bytes(String bytes) -{ - u64 result = fnv_offset; - for (u64 i = 0; i < bytes.length; i += 1) - { - result = hash_byte(result, bytes.pointer[i]); - } - - return result; -} - -#if LINK_LIBC == 0 -#ifdef __linux__ -may_be_unused fn forceinline long syscall0(long n) -{ - unsigned long ret; - __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n) : "rcx", "r11", "memory"); - return ret; -} - -may_be_unused fn forceinline long syscall1(long n, long a1) -{ - unsigned long ret; - __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory"); - return ret; -} - -may_be_unused fn forceinline long syscall2(long n, long a1, long a2) -{ - unsigned long ret; - __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2) - : "rcx", "r11", "memory"); - return ret; -} - -may_be_unused fn forceinline long syscall3(long n, long a1, long a2, long a3) -{ - unsigned long ret; - __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), - "d"(a3) : "rcx", "r11", "memory"); - return ret; -} - -may_be_unused fn forceinline long syscall4(long n, long a1, long a2, long a3, long a4) -{ - unsigned long ret; - register long r10 __asm__("r10") = a4; - __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), - "d"(a3), "r"(r10): "rcx", "r11", "memory"); - return ret; -} - -may_be_unused fn forceinline long syscall5(long n, long a1, long a2, long a3, long a4, long a5) -{ - unsigned long ret; - register long r10 __asm__("r10") = a4; - register long r8 __asm__("r8") = a5; - __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), - "d"(a3), "r"(r10), "r"(r8) : "rcx", "r11", "memory"); - return ret; -} - -may_be_unused fn forceinline long syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) -{ - unsigned long ret; - register long r10 __asm__("r10") = a4; - register long r8 __asm__("r8") = a5; - register long r9 __asm__("r9") = a6; - __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), - "d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory"); - return ret; -} - -enum SyscallX86_64 : u64 { - syscall_x86_64_read = 0, - syscall_x86_64_write = 1, - syscall_x86_64_open = 2, - syscall_x86_64_close = 3, - syscall_x86_64_stat = 4, - syscall_x86_64_fstat = 5, - syscall_x86_64_lstat = 6, - syscall_x86_64_poll = 7, - syscall_x86_64_lseek = 8, - syscall_x86_64_mmap = 9, - syscall_x86_64_mprotect = 10, - syscall_x86_64_munmap = 11, - syscall_x86_64_brk = 12, - syscall_x86_64_rt_sigaction = 13, - syscall_x86_64_rt_sigprocmask = 14, - syscall_x86_64_rt_sigreturn = 15, - syscall_x86_64_ioctl = 16, - syscall_x86_64_pread64 = 17, - syscall_x86_64_pwrite64 = 18, - syscall_x86_64_readv = 19, - syscall_x86_64_writev = 20, - syscall_x86_64_access = 21, - syscall_x86_64_pipe = 22, - syscall_x86_64_select = 23, - syscall_x86_64_sched_yield = 24, - syscall_x86_64_mremap = 25, - syscall_x86_64_msync = 26, - syscall_x86_64_mincore = 27, - syscall_x86_64_madvise = 28, - syscall_x86_64_shmget = 29, - syscall_x86_64_shmat = 30, - syscall_x86_64_shmctl = 31, - syscall_x86_64_dup = 32, - syscall_x86_64_dup2 = 33, - syscall_x86_64_pause = 34, - syscall_x86_64_nanosleep = 35, - syscall_x86_64_getitimer = 36, - syscall_x86_64_alarm = 37, - syscall_x86_64_setitimer = 38, - syscall_x86_64_getpid = 39, - syscall_x86_64_sendfile = 40, - syscall_x86_64_socket = 41, - syscall_x86_64_connect = 42, - syscall_x86_64_accept = 43, - syscall_x86_64_sendto = 44, - syscall_x86_64_recvfrom = 45, - syscall_x86_64_sendmsg = 46, - syscall_x86_64_recvmsg = 47, - syscall_x86_64_shutdown = 48, - syscall_x86_64_bind = 49, - syscall_x86_64_listen = 50, - syscall_x86_64_getsockname = 51, - syscall_x86_64_getpeername = 52, - syscall_x86_64_socketpair = 53, - syscall_x86_64_setsockopt = 54, - syscall_x86_64_getsockopt = 55, - syscall_x86_64_clone = 56, - syscall_x86_64_fork = 57, - syscall_x86_64_vfork = 58, - syscall_x86_64_execve = 59, - syscall_x86_64_exit = 60, - syscall_x86_64_wait4 = 61, - syscall_x86_64_kill = 62, - syscall_x86_64_uname = 63, - syscall_x86_64_semget = 64, - syscall_x86_64_semop = 65, - syscall_x86_64_semctl = 66, - syscall_x86_64_shmdt = 67, - syscall_x86_64_msgget = 68, - syscall_x86_64_msgsnd = 69, - syscall_x86_64_msgrcv = 70, - syscall_x86_64_msgctl = 71, - syscall_x86_64_fcntl = 72, - syscall_x86_64_flock = 73, - syscall_x86_64_fsync = 74, - syscall_x86_64_fdatasync = 75, - syscall_x86_64_truncate = 76, - syscall_x86_64_ftruncate = 77, - syscall_x86_64_getdents = 78, - syscall_x86_64_getcwd = 79, - syscall_x86_64_chdir = 80, - syscall_x86_64_fchdir = 81, - syscall_x86_64_rename = 82, - syscall_x86_64_mkdir = 83, - syscall_x86_64_rmdir = 84, - syscall_x86_64_creat = 85, - syscall_x86_64_link = 86, - syscall_x86_64_unlink = 87, - syscall_x86_64_symlink = 88, - syscall_x86_64_readlink = 89, - syscall_x86_64_chmod = 90, - syscall_x86_64_fchmod = 91, - syscall_x86_64_chown = 92, - syscall_x86_64_fchown = 93, - syscall_x86_64_lchown = 94, - syscall_x86_64_umask = 95, - syscall_x86_64_gettimeofday = 96, - syscall_x86_64_getrlimit = 97, - syscall_x86_64_getrusage = 98, - syscall_x86_64_sysinfo = 99, - syscall_x86_64_times = 100, - syscall_x86_64_ptrace = 101, - syscall_x86_64_getuid = 102, - syscall_x86_64_syslog = 103, - syscall_x86_64_getgid = 104, - syscall_x86_64_setuid = 105, - syscall_x86_64_setgid = 106, - syscall_x86_64_geteuid = 107, - syscall_x86_64_getegid = 108, - syscall_x86_64_setpgid = 109, - syscall_x86_64_getppid = 110, - syscall_x86_64_getpgrp = 111, - syscall_x86_64_setsid = 112, - syscall_x86_64_setreuid = 113, - syscall_x86_64_setregid = 114, - syscall_x86_64_getgroups = 115, - syscall_x86_64_setgroups = 116, - syscall_x86_64_setresuid = 117, - syscall_x86_64_getresuid = 118, - syscall_x86_64_setresgid = 119, - syscall_x86_64_getresgid = 120, - syscall_x86_64_getpgid = 121, - syscall_x86_64_setfsuid = 122, - syscall_x86_64_setfsgid = 123, - syscall_x86_64_getsid = 124, - syscall_x86_64_capget = 125, - syscall_x86_64_capset = 126, - syscall_x86_64_rt_sigpending = 127, - syscall_x86_64_rt_sigtimedwait = 128, - syscall_x86_64_rt_sigqueueinfo = 129, - syscall_x86_64_rt_sigsuspend = 130, - syscall_x86_64_sigaltstack = 131, - syscall_x86_64_utime = 132, - syscall_x86_64_mknod = 133, - syscall_x86_64_uselib = 134, - syscall_x86_64_personality = 135, - syscall_x86_64_ustat = 136, - syscall_x86_64_statfs = 137, - syscall_x86_64_fstatfs = 138, - syscall_x86_64_sysfs = 139, - syscall_x86_64_getpriority = 140, - syscall_x86_64_setpriority = 141, - syscall_x86_64_sched_setparam = 142, - syscall_x86_64_sched_getparam = 143, - syscall_x86_64_sched_setscheduler = 144, - syscall_x86_64_sched_getscheduler = 145, - syscall_x86_64_sched_get_priority_max = 146, - syscall_x86_64_sched_get_priority_min = 147, - syscall_x86_64_sched_rr_get_interval = 148, - syscall_x86_64_mlock = 149, - syscall_x86_64_munlock = 150, - syscall_x86_64_mlockall = 151, - syscall_x86_64_munlockall = 152, - syscall_x86_64_vhangup = 153, - syscall_x86_64_modify_ldt = 154, - syscall_x86_64_pivot_root = 155, - syscall_x86_64__sysctl = 156, - syscall_x86_64_prctl = 157, - syscall_x86_64_arch_prctl = 158, - syscall_x86_64_adjtimex = 159, - syscall_x86_64_setrlimit = 160, - syscall_x86_64_chroot = 161, - syscall_x86_64_sync = 162, - syscall_x86_64_acct = 163, - syscall_x86_64_settimeofday = 164, - syscall_x86_64_mount = 165, - syscall_x86_64_umount2 = 166, - syscall_x86_64_swapon = 167, - syscall_x86_64_swapoff = 168, - syscall_x86_64_reboot = 169, - syscall_x86_64_sethostname = 170, - syscall_x86_64_setdomainname = 171, - syscall_x86_64_iopl = 172, - syscall_x86_64_ioperm = 173, - syscall_x86_64_create_module = 174, - syscall_x86_64_init_module = 175, - syscall_x86_64_delete_module = 176, - syscall_x86_64_get_kernel_syms = 177, - syscall_x86_64_query_module = 178, - syscall_x86_64_quotactl = 179, - syscall_x86_64_nfsservctl = 180, - syscall_x86_64_getpmsg = 181, - syscall_x86_64_putpmsg = 182, - syscall_x86_64_afs_syscall = 183, - syscall_x86_64_tuxcall = 184, - syscall_x86_64_security = 185, - syscall_x86_64_gettid = 186, - syscall_x86_64_readahead = 187, - syscall_x86_64_setxattr = 188, - syscall_x86_64_lsetxattr = 189, - syscall_x86_64_fsetxattr = 190, - syscall_x86_64_getxattr = 191, - syscall_x86_64_lgetxattr = 192, - syscall_x86_64_fgetxattr = 193, - syscall_x86_64_listxattr = 194, - syscall_x86_64_llistxattr = 195, - syscall_x86_64_flistxattr = 196, - syscall_x86_64_removexattr = 197, - syscall_x86_64_lremovexattr = 198, - syscall_x86_64_fremovexattr = 199, - syscall_x86_64_tkill = 200, - syscall_x86_64_time = 201, - syscall_x86_64_futex = 202, - syscall_x86_64_sched_setaffinity = 203, - syscall_x86_64_sched_getaffinity = 204, - syscall_x86_64_set_thread_area = 205, - syscall_x86_64_io_setup = 206, - syscall_x86_64_io_destroy = 207, - syscall_x86_64_io_getevents = 208, - syscall_x86_64_io_submit = 209, - syscall_x86_64_io_cancel = 210, - syscall_x86_64_get_thread_area = 211, - syscall_x86_64_lookup_dcookie = 212, - syscall_x86_64_epoll_create = 213, - syscall_x86_64_epoll_ctl_old = 214, - syscall_x86_64_epoll_wait_old = 215, - syscall_x86_64_remap_file_pages = 216, - syscall_x86_64_getdents64 = 217, - syscall_x86_64_set_tid_address = 218, - syscall_x86_64_restart_syscall = 219, - syscall_x86_64_semtimedop = 220, - syscall_x86_64_fadvise64 = 221, - syscall_x86_64_timer_create = 222, - syscall_x86_64_timer_settime = 223, - syscall_x86_64_timer_gettime = 224, - syscall_x86_64_timer_getoverrun = 225, - syscall_x86_64_timer_delete = 226, - syscall_x86_64_clock_settime = 227, - syscall_x86_64_clock_gettime = 228, - syscall_x86_64_clock_getres = 229, - syscall_x86_64_clock_nanosleep = 230, - syscall_x86_64_exit_group = 231, - syscall_x86_64_epoll_wait = 232, - syscall_x86_64_epoll_ctl = 233, - syscall_x86_64_tgkill = 234, - syscall_x86_64_utimes = 235, - syscall_x86_64_vserver = 236, - syscall_x86_64_mbind = 237, - syscall_x86_64_set_mempolicy = 238, - syscall_x86_64_get_mempolicy = 239, - syscall_x86_64_mq_open = 240, - syscall_x86_64_mq_unlink = 241, - syscall_x86_64_mq_timedsend = 242, - syscall_x86_64_mq_timedreceive = 243, - syscall_x86_64_mq_notify = 244, - syscall_x86_64_mq_getsetattr = 245, - syscall_x86_64_kexec_load = 246, - syscall_x86_64_waitid = 247, - syscall_x86_64_add_key = 248, - syscall_x86_64_request_key = 249, - syscall_x86_64_keyctl = 250, - syscall_x86_64_ioprio_set = 251, - syscall_x86_64_ioprio_get = 252, - syscall_x86_64_inotify_init = 253, - syscall_x86_64_inotify_add_watch = 254, - syscall_x86_64_inotify_rm_watch = 255, - syscall_x86_64_migrate_pages = 256, - syscall_x86_64_openat = 257, - syscall_x86_64_mkdirat = 258, - syscall_x86_64_mknodat = 259, - syscall_x86_64_fchownat = 260, - syscall_x86_64_futimesat = 261, - syscall_x86_64_fstatat64 = 262, - syscall_x86_64_unlinkat = 263, - syscall_x86_64_renameat = 264, - syscall_x86_64_linkat = 265, - syscall_x86_64_symlinkat = 266, - syscall_x86_64_readlinkat = 267, - syscall_x86_64_fchmodat = 268, - syscall_x86_64_faccessat = 269, - syscall_x86_64_pselect6 = 270, - syscall_x86_64_ppoll = 271, - syscall_x86_64_unshare = 272, - syscall_x86_64_set_robust_list = 273, - syscall_x86_64_get_robust_list = 274, - syscall_x86_64_splice = 275, - syscall_x86_64_tee = 276, - syscall_x86_64_sync_file_range = 277, - syscall_x86_64_vmsplice = 278, - syscall_x86_64_move_pages = 279, - syscall_x86_64_utimensat = 280, - syscall_x86_64_epoll_pwait = 281, - syscall_x86_64_signalfd = 282, - syscall_x86_64_timerfd_create = 283, - syscall_x86_64_eventfd = 284, - syscall_x86_64_fallocate = 285, - syscall_x86_64_timerfd_settime = 286, - syscall_x86_64_timerfd_gettime = 287, - syscall_x86_64_accept4 = 288, - syscall_x86_64_signalfd4 = 289, - syscall_x86_64_eventfd2 = 290, - syscall_x86_64_epoll_create1 = 291, - syscall_x86_64_dup3 = 292, - syscall_x86_64_pipe2 = 293, - syscall_x86_64_inotify_init1 = 294, - syscall_x86_64_preadv = 295, - syscall_x86_64_pwritev = 296, - syscall_x86_64_rt_tgsigqueueinfo = 297, - syscall_x86_64_perf_event_open = 298, - syscall_x86_64_recvmmsg = 299, - syscall_x86_64_fanotify_init = 300, - syscall_x86_64_fanotify_mark = 301, - syscall_x86_64_prlimit64 = 302, - syscall_x86_64_name_to_handle_at = 303, - syscall_x86_64_open_by_handle_at = 304, - syscall_x86_64_clock_adjtime = 305, - syscall_x86_64_syncfs = 306, - syscall_x86_64_sendmmsg = 307, - syscall_x86_64_setns = 308, - syscall_x86_64_getcpu = 309, - syscall_x86_64_process_vm_readv = 310, - syscall_x86_64_process_vm_writev = 311, - syscall_x86_64_kcmp = 312, - syscall_x86_64_finit_module = 313, - syscall_x86_64_sched_setattr = 314, - syscall_x86_64_sched_getattr = 315, - syscall_x86_64_renameat2 = 316, - syscall_x86_64_seccomp = 317, - syscall_x86_64_getrandom = 318, - syscall_x86_64_memfd_create = 319, - syscall_x86_64_kexec_file_load = 320, - syscall_x86_64_bpf = 321, - syscall_x86_64_execveat = 322, - syscall_x86_64_userfaultfd = 323, - syscall_x86_64_membarrier = 324, - syscall_x86_64_mlock2 = 325, - syscall_x86_64_copy_file_range = 326, - syscall_x86_64_preadv2 = 327, - syscall_x86_64_pwritev2 = 328, - syscall_x86_64_pkey_mprotect = 329, - syscall_x86_64_pkey_alloc = 330, - syscall_x86_64_pkey_free = 331, - syscall_x86_64_statx = 332, - syscall_x86_64_io_pgetevents = 333, - syscall_x86_64_rseq = 334, - syscall_x86_64_pidfd_send_signal = 424, - syscall_x86_64_io_uring_setup = 425, - syscall_x86_64_io_uring_enter = 426, - syscall_x86_64_io_uring_register = 427, - syscall_x86_64_open_tree = 428, - syscall_x86_64_move_mount = 429, - syscall_x86_64_fsopen = 430, - syscall_x86_64_fsconfig = 431, - syscall_x86_64_fsmount = 432, - syscall_x86_64_fspick = 433, - syscall_x86_64_pidfd_open = 434, - syscall_x86_64_clone3 = 435, - syscall_x86_64_close_range = 436, - syscall_x86_64_openat2 = 437, - syscall_x86_64_pidfd_getfd = 438, - syscall_x86_64_faccessat2 = 439, - syscall_x86_64_process_madvise = 440, - syscall_x86_64_epoll_pwait2 = 441, - syscall_x86_64_mount_setattr = 442, - syscall_x86_64_quotactl_fd = 443, - syscall_x86_64_landlock_create_ruleset = 444, - syscall_x86_64_landlock_add_rule = 445, - syscall_x86_64_landlock_restrict_self = 446, - syscall_x86_64_memfd_secret = 447, - syscall_x86_64_process_mrelease = 448, - syscall_x86_64_futex_waitv = 449, - syscall_x86_64_set_mempolicy_home_node = 450, - syscall_x86_64_cachestat = 451, - syscall_x86_64_fchmodat2 = 452, - syscall_x86_64_map_shadow_stack = 453, - syscall_x86_64_futex_wake = 454, - syscall_x86_64_futex_wait = 455, - syscall_x86_64_futex_requeue = 456, -}; -#endif -#endif - -fn void* syscall_mmap(void* address, size_t length, int protection_flags, int map_flags, int fd, signed long offset) -{ -#if LINK_LIBC - return mmap(address, length, protection_flags, map_flags, fd, offset); -#else -#ifdef __linux__ - return (void*) syscall6(syscall_x86_64_mmap, (unsigned long)address, length, protection_flags, map_flags, fd, offset); -#else -#error "Unsupported operating system for static linking" -#endif -#endif -} - -fn int syscall_mprotect(void *address, size_t length, int protection_flags) -{ -#if LINK_LIBC - return mprotect(address, length, protection_flags); -#else -#ifdef __linux__ - return syscall3(syscall_x86_64_mprotect, (unsigned long)address, length, protection_flags); -#else - return mprotect(address, length, protection_flags); -#endif -#endif -} - -fn int syscall_open(const char *file_path, int flags, int mode) -{ -#if LINK_LIBC - return open(file_path, flags, mode); -#else -#ifdef __linux__ - return syscall3(syscall_x86_64_open, (unsigned long)file_path, flags, mode); -#else - return open(file_path, flags, mode); -#endif -#endif -} - -fn int syscall_close(int fd) -{ -#if LINK_LIBC - return close(fd); -#else -#ifdef __linux__ - return syscall1(syscall_x86_64_close, fd); -#else - return close(fd); -#endif -#endif -} - -fn int syscall_fstat(int fd, struct stat *buffer) -{ -#if LINK_LIBC - return fstat(fd, buffer); -#else -#ifdef __linux__ - return syscall2(syscall_x86_64_fstat, fd, (unsigned long)buffer); -#else - return fstat(fd, buffer); -#endif -#endif -} - -may_be_unused fn u64 file_get_size(int fd) -{ - struct stat stat_buffer; - int stat_result = syscall_fstat(fd, &stat_buffer); - assert(stat_result == 0); - u64 size = stat_buffer.st_size; - return size; -} - -fn ssize_t syscall_read(int fd, void* buffer, size_t bytes) -{ -#if LINK_LIBC - return read(fd, buffer, bytes); -#else -#ifdef __linux__ - return syscall3(syscall_x86_64_read, fd, (unsigned long)buffer, bytes); -#else - return read(fd, buffer, bytes); -#endif -#endif -} - -may_be_unused fn ssize_t syscall_write(int fd, const void *buffer, size_t bytes) -{ -#if LINK_LIBC - return write(fd, buffer, bytes); -#else -#ifdef __linux__ - return syscall3(syscall_x86_64_write, fd, (unsigned long)buffer, bytes); -#else - return write(fd, buffer, bytes); -#endif -#endif -} - -may_be_unused fn int syscall_mkdir(const char* path, u32 mode) -{ -#if LINK_LIBC - return mkdir(path, mode); -#else - return syscall2(syscall_x86_64_mkdir, (unsigned long)path, mode); -#endif -} - -may_be_unused fn int syscall_rmdir(const char* path) -{ -#if LINK_LIBC - return rmdir(path); -#else - return syscall1(syscall_x86_64_rmdir, (unsigned long)path); -#endif -} - -may_be_unused fn int syscall_unlink(const char* path) -{ -#if LINK_LIBC - return unlink(path); -#else - return syscall1(syscall_x86_64_unlink, (unsigned long)path); -#endif -} - -may_be_unused fn int syscall_execve(const char* path, char *const argv[], char *const envp[]) -{ -#if LINK_LIBC - return execve(path, argv, envp); -#else - return syscall3(syscall_x86_64_execve, (unsigned long)path, (unsigned long)argv, (unsigned long)envp); -#endif -} - -[[noreturn]] [[gnu::cold]] fn void syscall_exit(int status) -{ -#if LINK_LIBC - _exit(status); -#else -#ifdef __linux__ - (void)syscall1(231, status); - trap(); -#else - _exit(status); -#endif -#endif -} - -fn void* reserve(u64 size) -{ - int protection_flags = PROT_NONE; - int map_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; - void* result = syscall_mmap(0, size, protection_flags, map_flags, -1, 0); - assert(result != MAP_FAILED); - return result; -} - -fn void commit(void* address, u64 size) -{ - int result = syscall_mprotect(address, size, PROT_READ | PROT_WRITE); - assert(result == 0); -} - -fn u64 align_forward(u64 value, u64 alignment) -{ - u64 mask = alignment - 1; - u64 result = (value + mask) & ~mask; - return result; -} - -fn u32 format_hexadecimal(String buffer, u64 hexadecimal) -{ - u64 value = hexadecimal; - if (value) - { - u8 reverse_buffer[16]; - u8 reverse_index = 0; - - while (value) - { - u8 digit_value = value % 16; - u8 ascii_ch = digit_value >= 10 ? (digit_value + 'a' - 10) : (digit_value + '0'); - value /= 16; - reverse_buffer[reverse_index] = ascii_ch; - reverse_index += 1; - } - - u32 index = 0; - - while (reverse_index > 0) - { - reverse_index -= 1; - buffer.pointer[index] = reverse_buffer[reverse_index]; - index += 1; - } - - return index; - } - else - { - buffer.pointer[0] = '0'; - return 1; - } -} - -fn u32 format_decimal(String buffer, u64 decimal) -{ - u64 value = decimal; - if (value) - { - u8 reverse_buffer[64]; - u8 reverse_index = 0; - - while (value) - { - u8 digit_value = (value % 10); - u8 ascii_ch = digit_value + '0'; - value /= 10; - reverse_buffer[reverse_index] = ascii_ch; - reverse_index += 1; - } - - u32 index = 0; - while (reverse_index > 0) - { - reverse_index -= 1; - buffer.pointer[index] = reverse_buffer[reverse_index]; - index += 1; - } - - return index; - } - else - { - buffer.pointer[0] = '0'; - return 1; - } -} - -#define SILENT (0) - -may_be_unused fn void print(const char* format, ...) -{ -#if SILENT == 0 - u8 stack_buffer[4096]; - va_list args; - va_start(args, format); - String buffer = { .pointer = stack_buffer, .length = array_length(stack_buffer) }; - u8* it = (u8*)format; - u64 buffer_i = 0; - - while (*it) - { - while (*it && *it != brace_open) - { - s_get(buffer, buffer_i) = *it; - buffer_i += 1; - it += 1; - } - - if (*it == brace_open) - { - it += 1; - char next_ch = *it; - - if (next_ch == brace_open) - { - trap(); - } - else - { - switch (next_ch) - { - case 'c': - { - int done = 0; - it += 1; - if (*it == 's') - { - it += 1; - if (*it == 't') - { - it += 1; - if (*it == 'r') - { - it += 1; - done = 1; - auto* cstring = va_arg(args, const char*); - while (*cstring) - { - buffer.pointer[buffer_i] = *cstring; - buffer_i += 1; - cstring += 1; - } - } - } - } - assert(done); - } break; - case 's': - { - it += 1; - - if (is_decimal_digit(*it)) - { - trap(); - } - else - { - String string = va_arg(args, String); - memcpy(buffer.pointer + buffer_i, string.pointer, string.length); - buffer_i += string.length; - } - - } break; - case 'u': - { - it += 1; - - u8* bit_count_start = it; - while (is_decimal_digit(*it)) - { - it += 1; - } - - u8* bit_count_end = it; - u64 bit_count = parse_decimal(slice_from_pointer_range(u8, (u8*)bit_count_start, (u8*)bit_count_end)); - - typedef enum IntegerFormat : u8 - { - INTEGER_FORMAT_HEXADECIMAL, - INTEGER_FORMAT_DECIMAL, - INTEGER_FORMAT_OCTAL, - INTEGER_FORMAT_BINARY, - } IntegerFormat; - - IntegerFormat format = INTEGER_FORMAT_DECIMAL; - - if (*it == ':') - { - it += 1; - switch (*it) - { - case 'x': - format = INTEGER_FORMAT_HEXADECIMAL; - break; - case 'd': - format = INTEGER_FORMAT_DECIMAL; - break; - case 'o': - format = INTEGER_FORMAT_OCTAL; - break; - case 'b': - format = INTEGER_FORMAT_BINARY; - break; - default: - trap(); - } - - it += 1; - } - - u64 original_value; - switch (bit_count) - { - case 8: - case 16: - case 32: - original_value = va_arg(args, u32); - break; - case 64: - original_value = va_arg(args, u64); - break; - default: - trap(); - } - - auto buffer_slice = s_get_slice(u8, buffer, buffer_i, buffer.length); - - switch (format) - { - case INTEGER_FORMAT_HEXADECIMAL: - { - auto written_characters = format_hexadecimal(buffer_slice, original_value); - buffer_i += written_characters; - } break; - case INTEGER_FORMAT_DECIMAL: - { - auto written_characters = format_decimal(buffer_slice, original_value); - buffer_i += written_characters; - } break; - case INTEGER_FORMAT_OCTAL: - case INTEGER_FORMAT_BINARY: - trap(); - } - } break; - default: - buffer.pointer[buffer_i] = '{'; - buffer_i += 1; - continue; - } - - if (*it != brace_close) - { - fail(); - } - - it += 1; - } - } - } - - String final_string = s_get_slice(u8, buffer, 0, buffer_i); - syscall_write(1, final_string.pointer, final_string.length); -#endif -} - -global u64 minimum_granularity = page_size; -// global u64 middle_granularity = MB(2); -global u64 default_size = GB(4); - -struct Arena -{ - u64 reserved_size; - u64 committed; - u64 commit_position; - u64 granularity; - u8 reserved[4 * 8]; -}; - -typedef struct Arena Arena; -static_assert(sizeof(Arena) == 64); - -fn Arena* arena_init(u64 reserved_size, u64 granularity, u64 initial_size) -{ - Arena* arena = (Arena*)reserve(reserved_size); - commit(arena, initial_size); - *arena = (Arena){ - .reserved_size = reserved_size, - .committed = initial_size, - .commit_position = sizeof(Arena), - .granularity = granularity, - }; - return arena; -} - -fn Arena* arena_init_default(u64 initial_size) -{ - return arena_init(default_size, minimum_granularity, initial_size); -} - -fn void* arena_allocate_bytes(Arena* arena, u64 size, u64 alignment) -{ - u64 aligned_offset = align_forward(arena->commit_position, alignment); - u64 aligned_size_after = aligned_offset + size; - - if (aligned_size_after > arena->committed) - { - u64 committed_size = align_forward(aligned_size_after, arena->granularity); - u64 size_to_commit = committed_size - arena->committed; - void* commit_pointer = (u8*)arena + arena->committed; - commit(commit_pointer, size_to_commit); - arena->committed = committed_size; - } - - void* result = (u8*)arena + aligned_offset; - arena->commit_position = aligned_size_after; - assert(arena->commit_position <= arena->committed); - return result; -} - -fn String arena_join_string(Arena* arena, Slice(String) pieces) -{ - u64 size = 0; - for (u64 i = 0; i < pieces.length; i += 1) - { - String piece = pieces.pointer[i]; - size += piece.length; - } - - u8* pointer = arena_allocate_bytes(arena, size + 1, 1); - auto* it = pointer; - for (u64 i = 0; i < pieces.length; i += 1) - { - String piece = pieces.pointer[i]; - memcpy(it, piece.pointer, piece.length); - it += piece.length; - } - assert((u64)(it - pointer) == size); - *it = 0; - - return (String) { .pointer = pointer, .length = size }; -} - -#define arena_allocate(arena, T, count) (T*)(arena_allocate_bytes(arena, sizeof(T) * count, alignof(T))) -#define arena_allocate_slice(arena, T, count) (Slice(T)){ .pointer = arena_allocate(arena, T, count), .length = count } - -fn void arena_reset(Arena* arena) -{ - arena->commit_position = sizeof(Arena); - memset(arena + 1, 0, arena->committed - sizeof(Arena)); -} - -#define transmute(D, source) *(D*)&source - +#include "lib.h" struct StringMapValue { String string; @@ -1721,79 +419,6 @@ struct NameReference typedef struct NameReference NameReference; -#define VirtualBuffer(T) VirtualBuffer_ ## T -#define VirtualBufferP(T) VirtualBufferPointerTo_ ## T - -#define decl_vb_ex(T, StructName) \ -struct StructName \ -{\ - T* pointer;\ - u32 length;\ - u32 capacity;\ -};\ -typedef struct StructName StructName - -#define decl_vb(T) decl_vb_ex(T, VirtualBuffer(T)) -#define decl_vbp(T) decl_vb_ex(T*, VirtualBufferP(T)) - -decl_vb(u8); - -fn void vb_generic_ensure_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count) -{ - u32 old_capacity = vb->capacity; - u32 wanted_capacity = vb->length + item_count; - - if (old_capacity < wanted_capacity) - { - if (old_capacity == 0) - { - vb->pointer = reserve(item_size * UINT32_MAX); - } - - u32 old_page_capacity = align_forward(old_capacity * item_size, minimum_granularity); - u32 new_page_capacity = align_forward(wanted_capacity * item_size, minimum_granularity); - - u32 commit_size = new_page_capacity - old_page_capacity; - void* commit_pointer = vb->pointer + old_page_capacity; - - commit(commit_pointer, commit_size); - - u32 new_capacity = new_page_capacity / item_size; - vb->capacity = new_capacity; - } -} - -fn u8* vb_generic_add_assume_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count) -{ - u32 index = vb->length; - assert(vb->capacity >= index + item_count); - vb->length = index + item_count; - return vb->pointer + (index * item_size); -} - -// fn u8* vb_generic_append_assume_capacity(VirtualBuffer(u8)* vb, void* item_pointer, u32 item_size, u32 item_count) -// { -// u8* new_memory = vb_generic_add_assume_capacity(vb, item_size, item_count); -// memcpy(new_memory, item_pointer, item_size * item_count); -// return new_memory; -// } - -fn u8* vb_generic_add(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count) -{ - vb_generic_ensure_capacity(vb, item_size, item_count); - return vb_generic_add_assume_capacity(vb, item_size, item_count); -} - - -// fn u8* vb_generic_append(VirtualBuffer(u8)* vb, void* item_pointer, u32 item_size, u32 item_count) -// { -// vb_generic_ensure_capacity(vb, item_size, item_count); -// return vb_generic_append_assume_capacity(vb, item_pointer, item_size, item_count); -// } - -#define vb_add(a, count) (typeof((a)->pointer)) vb_generic_add((VirtualBuffer(u8)*)(a), sizeof(*((a)->pointer)), count) -#define vb_append_one(a, item) (typeof((a)->pointer)) vb_generic_append((VirtualBuffer(u8)*)(a), &(item), sizeof(*((a)->pointer)), 1) - typedef struct Thread Thread; typedef enum TypeId : u32 @@ -6082,7 +4707,6 @@ fn Interpreter* interpreter_create(Thread* thread) fn s32 emit_node(Interpreter* interpreter, Thread* thread, NodeIndex node_index) { auto* node = thread_node_get(thread, node_index); - auto outputs = node_get_outputs(thread, node); auto inputs = node_get_inputs(thread, node); s32 result = -1; @@ -6294,9 +4918,8 @@ void entry_point(int argc, const char* argv[]) } print("\n"); - int res = syscall_execve("/usr/bin/cc", command, envp); - unused(res); - assert(0); + + run_command((CStringSlice) array_to_slice(command), envp); } break; case EXECUTION_ENGINE_INTERPRETER: { diff --git a/compile.sh b/compile.sh deleted file mode 100755 index 80e0af5..0000000 --- a/compile.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -function compile() -{ - mkdir -p $build_dir - - build_dir=$1 - exe_name=$2 - debug_info=$3 - optimizations=$4 - static=$5 - - echo "BUILD_DIR: $build_dir" - echo "EXE_NAME: $exe_name" - echo "DEBUG_INFO: $debug_info" - echo "OPTIMIZATIONS: $optimizations" - echo "STATIC: $static" - - compile_command="clang bootstrap/main.c -o $build_dir/$exe_name $debug_info $optimizations -std=gnu2x -Wall -Wextra -Wpedantic -Wno-nested-anon-types -Wno-keyword-macro -Wno-gnu-auto-type -Wno-auto-decl-extensions -pedantic -fno-exceptions -fno-stack-protector -ferror-limit=1 -MJ $build_dir/compile_commands.json" - - if [ "$static" == "1" ] - then - compile_command="$compile_command -ffreestanding -nostdlib -static -DSTATIC" - fi - - echo -e "\x1b[36m$compile_command\x1b[0m" - eval "time $compile_command" -} diff --git a/debug.sh b/debug.sh deleted file mode 100755 index a067f4d..0000000 --- a/debug.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -set -e - -path=$1 -if [ "$path" == "" ] -then - echo "error: a valid binary path must be provided to debug" - exit 1 -fi - -source ./compile.sh -build_dir="build" -exe_name="nest" -exe_path=$build_dir/$exe_name -debug_flags="-g" -optimization_flags="-O0" -bootstrap_args="$path c" -case "$OSTYPE" in - darwin*) static=0;; - linux*) static=1;; - *) echo "unknown: $OSTYPE" ;; -esac - -compile $build_dir $exe_name $debug_flags $optimization_flags $static - -case "$OSTYPE" in - darwin*) lldb -- $exe_path $bootstrap_args;; - linux*) gf2 -ex "set auto-solib-add off" -ex "r" --args $exe_path $bootstrap_args;; - *) echo "unknown: $OSTYPE" ;; -esac diff --git a/project.sh b/project.sh new file mode 100755 index 0000000..09513f9 --- /dev/null +++ b/project.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e +mkdir -p build +clang -o build/build bootstrap/build.c -O3 -march=native -std=gnu2x -Wall -Wextra -Wpedantic -Wno-nested-anon-types -Wno-keyword-macro -Wno-gnu-auto-type -Wno-auto-decl-extensions -Wno-gnu-empty-initializer -Wno-fixed-enum-extension -pedantic -fno-exceptions -fno-stack-protector +build/build $@ diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index 78d3be3..0000000 --- a/run_tests.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash - -set -e -source ./compile.sh -all=$1 -all=$1 -build_dir="build" -base_exe_name="nest" -debug_flags="-g" -no_optimization_flags="" -test_names=( - "first" - "add_sub" - "mul" - "div" - "and" - "or" - "xor" - "return_var" - "return_mod_scope" - "shift_left" - "shift_right" - "thousand_simple_functions" - "simple_arg" -) - -if [ "$all" == "1" ] -then - optimization_modes=("-O0" "-O1" "-O2" "-Os" "-Oz" "-O3") - case "$OSTYPE" in - darwin*) linking_modes=("0") ;; - linux*) linking_modes=("0" "1") ;; - *) echo "unknown: $OSTYPE"; exit 1 ;; - esac - execution_engines=("c" "i") -else - optimization_modes=("-O0") - case "$OSTYPE" in - darwin*) linking_modes=("0") ;; - linux*) linking_modes=("1") ;; - *) echo "unknown: $OSTYPE"; exit 1 ;; - esac - execution_engines=("i") -fi - -for linking_mode in "${linking_modes[@]}" -do - for optimization_mode in "${optimization_modes[@]}" - do - printf "\n===========================\n" - echo "TESTS (STATIC=$linking_mode, $optimization_mode)" - printf "===========================\n\n" - - exe_name="${base_exe_name}_${optimization_mode}_$linking_mode" - compile $build_dir $exe_name $debug_flags $optimization_mode $linking_mode; - - printf "\n===========================\n" - echo "COMPILER BUILD OK" - printf "===========================\n\n" - - for test_name in "${test_names[@]}" - do - printf "\n===========================\n" - echo "$test_name..." - printf "===========================\n\n" - - for execution_engine in "${execution_engines[@]}" - do - cmd="build/$exe_name tests/$test_name.nat $execution_engine" - echo "Run command: $cmd" - eval "$cmd" - printf "\n===========================\n" - echo "$test_name [COMPILATION] [EXECUTION ENGINE: $execution_engine] [OK]" - printf "===========================\n\n" - - if [ "$execution_engine" != "i" ] - then - nest/$test_name - fi - - printf "\n===========================\n" - echo "$test_name [RUN] [OK]" - printf "===========================\n\n" - done - done - done -done -