kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

core.c (5787B)


      1 /* Compiler lifecycle, panic, and cleanup-stack machinery. */
      2 
      3 #include "core/core.h"
      4 
      5 #include <stdarg.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 
      9 #include "abi/abi.h"
     10 #include "api/lang_registry.h"
     11 #include "core/arena.h"
     12 #include "core/diag.h"
     13 #include "core/heap.h"
     14 #include "core/pool.h"
     15 
     16 #if defined(__GNUC__) || defined(__clang__) || defined(__kit__)
     17 __attribute__((weak))
     18 #endif
     19 void kit_debug_printf(const char* fmt, ...) {
     20   (void)fmt;
     21 }
     22 
     23 #if defined(__GNUC__) || defined(__clang__) || defined(__kit__)
     24 __attribute__((weak))
     25 #endif
     26 const char* kit_debug_getenv(const char* name) {
     27   (void)name;
     28   return NULL;
     29 }
     30 
     31 /* Weak fallbacks for the tracing seam (kit/trace.h). libkit holds no trace
     32  * state, so the library-side gate is always closed and the sink is a no-op;
     33  * hosted binaries (driver/env) override both with the KIT_TRACE-driven
     34  * implementation. */
     35 #if defined(__GNUC__) || defined(__clang__) || defined(__kit__)
     36 __attribute__((weak))
     37 #endif
     38 int kit_trace_enabled(const char* module, int level) {
     39   (void)module;
     40   (void)level;
     41   return 0;
     42 }
     43 
     44 #if defined(__GNUC__) || defined(__clang__) || defined(__kit__)
     45 __attribute__((weak))
     46 #endif
     47 void kit_trace_emit(const char* module, int level, const char* file, int line,
     48                     const char* fmt, ...) {
     49   (void)module;
     50   (void)level;
     51   (void)file;
     52   (void)line;
     53   (void)fmt;
     54 }
     55 
     56 /* Weak fallback for the <assert.h> failure hook (rt/include/assert.h). kit's
     57  * own code uses compiler_panic, not C assert(), but vendored code compiled into
     58  * libkit (the lz4 codecs) references __kit_assert_fail in non-NDEBUG builds.
     59  * A hidden weak trap lets every libkit.a consumer -- the kit binary, the
     60  * test harnesses that link the archive directly, a standalone embedder --
     61  * resolve it without pulling in the runtime. Hidden (the -fvisibility=hidden
     62  * default, NOT visibility-default) keeps it off libkit's public export
     63  * surface that scripts/lib_reloc_defined_prefixes.py guards. The freestanding
     64  * runtime ships its own weak __kit_assert_fail (rt/lib/assert) for programs
     65  * that link it. The contract is _Noreturn, so trap rather than return. */
     66 #if defined(__GNUC__) || defined(__clang__) || defined(__kit__)
     67 __attribute__((weak))
     68 #endif
     69 void __kit_assert_fail(const char* expr, const char* file, int line,
     70                        const char* func) {
     71   (void)expr;
     72   (void)file;
     73   (void)line;
     74   (void)func;
     75   __builtin_trap();
     76   for (;;) {
     77   }
     78 }
     79 
     80 SourceManager* source_new(Compiler*);
     81 void source_free(SourceManager*);
     82 
     83 struct CompilerCleanup {
     84   void (*fn)(void*);
     85   void* arg;
     86   CompilerCleanup* prev;
     87 };
     88 
     89 KitStatus compiler_init(Compiler* c, const KitTarget* target,
     90                         const KitContext* ctx) {
     91   Heap* h = ctx->heap;
     92 
     93   if (!c || !target || !ctx || !h) return KIT_INVALID;
     94   memset(c, 0, sizeof(*c));
     95   c->ctx = ctx;
     96   c->target_ref = target;
     97   c->target = target->spec;
     98 
     99   c->global = (Pool*)h->alloc(h, sizeof(Pool), _Alignof(Pool));
    100   if (!c->global) goto nomem;
    101   pool_init(c->global, h);
    102 
    103   c->tu = (Arena*)h->alloc(h, sizeof(Arena), _Alignof(Arena));
    104   if (!c->tu) goto nomem;
    105   arena_init(c->tu, h, 0);
    106 
    107   c->scratch = (Arena*)h->alloc(h, sizeof(Arena), _Alignof(Arena));
    108   if (!c->scratch) goto nomem;
    109   arena_init(c->scratch, h, 0);
    110 
    111   c->sources = source_new(c);
    112   if (!c->sources) goto nomem;
    113 
    114   c->abi = abi_new(c);
    115   if (!c->abi) goto nomem;
    116 
    117   c->cleanup = NULL;
    118 
    119   lang_registry_init(c);
    120   return KIT_OK;
    121 
    122 nomem:
    123   compiler_fini(c);
    124   return KIT_NOMEM;
    125 }
    126 
    127 void compiler_fini(Compiler* c) {
    128   Heap* h = c->ctx->heap;
    129 
    130   compiler_run_cleanups(c);
    131 
    132   if (c->cg_api_free) {
    133     c->cg_api_free(c);
    134     c->cg_api_free = NULL;
    135   }
    136 
    137   if (c->abi) {
    138     abi_free(c->abi);
    139     c->abi = NULL;
    140   }
    141   if (c->sources) source_free(c->sources);
    142   if (c->scratch) {
    143     arena_fini(c->scratch);
    144     h->free(h, c->scratch, sizeof(Arena));
    145   }
    146   if (c->tu) {
    147     arena_fini(c->tu);
    148     h->free(h, c->tu, sizeof(Arena));
    149   }
    150   if (c->global) {
    151     pool_fini(c->global);
    152     h->free(h, c->global, sizeof(Pool));
    153   }
    154   c->global = NULL;
    155   c->tu = c->scratch = NULL;
    156   c->sources = NULL;
    157 }
    158 
    159 CompilerCleanup* compiler_defer(Compiler* c, void (*fn)(void*), void* arg) {
    160   CompilerCleanup* node;
    161   node = (CompilerCleanup*)arena_alloc(c->scratch, sizeof(*node),
    162                                        _Alignof(CompilerCleanup));
    163   if (!node) return NULL;
    164   node->fn = fn;
    165   node->arg = arg;
    166   node->prev = c->cleanup;
    167   c->cleanup = node;
    168   return node;
    169 }
    170 
    171 void compiler_undefer(Compiler* c, CompilerCleanup* node) {
    172   CompilerCleanup** link = &c->cleanup;
    173   while (*link) {
    174     if (*link == node) {
    175       *link = node->prev;
    176       return;
    177     }
    178     link = &(*link)->prev;
    179   }
    180 }
    181 
    182 void compiler_run_cleanups(Compiler* c) {
    183   while (c->cleanup) {
    184     CompilerCleanup* node = c->cleanup;
    185     c->cleanup = node->prev;
    186     node->fn(node->arg);
    187   }
    188 }
    189 
    190 void compiler_panic_push(Compiler* c, PanicFrame* frame) {
    191   frame->prev = c->panic_frame;
    192   c->panic_frame = frame;
    193 }
    194 
    195 void compiler_panic_pop(Compiler* c, PanicFrame* frame) {
    196   PanicFrame** link;
    197   if (!c || !frame) return;
    198   if (c->panic_frame == frame) {
    199     c->panic_frame = frame->prev;
    200     frame->prev = NULL;
    201     return;
    202   }
    203   link = &c->panic_frame;
    204   while (*link) {
    205     if (*link == frame) {
    206       *link = frame->prev;
    207       frame->prev = NULL;
    208       return;
    209     }
    210     link = &(*link)->prev;
    211   }
    212 }
    213 
    214 void compiler_panic(Compiler* c, SrcLoc loc, const char* fmt, ...) {
    215   va_list ap;
    216   va_start(ap, fmt);
    217   compiler_panicv(c, loc, fmt, ap);
    218   va_end(ap);
    219 }
    220 
    221 void compiler_panicv(Compiler* c, SrcLoc loc, const char* fmt, va_list ap) {
    222   if (c->ctx && c->ctx->diag && c->ctx->diag->emit) {
    223     c->ctx->diag->emit(c->ctx->diag, KIT_DIAG_FATAL, loc, fmt, ap);
    224   }
    225   if (c->panic_frame) longjmp(c->panic_frame->env, 1);
    226   longjmp(c->panic, 1);
    227 }