compile.c (22141B)
1 /* libkit's top-level compile entry points. Status-returning shapes 2 * that drive the C, asm, and registered-frontend paths. */ 3 4 #include <kit/compile.h> 5 #include <kit/cg.h> 6 #include <kit/core.h> 7 #include <string.h> 8 9 #include "api/lang_registry.h" 10 #include "arch/arch.h" 11 #include "asm/asm.h" 12 #include "core/core.h" 13 #include "core/heap.h" 14 #include "core/metrics.h" 15 #include "core/pool.h" 16 #include "core/slice.h" 17 #include "obj/obj.h" 18 19 typedef struct AsmFrontend { 20 Compiler* c; 21 } AsmFrontend; 22 23 struct KitFrontend { 24 KitCompiler* c; 25 KitLanguage lang; 26 const KitFrontendVTable* vtable; 27 KitFrontendState* state; 28 }; 29 30 struct KitCompileSession { 31 KitCompiler* c; 32 KitLanguage lang; 33 KitFrontend* frontend; 34 KitFrontendCompileOptions opts; 35 }; 36 37 static KitFrontendState* asm_frontend_new(KitCompiler* c); 38 static KitStatus asm_frontend_compile(KitFrontendState* fe, 39 const KitFrontendCompileOptions* opts, 40 const KitSourceInput* input, 41 KitObjBuilder* out); 42 static void asm_frontend_free(KitFrontendState* fe); 43 44 static const KitSlice asm_extensions[] = {KIT_SLICE_LIT("s")}; 45 /* Canonical `-x` name plus alias; mirrors the driver's "asm"/"s" spellings. */ 46 static const KitSlice asm_names[] = {KIT_SLICE_LIT("asm"), KIT_SLICE_LIT("s")}; 47 48 const KitFrontendVTable kit_asm_frontend_vtable = { 49 asm_frontend_new, 50 NULL, /* compile_cg: asm participates in LTO as an opaque object */ 51 asm_frontend_compile, 52 asm_frontend_free, 53 asm_extensions, 54 (uint32_t)(sizeof asm_extensions / sizeof asm_extensions[0]), 55 asm_names, 56 (uint32_t)(sizeof asm_names / sizeof asm_names[0]), 57 NULL, /* commit: asm has no durable cross-compile state */ 58 NULL, /* abort */ 59 {false, KIT_FRONTEND_LTO_OPAQUE, false}, 60 NULL, /* parse_options: no asm-specific flags */ 61 NULL, /* free_options */ 62 }; 63 64 static _Noreturn void panic_bad_options(Compiler* c, const char* msg) { 65 compiler_panic(c, SRCLOC_NONE, "bad kit options: %.*s", 66 SLICE_ARG(slice_from_cstr(msg))); 67 } 68 69 /* Compare `ext` to `pat` letter-for-letter, lowercasing ASCII A-Z in 70 * the path side so `.S` matches asm's `"s"` entry. `ext` is a borrowed 71 * slice over the path tail; `pat` is the frontend's extension slice. 72 * Returns nonzero on full match. */ 73 static int ext_eq_ci(KitSlice ext, KitSlice pat) { 74 size_t i; 75 if (ext.len != pat.len) return 0; 76 for (i = 0; i < ext.len; ++i) { 77 char a = ext.s[i]; 78 char b = pat.s[i]; 79 if (a >= 'A' && a <= 'Z') a = (char)(a - 'A' + 'a'); 80 if (a != b) return 0; 81 } 82 return 1; 83 } 84 85 /* Resolve `lang`'s frontend vtable: from the compiler's per-instance table 86 * when a compiler is supplied, else from the compile-time default registry so 87 * the language resolvers work with c==NULL (e.g. at CLI arg-parse time, before 88 * a KitCompiler exists). Out-of-range `lang` yields NULL via lang_registry. */ 89 static const KitFrontendVTable* frontend_for(KitCompiler* c, unsigned lang) { 90 if (c) { 91 if (lang >= KIT_LANG_COUNT) return NULL; 92 return c->frontends[lang]; 93 } 94 return lang_registry_vtable((KitLanguage)lang); 95 } 96 97 KitLanguage kit_language_for_path(KitCompiler* c, const char* path) { 98 size_t len; 99 size_t i; 100 KitSlice ext = SLICE_NULL; 101 int have_ext = 0; 102 unsigned lang; 103 104 if (!path) return KIT_LANG_UNKNOWN; 105 for (len = 0; path[len]; ++len) { 106 } 107 /* Strip back to the last `.` after the final `/`. No dot → no 108 * extension → no language claims it. */ 109 i = len; 110 while (i > 0) { 111 --i; 112 if (path[i] == '/') break; 113 if (path[i] == '.') { 114 ext.s = path + i + 1; 115 ext.len = len - (i + 1); 116 have_ext = 1; 117 break; 118 } 119 } 120 if (!have_ext) return KIT_LANG_UNKNOWN; 121 122 for (lang = 0; lang < KIT_LANG_COUNT; ++lang) { 123 const KitFrontendVTable* v = frontend_for(c, lang); 124 uint32_t e; 125 if (!v || !v->extensions) continue; 126 for (e = 0; e < v->nextensions; ++e) { 127 if (ext_eq_ci(ext, v->extensions[e])) return (KitLanguage)lang; 128 } 129 } 130 /* No registered frontend claims this extension. C is not special — it does 131 * not absorb unrecognized inputs. */ 132 return KIT_LANG_UNKNOWN; 133 } 134 135 /* Compare a NUL-terminated name to a frontend's name slice, byte-for-byte 136 * (case-sensitive, mirroring the driver's exact `-x` spellings). Returns 137 * nonzero on a full match. */ 138 static int name_eq(const char* name, KitSlice pat) { 139 size_t i; 140 for (i = 0; i < pat.len; ++i) { 141 if (name[i] == '\0' || name[i] != pat.s[i]) return 0; 142 } 143 return name[pat.len] == '\0'; 144 } 145 146 KitLanguage kit_language_for_name(KitCompiler* c, const char* name) { 147 unsigned lang; 148 if (!name) return KIT_LANG_UNKNOWN; 149 for (lang = 0; lang < KIT_LANG_COUNT; ++lang) { 150 const KitFrontendVTable* v = frontend_for(c, lang); 151 uint32_t n; 152 if (!v || !v->names) continue; 153 for (n = 0; n < v->nnames; ++n) { 154 if (name_eq(name, v->names[n])) return (KitLanguage)lang; 155 } 156 } 157 return KIT_LANG_UNKNOWN; 158 } 159 160 const char* kit_language_name(KitCompiler* c, KitLanguage lang) { 161 const KitFrontendVTable* v; 162 if ((unsigned)lang >= KIT_LANG_COUNT) return NULL; 163 v = frontend_for(c, (unsigned)lang); 164 if (!v || !v->names || v->nnames == 0) return NULL; 165 /* The first name is the canonical one. Name tables are KIT_SLICE_LIT over 166 * string literals, so the slice's bytes are NUL-terminated just past .len. */ 167 return v->names[0].s; 168 } 169 170 const char* kit_language_default_extension(KitCompiler* c, KitLanguage lang) { 171 const KitFrontendVTable* v; 172 if ((unsigned)lang >= KIT_LANG_COUNT) return NULL; 173 v = frontend_for(c, (unsigned)lang); 174 if (!v || !v->extensions || v->nextensions == 0) return NULL; 175 /* The first extension is the canonical one. Extension tables are 176 * KIT_SLICE_LIT over string literals, so the slice's bytes are 177 * NUL-terminated just past .len. */ 178 return v->extensions[0].s; 179 } 180 181 KitStatus kit_register_frontend(KitCompiler* c, KitLanguage lang, 182 const KitFrontendVTable* vtable) { 183 if (!c) return KIT_INVALID; 184 if ((unsigned)lang >= KIT_LANG_COUNT) return KIT_INVALID; 185 if (vtable) { 186 uint8_t mode = vtable->caps.lto_mode; 187 if (!vtable->new_frontend || !vtable->free_frontend || 188 mode > KIT_FRONTEND_LTO_OPAQUE) { 189 return KIT_INVALID; 190 } 191 if (mode == KIT_FRONTEND_LTO_CG) { 192 if (!vtable->compile_cg) return KIT_INVALID; 193 } else if (!vtable->compile_obj) { 194 return KIT_INVALID; 195 } 196 } 197 c->frontends[lang] = vtable; 198 return KIT_OK; 199 } 200 201 KitStatus kit_frontend_caps(KitCompiler* c, KitLanguage lang, 202 KitFrontendCaps* out) { 203 const KitFrontendVTable* v; 204 if (!c || !out || (unsigned)lang >= KIT_LANG_COUNT) return KIT_INVALID; 205 v = c->frontends[lang]; 206 if (!v) return KIT_INVALID; 207 *out = v->caps; 208 return KIT_OK; 209 } 210 211 KitStatus kit_frontend_parse_options(KitCompiler* c, KitLanguage lang, int argc, 212 char** argv, void** out_opts) { 213 const KitFrontendVTable* v; 214 if (out_opts) *out_opts = NULL; 215 if (!c || !out_opts || (unsigned)lang >= KIT_LANG_COUNT) return KIT_INVALID; 216 v = c->frontends[lang]; 217 if (!v || !v->parse_options) return KIT_INVALID; 218 return v->parse_options(c, argc, argv, out_opts); 219 } 220 221 void kit_frontend_free_options(KitCompiler* c, KitLanguage lang, void* opts) { 222 const KitFrontendVTable* v; 223 if (!c || !opts || (unsigned)lang >= KIT_LANG_COUNT) return; 224 v = c->frontends[lang]; 225 if (v && v->free_options) v->free_options(c, opts); 226 } 227 228 uint32_t kit_compiler_arch_predefines(KitCompiler* c, 229 const KitPredefinedMacro** out) { 230 const ArchImpl* arch; 231 if (out) *out = NULL; 232 if (!c) return 0; 233 arch = arch_for_compiler((Compiler*)c); 234 if (!arch || !arch->predefined_macros || arch->npredefined_macros == 0) 235 return 0; 236 if (out) *out = arch->predefined_macros; 237 return arch->npredefined_macros; 238 } 239 240 static void validate_bytes(Compiler* c, const KitSourceInput* in) { 241 if (!in->name.s) panic_bad_options(c, "input name is NULL"); 242 if (!in->bytes.data && in->bytes.len != 0) { 243 panic_bad_options(c, "input data is NULL but len > 0"); 244 } 245 } 246 247 static const KitFrontendVTable* frontend_for_language(Compiler* c, 248 KitLanguage lang) { 249 if ((unsigned)lang >= KIT_LANG_COUNT) return NULL; 250 return c->frontends[lang]; 251 } 252 253 static KitStatus compile_obj_finalize(Compiler* c, ObjBuilder* ob); 254 static KitStatus compile_frontend_state_obj_into( 255 Compiler* c, const KitFrontendVTable* vtable, KitFrontendState* frontend, 256 const KitFrontendCompileOptions* opts, const KitSourceInput* input, 257 ObjBuilder* ob); 258 259 static KitStatus kit_frontend_new(KitCompiler* c, KitLanguage lang, 260 KitFrontend** out) { 261 const KitFrontendVTable* vtable; 262 KitFrontendState* state; 263 KitFrontend* frontend; 264 Heap* h; 265 266 if (!out) return KIT_INVALID; 267 *out = NULL; 268 if (!c || (unsigned)lang >= KIT_LANG_COUNT) return KIT_INVALID; 269 vtable = frontend_for_language((Compiler*)c, lang); 270 if (!vtable) return KIT_UNSUPPORTED; 271 state = vtable->new_frontend(c); 272 if (!state) return KIT_NOMEM; 273 h = (Heap*)c->ctx->heap; 274 frontend = 275 (KitFrontend*)h->alloc(h, sizeof(*frontend), _Alignof(KitFrontend)); 276 if (!frontend) { 277 vtable->free_frontend(state); 278 return KIT_NOMEM; 279 } 280 frontend->c = c; 281 frontend->lang = lang; 282 frontend->vtable = vtable; 283 frontend->state = state; 284 *out = frontend; 285 return KIT_OK; 286 } 287 288 static void kit_frontend_commit(KitFrontend* frontend) { 289 if (frontend && frontend->vtable && frontend->vtable->commit) { 290 frontend->vtable->commit(frontend->state); 291 } 292 } 293 294 static void kit_frontend_abort(KitFrontend* frontend) { 295 if (frontend && frontend->vtable && frontend->vtable->abort) { 296 frontend->vtable->abort(frontend->state); 297 } 298 } 299 300 static KitStatus kit_frontend_compile_obj(KitFrontend* frontend, 301 const KitFrontendCompileOptions* opts, 302 const KitSourceInput* input, 303 KitObjBuilder* out) { 304 Compiler* c; 305 PanicFrame panic; 306 KitStatus st; 307 308 if (!frontend || !frontend->c || !frontend->vtable || !frontend->state || 309 !opts || !input || !out) { 310 return KIT_INVALID; 311 } 312 if (input->lang != frontend->lang) return KIT_INVALID; 313 if (!frontend->vtable->compile_obj) return KIT_UNSUPPORTED; 314 c = (Compiler*)frontend->c; 315 compiler_panic_push(c, &panic); 316 if (setjmp(panic.env)) { 317 /* A genuine internal panic (CG/backend) longjmp'd here. Run cleanups, then 318 * roll back any durable frontend state staged during this compile, and 319 * propagate as a soft error. Ordinary diagnostic failures do NOT take this 320 * path: the frontend returns KIT_ERR below without panicking. */ 321 compiler_run_cleanups(c); 322 kit_frontend_abort(frontend); 323 compiler_panic_pop(c, &panic); 324 return KIT_ERR; 325 } 326 validate_bytes(c, input); 327 metrics_scope_begin(c, "compile.tu"); 328 metrics_count(c, "compile.input_bytes", (u64)input->bytes.len); 329 st = compile_frontend_state_obj_into(c, frontend->vtable, frontend->state, 330 opts, input, (ObjBuilder*)out); 331 metrics_scope_end(c, "compile.tu"); 332 /* On a soft diagnostic failure, roll back the staged transaction here so the 333 * frontend is left exactly as it was before this compile. On success the 334 * transaction is left open for the caller to commit or abort. */ 335 if (st != KIT_OK) kit_frontend_abort(frontend); 336 compiler_panic_pop(c, &panic); 337 return st; 338 } 339 340 static KitStatus kit_frontend_compile_cg(KitFrontend* frontend, 341 const KitFrontendCompileOptions* opts, 342 const KitSourceInput* input, 343 KitCg* cg) { 344 Compiler* c; 345 PanicFrame panic; 346 KitStatus st; 347 348 if (!frontend || !frontend->c || !frontend->vtable || !frontend->state || 349 !opts || !input || !cg) { 350 return KIT_INVALID; 351 } 352 if (input->lang != frontend->lang) return KIT_INVALID; 353 if (frontend->vtable->caps.lto_mode != KIT_FRONTEND_LTO_CG || 354 !frontend->vtable->compile_cg) { 355 return KIT_UNSUPPORTED; 356 } 357 c = (Compiler*)frontend->c; 358 compiler_panic_push(c, &panic); 359 if (setjmp(panic.env)) { 360 compiler_run_cleanups(c); 361 kit_frontend_abort(frontend); 362 compiler_panic_pop(c, &panic); 363 return KIT_ERR; 364 } 365 validate_bytes(c, input); 366 metrics_scope_begin(c, "compile.tu"); 367 metrics_count(c, "compile.input_bytes", (u64)input->bytes.len); 368 metrics_scope_begin(c, "compile.frontend"); 369 st = frontend->vtable->compile_cg(frontend->state, opts, input, cg); 370 metrics_scope_end(c, "compile.frontend"); 371 metrics_scope_end(c, "compile.tu"); 372 if (st != KIT_OK) kit_frontend_abort(frontend); 373 compiler_panic_pop(c, &panic); 374 return st; 375 } 376 377 static void kit_frontend_free(KitFrontend* frontend) { 378 Heap* h; 379 if (!frontend) return; 380 if (frontend->vtable && frontend->state) { 381 frontend->vtable->free_frontend(frontend->state); 382 } 383 h = (Heap*)frontend->c->ctx->heap; 384 h->free(h, frontend, sizeof(*frontend)); 385 } 386 387 KitStatus kit_compile_session_new(KitCompiler* c, 388 const KitCompileSessionOptions* opts, 389 KitCompileSession** out) { 390 KitCompileSession* s; 391 KitFrontend* frontend = NULL; 392 KitStatus st; 393 Heap* h; 394 395 if (!out) return KIT_INVALID; 396 *out = NULL; 397 if (!c || !opts || (unsigned)opts->lang >= KIT_LANG_COUNT) return KIT_INVALID; 398 st = kit_frontend_new(c, opts->lang, &frontend); 399 if (st != KIT_OK) return st; 400 h = (Heap*)c->ctx->heap; 401 s = (KitCompileSession*)h->alloc(h, sizeof(*s), _Alignof(KitCompileSession)); 402 if (!s) { 403 kit_frontend_free(frontend); 404 return KIT_NOMEM; 405 } 406 memset(s, 0, sizeof(*s)); 407 s->c = c; 408 s->lang = opts->lang; 409 s->frontend = frontend; 410 s->opts = opts->compile; 411 *out = s; 412 return KIT_OK; 413 } 414 415 /* Shared object-producing compile path. Opaque frontends compile directly into 416 * the object builder; semantic frontends use the same borrowed KitCg lifecycle 417 * as LTO with a single source unit. On failure the frontend transaction is 418 * rolled back and *out is NULL. On success, when commit_on_success is set (the 419 * batch path), the transaction is committed before returning; otherwise it is 420 * left open for the caller to resolve. */ 421 static KitStatus compile_session_run(KitCompileSession* s, 422 const KitSourceInput* input, 423 KitObjBuilder** out, 424 int commit_on_success) { 425 ObjBuilder* ob; 426 KitFrontendCompileOptions opts; 427 KitStatus st; 428 429 if (!out) return KIT_INVALID; 430 *out = NULL; 431 if (!s || !s->c || !s->frontend || !input) return KIT_INVALID; 432 if (input->lang != s->lang) return KIT_INVALID; 433 ob = obj_new((Compiler*)s->c); 434 if (!ob) return KIT_NOMEM; 435 opts = s->opts; 436 opts.input_kind = input->input_kind; 437 opts.repl_entry_name = input->repl_entry_name; 438 if (s->frontend->vtable->caps.lto_mode == KIT_FRONTEND_LTO_CG) { 439 KitCg* cg = NULL; 440 KitCgUnitOptions uopts; 441 st = kit_cg_new(s->c, &cg); 442 if (st == KIT_OK) st = kit_cg_begin(cg, (KitObjBuilder*)ob, &opts.code); 443 memset(&uopts, 0, sizeof uopts); 444 uopts.source_name = input->name; 445 if (st == KIT_OK) st = kit_cg_begin_unit(cg, &uopts); 446 if (st == KIT_OK) 447 st = kit_frontend_compile_cg(s->frontend, &opts, input, cg); 448 if (st == KIT_OK) st = kit_cg_end_unit(cg); 449 if (st == KIT_OK) st = kit_cg_finish(cg, NULL); 450 if (st == KIT_OK) st = kit_cg_detach(cg); 451 kit_cg_free(cg); 452 if (st == KIT_OK) st = compile_obj_finalize((Compiler*)s->c, ob); 453 } else { 454 st = kit_frontend_compile_obj(s->frontend, &opts, input, 455 (KitObjBuilder*)ob); 456 } 457 if (st != KIT_OK) { 458 kit_frontend_abort(s->frontend); 459 obj_free(ob); 460 return st; 461 } 462 if (commit_on_success) kit_frontend_commit(s->frontend); 463 *out = (KitObjBuilder*)ob; 464 return KIT_OK; 465 } 466 467 KitStatus kit_compile_session_compile(KitCompileSession* s, 468 const KitSourceInput* input, 469 KitObjBuilder** out) { 470 return compile_session_run(s, input, out, /*commit_on_success=*/1); 471 } 472 473 KitStatus kit_compile_session_compile_cg(KitCompileSession* s, 474 const KitSourceInput* input, 475 KitCg* cg) { 476 KitFrontendCompileOptions opts; 477 KitStatus st; 478 int unit_open = 0; 479 480 if (!s || !s->c || !s->frontend || !input || !cg) return KIT_INVALID; 481 if (input->lang != s->lang) return KIT_INVALID; 482 opts = s->opts; 483 opts.input_kind = input->input_kind; 484 opts.repl_entry_name = input->repl_entry_name; 485 { 486 KitCgUnitOptions uopts; 487 memset(&uopts, 0, sizeof uopts); 488 uopts.source_name = input->name; 489 st = kit_cg_begin_unit(cg, &uopts); 490 } 491 if (st == KIT_OK) unit_open = 1; 492 if (st == KIT_OK) st = kit_frontend_compile_cg(s->frontend, &opts, input, cg); 493 if (st == KIT_OK) st = kit_cg_end_unit(cg); 494 if (st == KIT_OK) { 495 unit_open = 0; 496 kit_frontend_commit(s->frontend); 497 } else if (unit_open) { 498 (void)kit_cg_abort(cg); 499 } 500 return st; 501 } 502 503 KitStatus kit_compile_session_stage(KitCompileSession* s, 504 const KitSourceInput* input, 505 KitObjBuilder** out) { 506 return compile_session_run(s, input, out, /*commit_on_success=*/0); 507 } 508 509 void kit_compile_session_commit(KitCompileSession* s) { 510 if (s && s->frontend) kit_frontend_commit(s->frontend); 511 } 512 513 void kit_compile_session_abort(KitCompileSession* s) { 514 if (s && s->frontend) kit_frontend_abort(s->frontend); 515 } 516 517 void kit_compile_session_free(KitCompileSession* s) { 518 Heap* h; 519 if (!s) return; 520 h = (Heap*)s->c->ctx->heap; 521 kit_frontend_free(s->frontend); 522 h->free(h, s, sizeof(*s)); 523 } 524 525 static KitStatus compile_obj_finalize(Compiler* c, ObjBuilder* ob) { 526 metrics_scope_begin(c, "compile.obj_finalize"); 527 obj_finalize(ob); 528 metrics_scope_end(c, "compile.obj_finalize"); 529 metrics_count(c, "compile.obj_sections", obj_section_count(ob)); 530 metrics_count(c, "compile.obj_relocs", obj_reloc_total(ob)); 531 return KIT_OK; 532 } 533 534 static KitStatus compile_frontend_state_obj_into( 535 Compiler* c, const KitFrontendVTable* vtable, KitFrontendState* frontend, 536 const KitFrontendCompileOptions* opts, const KitSourceInput* input, 537 ObjBuilder* ob) { 538 KitStatus st; 539 540 metrics_scope_begin(c, "compile.frontend"); 541 st = vtable->compile_obj(frontend, opts, input, ob); 542 metrics_scope_end(c, "compile.frontend"); 543 /* Ordinary diagnostic failure: fail softly with the status the frontend 544 * already reported. No synthetic fatal, and do not finalize a half-built 545 * object. Genuine internal failures panic from inside compile_obj and 546 * never reach here. */ 547 if (st != KIT_OK) return st; 548 return compile_obj_finalize(c, ob); 549 } 550 551 /* ============================================================ 552 * Asm 553 * ============================================================ */ 554 555 static KitFrontendState* asm_frontend_new(KitCompiler* c) { 556 Heap* h; 557 AsmFrontend* fe; 558 if (!c) return NULL; 559 h = (Heap*)c->ctx->heap; 560 fe = (AsmFrontend*)h->alloc(h, sizeof(*fe), _Alignof(AsmFrontend)); 561 if (!fe) return NULL; 562 fe->c = c; 563 return (KitFrontendState*)fe; 564 } 565 566 static KitStatus asm_frontend_compile(KitFrontendState* frontend, 567 const KitFrontendCompileOptions* opts, 568 const KitSourceInput* input, 569 KitObjBuilder* out) { 570 AsmFrontend* fe = (AsmFrontend*)frontend; 571 Compiler* c; 572 AsmLexer* lex; 573 MCEmitter* mc; 574 (void)opts; 575 if (!fe || !fe->c || !input || !out) return KIT_INVALID; 576 c = fe->c; 577 metrics_scope_begin(c, "compile.asm.lex_open"); 578 lex = asm_lex_open_mem(c, input->name.s, input->bytes.s, input->bytes.len); 579 metrics_scope_end(c, "compile.asm.lex_open"); 580 metrics_scope_begin(c, "compile.asm.mc_new"); 581 mc = mc_new(c, (ObjBuilder*)out); 582 metrics_scope_end(c, "compile.asm.mc_new"); 583 metrics_scope_begin(c, "compile.asm.parse"); 584 asm_parse(c, lex, mc); 585 metrics_scope_end(c, "compile.asm.parse"); 586 metrics_scope_begin(c, "compile.asm.mc_free"); 587 mc_free(mc); 588 metrics_scope_end(c, "compile.asm.mc_free"); 589 return KIT_OK; 590 } 591 592 static void asm_frontend_free(KitFrontendState* frontend) { 593 AsmFrontend* fe = (AsmFrontend*)frontend; 594 Heap* h; 595 if (!fe) return; 596 h = fe->c->ctx->heap; 597 h->free(h, fe, sizeof(*fe)); 598 } 599 600 struct KitDepIter { 601 Compiler* c; 602 SourceDepIter* inner; 603 }; 604 605 KitStatus kit_dep_iter_new(KitCompiler* c, KitDepIter** out) { 606 Heap* h; 607 KitDepIter* it; 608 if (!out) return KIT_INVALID; 609 if (!c || !c->sources) return KIT_INVALID; 610 h = c->ctx->heap; 611 it = (KitDepIter*)h->alloc(h, sizeof(*it), _Alignof(KitDepIter)); 612 if (!it) return KIT_NOMEM; 613 it->c = c; 614 it->inner = source_depiter_new(c->sources); 615 if (!it->inner) { 616 h->free(h, it, sizeof(*it)); 617 return KIT_NOMEM; 618 } 619 *out = it; 620 return KIT_OK; 621 } 622 623 KitIterResult kit_dep_iter_next(KitDepIter* it, KitDepEdge* out) { 624 const SourceInclude* edge; 625 const SourceFile* includer; 626 const SourceFile* included; 627 if (!it || !out) return KIT_ITER_ERROR; 628 edge = source_depiter_next(it->inner); 629 if (!edge) return KIT_ITER_END; 630 includer = source_file(it->c->sources, edge->includer_file_id); 631 included = source_file(it->c->sources, edge->included_file_id); 632 out->includer_name = 633 includer ? pool_slice(it->c->global, includer->name) : KIT_SLICE_NULL; 634 out->included_name = 635 included ? pool_slice(it->c->global, included->name) : KIT_SLICE_NULL; 636 out->include_loc = edge->include_loc; 637 out->from_system_path = (uint8_t)(edge->system ? 1 : 0); 638 out->bracketed = (uint8_t)(edge->system ? 1 : 0); 639 out->pad[0] = 0; 640 out->pad[1] = 0; 641 return KIT_ITER_ITEM; 642 } 643 644 void kit_dep_iter_free(KitDepIter* it) { 645 Heap* h; 646 if (!it) return; 647 h = it->c->ctx->heap; 648 if (it->inner) source_depiter_free(it->inner); 649 h->free(h, it, sizeof(*it)); 650 }