kit

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

commit b998131d3551a570801f5028d6f55683a4cdac69
parent 572b0bbeeaeb5e30e79c8fcb5cdacd298a1de11a
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 21 May 2026 13:37:11 -0700

Align compile link and JIT session APIs

Diffstat:
Mdoc/FRONTEND.md | 307++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mdriver/as.c | 33+++++++++++++++++++++++++--------
Mdriver/cc.c | 242+++++++++++++++++++++++++++++++++++--------------------------------------------
Mdriver/dbg.c | 1260+++++++++++++++++++++++++++++++++++++------------------------------------------
Mdriver/inputs.c | 198++++++++++++++++++++++++++++++++++++-------------------------------------------
Mdriver/ld.c | 123++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mdriver/runtime.c | 40++++++++++++++++++++++++++++++++++++++--
Minclude/cfree/cg.h | 124++++++++++++++++++++++++++++++++++++++++----------------------------------------
Minclude/cfree/compile.h | 91++++++++++++++++++++++++++++++++++++++-----------------------------------------
Minclude/cfree/core.h | 96++++++++++++++++++++++++++++++++++++++++---------------------------------------
Minclude/cfree/jit.h | 72++++++++++++++++++++++++++++++++++++++++++++----------------------------
Minclude/cfree/link.h | 138++++++++++++++++++++++++++++++++++++-------------------------------------------
Mlang/c/c.c | 10+++++-----
Mlang/toy/compile.c | 26+++++++++++++-------------
Mlang/wasm/cg.c | 88++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/api/compile.c | 297++++++++++++++++++++-----------------------------------------------------------
Msrc/api/link.c | 449++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/cg/internal.h | 6++++--
Msrc/cg/session.c | 135++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/emu/emu.c | 3++-
Msrc/link/link.h | 14++++++++++++++
Msrc/link/link_jit.c | 850+++++++++++++++++++++++++++++++++++--------------------------------------------
Mtest/api/cg_switch_test.c | 12++++++------
Mtest/api/cg_type_test.c | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mtest/asm/harness/asm_runner.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mtest/link/harness/jit_runner.c | 29+++++++++++++++++++----------
Mtest/link/harness/link_exe_runner.c | 33++++++++++++++++++++-------------
Mtest/parse/harness/parse_runner.c | 98++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
28 files changed, 2562 insertions(+), 2477 deletions(-)

diff --git a/doc/FRONTEND.md b/doc/FRONTEND.md @@ -1,30 +1,61 @@ # Interactive Frontend REPL -This document tracks the work needed to make `cfree dbg` an ergonomic, -interactive REPL for registered source frontends. The goal is not just "append a -new object"; snippets must share language context, compile quickly, and make -bare expression input feel native for Toy, C, and Wasm. +This document tracks the current source-frontend REPL shape and the remaining +work to make `cfree dbg` a full interactive compile/link/publish environment. +The immediate API direction is stateful handles at each layer: + +- `CfreeCompileSession` owns frontend state for one source language. +- `CfreeCg` owns reusable codegen metadata and binds one object delta at a time. +- `CfreeLinkSession` owns linker inputs and resolution state. +- `CfreeJit` owns the live executable image and publishes resolved deltas. + +One-shot public compile/link/JIT append APIs are being removed. Callers should +create sessions, add inputs, resolve or publish, and then free the sessions. ## Current State -- [x] Frontend registration uses a lifecycle vtable: +- [x] Registered frontends use the lifecycle vtable `new_frontend`, `compile`, `free_frontend`. -- [x] Public source frontend instances are explicit: - `cfree_frontend_new`, `cfree_frontend_compile`, `cfree_frontend_free`. -- [x] `cfree_compile_source_obj{,_emit}` has been removed. Callers now create a - `CfreeObjBuilder`, compile through a frontend instance, and emit/link the - resulting object explicitly. -- [x] `driver/cc.c`, `driver/inputs.c`, and `driver/dbg.c` have been migrated to - the new frontend instance API. -- [x] `driver/dbg.c` keeps frontend instances alive across `jit` snippets. -- [x] `cfree dbg` can start from an empty JIT image, with the REPL language set - by `-x LANG` / `--language LANG` or by `:language` after startup. -- [ ] C and Wasm frontend implementations still allocate parser/CG state per - compile; Toy keeps parser state but still creates CG state per compile. -- [x] `driver/dbg.c` no longer fabricates language-specific expression source; - selected frontends own REPL expression/block wrapping. -- [x] Bare REPL input uses the selected frontend-specific expression/thunk - fallback for Toy. +- [x] Public source compilation goes through `CfreeCompileSession`: + `cfree_compile_session_new`, `cfree_compile_session_compile`, + `cfree_compile_session_free`. +- [x] Public one-shot source APIs such as `cfree_compile_c_obj`, + `cfree_compile_c_emit`, `cfree_compile_asm_obj`, and + `cfree_compile_asm_emit` have been removed. +- [x] `CfreeSourceInput` carries per-delta REPL shape: + `input_kind` and `repl_entry_name`. +- [x] `CfreeCompileSessionOptions` keeps fixed session options: + language, code options, diagnostics, and language-specific options. +- [x] `CfreeCg` is reusable across object deltas with + `cfree_cg_begin_obj` and `cfree_cg_end_obj`. +- [x] `CfreeLinkSession` is public and owns link inputs plus resolve/emit/JIT + operations. +- [x] Public one-shot link APIs have been removed; drivers and tests create + `CfreeLinkSession` directly. +- [x] Public JIT append is `cfree_jit_publish`. The v1 publish mode supports + append-object batches through a `CfreeLinkSession`. +- [x] `driver/cc.c`, `driver/as.c`, `driver/ld.c`, `driver/inputs.c`, + `driver/runtime.c`, `driver/dbg.c`, and the active harnesses have been + migrated to session APIs. +- [x] `cfree dbg` can start from an empty JIT image. The default REPL language + is selected by `-x LANG` / `--language LANG` or changed with `:language`. +- [x] `driver/dbg.c` caches `CfreeCompileSession*` per language for snippets + typed during the REPL. +- [x] `driver/dbg.c` publishes snippets by creating a temporary + `CfreeLinkSession`, adding the object delta, and calling `cfree_jit_publish`. +- [x] Toy supports top-level snippets, bare expression wrappers, block wrappers, + persistent globals, persistent functions, and persistent nominal types across + REPL snippets. +- [x] Scripted driver tests cover the Toy REPL append/expression path. +- [ ] Initial source files passed to `cfree dbg` are not yet used to seed the + cached per-language `CfreeCompileSession`, so REPL expressions do not have + source-frontend declarations from those initial files. +- [ ] C and Wasm still need true interactive frontend state. C currently owns + parser/preprocessor/declaration state per compile; Wasm is still module-shaped. +- [ ] `CfreeLinkSession` is session-shaped, but incremental watermarks, + symbol-version policy, and replace/redefine semantics are still skeletal. +- [ ] `cfree_jit_publish` function replacement is shaped in the API but returns + `CFREE_UNSUPPORTED`. ## Target UX @@ -53,39 +84,16 @@ $1 = 9 (0x9) ``` For C and Toy, unrecognized bare input should be the expression/thunk fallback -and should compile a language-native expression wrapper. An explicit `expr` -command can remain as an alias, but it is not the primary workflow. For Wasm, -the natural interactive unit is a module plus explicit export invocation; WAT -expression shortcuts can come later as sugar over generated modules. +and should compile a language-native expression wrapper. The explicit `expr` +command can remain as an alias. For Wasm, the natural interactive unit is a +module plus explicit export invocation; WAT expression shortcuts can come later +as sugar over generated modules. -## Shared Design +## Public API Shape -### Frontend API +### Source Compile -Landed public shape: - -```c -typedef struct CfreeFrontend CfreeFrontend; -typedef struct CfreeFrontendState CfreeFrontendState; - -typedef CfreeFrontendState* (*CfreeFrontendNewFn)(CfreeCompiler*); -typedef CfreeStatus (*CfreeFrontendCompileFn)( - CfreeFrontendState*, - const CfreeFrontendCompileOptions*, - const CfreeSourceInput*, - CfreeObjBuilder*); -typedef void (*CfreeFrontendFreeFn)(CfreeFrontendState*); - -CfreeStatus cfree_frontend_new(CfreeCompiler*, CfreeLanguage, - CfreeFrontend** out); -CfreeStatus cfree_frontend_compile(CfreeFrontend*, - const CfreeFrontendCompileOptions*, - const CfreeSourceInput*, - CfreeObjBuilder* out); -void cfree_frontend_free(CfreeFrontend*); -``` - -Landed REPL compile options: +Current public source compilation: ```c typedef enum CfreeFrontendInputKind { @@ -95,6 +103,13 @@ typedef enum CfreeFrontendInputKind { CFREE_FRONTEND_INPUT_REPL_BLOCK, } CfreeFrontendInputKind; +typedef struct CfreeSourceInput { + CfreeBytes bytes; + CfreeLanguage lang; + CfreeFrontendInputKind input_kind; + const char *repl_entry_name; +} CfreeSourceInput; + typedef struct CfreeFrontendCompileOptions { CfreeCodeOptions code; CfreeDiagnosticOptions diagnostics; @@ -102,50 +117,142 @@ typedef struct CfreeFrontendCompileOptions { CfreeFrontendInputKind input_kind; const char *repl_entry_name; } CfreeFrontendCompileOptions; + +typedef struct CfreeCompileSessionOptions { + CfreeLanguage lang; + CfreeFrontendCompileOptions compile; +} CfreeCompileSessionOptions; + +CfreeStatus cfree_compile_session_new(CfreeCompiler *, + const CfreeCompileSessionOptions *, + CfreeCompileSession **out); +CfreeStatus cfree_compile_session_compile(CfreeCompileSession *, + const CfreeSourceInput *, + CfreeObjBuilder **out); +void cfree_compile_session_free(CfreeCompileSession *); +``` + +`input_kind` and `repl_entry_name` are copied from `CfreeSourceInput` into the +frontend compile options for each delta. This lets a debugger keep one +`CfreeCompileSession` alive while alternating top-level snippets, expression +thunks, and block thunks. + +### Codegen + +Current public codegen lifecycle: + +```c +CfreeStatus cfree_cg_new(CfreeCompiler *, CfreeCg **out); +CfreeStatus cfree_cg_begin_obj(CfreeCg *, CfreeObjBuilder *, + const CfreeCodeOptions *); +CfreeStatus cfree_cg_end_obj(CfreeCg *); +void cfree_cg_free(CfreeCg *); ``` -### Persistent Codegen +`CfreeCg` preserves compiler-level metadata across object deltas. Object-bound +target, MC, and debug state are created by `begin_obj` and finalized by +`end_obj`. -`CfreeCgSym` is still an `ObjSymId`, so a persistent frontend cannot simply keep -old symbol handles while compiling into a new object. The intended bridge is: +Remaining codegen work: -- [ ] Add `cfree_cg_swap_obj(CfreeCg*, CfreeObjBuilder*, const CfreeCodeOptions*)`. -- [ ] On swap, finalize the previous target/MC/debug state before replacing it. -- [ ] Recreate target/MC/debug state for the new object builder. -- [ ] Seed the new object builder with external declarations for all known CG - symbols in the same `ObjSymId` order. -- [ ] Preserve `sym_types`, `sym_attrs`, type ids, readonly-data counters, and - any source-level symbol metadata owned by the frontend. -- [ ] Add focused tests proving a second object can relocate against a symbol - defined by a first JIT-appended object. +- [ ] Define exactly which symbol/type/metadata tables persist across + `begin_obj`/`end_obj` for each frontend. +- [ ] Seed each new object builder with external declarations for all known + frontend symbols that may be referenced by later snippets. +- [ ] Add a focused test proving two objects emitted by one `CfreeCg` can refer + to each other after link/JIT resolution. +- [ ] Audit failed-object cleanup so a failed snippet cannot corrupt the + persistent frontend or CG metadata. -The JIT append path already resolves undefined symbols against the existing -image, so once the new object contains matching undefined symbols, references to -prior snippets should link naturally. +### Link -### Debugger Driver +Current public link lifecycle: -- [x] Add a small per-language frontend cache to `DbgState`. -- [x] Keep the selected language frontend alive for the whole REPL session. -- [x] Compile `jit` snippets by creating a fresh object builder and calling - `cfree_frontend_compile` on the cached frontend. +```c +CfreeStatus cfree_link_session_new(CfreeCompiler *, + const CfreeLinkSessionOptions *, + CfreeLinkSession **out); +CfreeStatus cfree_link_session_add_obj(CfreeLinkSession *, CfreeObjBuilder *); +CfreeStatus cfree_link_session_add_obj_bytes(CfreeLinkSession *, CfreeBytes); +CfreeStatus cfree_link_session_add_archive_bytes(CfreeLinkSession *, + CfreeBytes); +CfreeStatus cfree_link_session_add_dso_bytes(CfreeLinkSession *, CfreeBytes); +CfreeStatus cfree_link_session_resolve(CfreeLinkSession *); +CfreeStatus cfree_link_session_emit(CfreeLinkSession *, CfreeWriter *out); +CfreeStatus cfree_link_session_jit(CfreeLinkSession *, CfreeJit **out_jit); +void cfree_link_session_free(CfreeLinkSession *); +``` + +Remaining link work for a full interactive REPL: + +- [ ] Keep durable symbol-resolution state for incremental sessions instead of + treating each publish as a mostly independent batch. +- [ ] Define duplicate strong symbol policy across REPL generations. +- [ ] Define weak/common/TLS behavior across appended generations. +- [ ] Track generation watermarks so diagnostics can say whether a symbol came + from the initial image or a later snippet. +- [ ] Add tests where a later object resolves references against prior objects, + archives, DSOs, and the initial JIT image. +- [ ] Add negative tests for unresolved symbols, duplicate definitions, and + unsupported relocation modes in interactive publish. + +### JIT Publish + +Current public publish lifecycle: + +```c +typedef enum CfreeJitPublishKind { + CFREE_JIT_PUBLISH_APPEND_OBJECTS, + CFREE_JIT_PUBLISH_REPLACE_SYMBOLS, +} CfreeJitPublishKind; + +typedef struct CfreeJitPublishOptions { + uint8_t kind; + CfreeLinkSession *link; +} CfreeJitPublishOptions; + +typedef struct CfreeJitPublishResult { + uint64_t generation; +} CfreeJitPublishResult; + +CfreeStatus cfree_jit_publish(CfreeJit *, const CfreeJitPublishOptions *, + CfreeJitPublishResult *); +``` + +Remaining publish work: + +- [ ] Implement `CFREE_JIT_PUBLISH_REPLACE_SYMBOLS` or remove it until the + semantics are fully specified. +- [ ] Preserve old symbol addresses for append-only generations and test that + invariant directly. +- [ ] Decide how the debugger should surface symbols shadowed or replaced by a + later generation. +- [ ] Keep DWARF and symbol iteration generation-aware. +- [ ] Add tests that publish increments the JIT generation and keeps old + function pointers callable after new snippets are appended. + +## Debugger Driver + +- [x] Cache `CfreeCompileSession*` per language in `DbgState`. +- [x] Keep cached compile sessions alive for the whole REPL session. - [x] Treat a REPL line beginning with `{` as shorthand for `jit { ... }`. -- [x] Add `:language c|toy|wat|wasm|asm` and make `jit`, explicit `expr`, and - bare fallback input honor the selected language through the frontend vtable. +- [x] Add `:language c|toy|wat|wasm|asm`. +- [x] Make `jit`, explicit `expr`, and bare fallback input honor the selected + language through `CfreeSourceInput.input_kind`. - [x] Add `-x LANG` / `--language LANG` to choose the default REPL language before any source file exists. -- [x] Make `:language` with no argument report the current language and - language options. +- [x] Make `:language` with no argument report the current language and whether + that language has a cached compile session. - [x] Allow an empty initial JIT image; `run` resolves the entry lazily so a later snippet can define `main`. -- [x] Add `input_kind` and `repl_entry_name` wiring for bare expression fallback, - explicit `expr`, and block modes. -- [ ] Seed cached frontend state from initial source-file inputs so REPL - expressions can see declarations compiled before the prompt. -- [x] Remove `dbg_append_expr_prelude` and driver-side C thunk fabrication. -- [ ] Keep DWARF/JIT symbol recovery for external/preexisting code inspection, - not as the normal path for declarations typed during the session. -- [x] Add scripted `dbg` smoke tests that drive stdin and assert output. +- [x] Remove driver-side language-specific thunk fabrication for Toy. Frontends + own REPL expression/block wrapping. +- [ ] Seed cached compile sessions from initial source-file inputs. +- [ ] Reuse or persist link-session state where that is needed for incremental + diagnostics and symbol policy. +- [ ] Keep DWARF/JIT symbol recovery for inspecting external/preexisting code, + not as the normal path for declarations typed during the current session. +- [ ] Add command support for Wasm export invocation. ## C Checklist @@ -158,7 +265,8 @@ tags, typedefs, declaration table, and CG symbol/type handles. at frontend creation or first compile, with clear behavior if options change. - [ ] Keep the file-scope `Scope` alive across snippets. - [ ] Keep `DeclTable` alive across snippets. -- [ ] Keep one persistent `CfreeCg` and use `cfree_cg_swap_obj` per snippet. +- [ ] Keep one persistent `CfreeCg` and bind a new object with + `cfree_cg_begin_obj` per snippet. - [ ] Split parser initialization from translation-unit parsing so a parser can reuse file-scope state with a new lexer. - [ ] Ensure failed snippets do not corrupt persistent scope or macro state. @@ -195,15 +303,12 @@ unsigned long long __cfree_dbg_expr_N(void) { ## Toy Checklist -Toy is the best first full REPL target because it already sits cleanly on the -public CG API and has explicit source syntax for types, globals, functions, and -expressions. +Toy is the current working interactive target. -- [x] Change `ToyFrontend` to own persistent symbol/type storage instead of - rebuilding all parser state per compile. -- [ ] Keep one persistent `CfreeCg` and use `cfree_cg_swap_obj` per snippet. +- [x] Change `ToyFrontend` to own persistent parser symbol/type storage instead + of rebuilding all parser state per compile. - [x] Refactor `ToyParser` so lexical state is per snippet but declarations, - record/enum/type tables, globals, and function symbols live on `ToyFrontend`. + record/enum/type tables, globals, and function symbols persist. - [x] Implement `CFREE_FRONTEND_INPUT_REPL_TOPLEVEL` for declarations and definitions. - [x] Implement `CFREE_FRONTEND_INPUT_REPL_EXPR` by generating: @@ -220,11 +325,15 @@ fn __cfree_dbg_expr_N(): i64 { `jit { let x: i64 = 41; }`, then bare `x + 1`. - [x] Preserve nominal records/enums/type aliases across snippets. - [x] Preserve functions across snippets, including calls from later snippets. -- [ ] Add diagnostics for duplicate definitions and type mismatches that include - the snippet input name. - [x] Add Toy REPL smoke tests for globals, functions, record field access, and expression wrapper. +- [ ] Keep one persistent `CfreeCg` if Toy needs CG-level metadata beyond the + parser-owned declaration/type tables. +- [ ] Add diagnostics for duplicate definitions and type mismatches that include + the snippet input name. - [ ] Add Toy REPL smoke tests for enum constants and block wrapper. +- [ ] Add a focused test for a failed Toy snippet followed by a successful + snippet, documenting poison-or-recovery semantics. ## Wasm Checklist @@ -256,11 +365,15 @@ module/session model with export invocation and instance-owned runtime state. ## Shared Acceptance Tests -- [ ] `make bin` builds after each milestone. +- [x] `make bin` +- [x] `make test-cg-api` +- [x] `make test-link` +- [x] `make test-asm` +- [x] `make test-parse` +- [x] `make test-driver` - [ ] `make test-toy` stays green after Toy refactors. -- [ ] `make test-parse test-parse-err test-pp test-pp-err` stay green after C - refactors. -- [ ] `make test-wasm-front` stays green after Wasm REPL command work. +- [ ] `make test-parse-err test-pp test-pp-err` stay green after C REPL + frontend work. - [ ] New scripted REPL tests cover: C macro/type/global persistence, Toy type/global/function persistence, Wasm module invoke, bare expression fallback, explicit `expr` alias behavior, block diff --git a/driver/as.c b/driver/as.c @@ -1,14 +1,14 @@ +#include <cfree/compile.h> +#include <cfree/core.h> #include <stdint.h> +#include <string.h> #include "cflags.h" #include "driver.h" #include "lang/c/c.h" -#include <cfree/compile.h> -#include <cfree/core.h> - /* `cfree as` — standalone assembler. Reads a single text source, writes a - * relocatable object via cfree_compile_asm_obj_emit. `.S` inputs are + * relocatable object via a CfreeCompileSession. `.S` inputs are * preprocessed first via cfree_c_preprocess; `.s` inputs are not. The * accepted input is a GAS subset (AT&T syntax on x86). */ @@ -207,10 +207,27 @@ int driver_as(int argc, char** argv) { asm_input.len = pp_len; } - rc = cfree_compile_asm_obj_emit(compiler, &copts, &asm_input, writer) == - CFREE_OK - ? 0 - : 1; + { + CfreeCompileSessionOptions sopts; + CfreeCompileSession* session = NULL; + CfreeSourceInput sin; + CfreeObjBuilder* ob = NULL; + CfreeStatus st; + memset(&sopts, 0, sizeof(sopts)); + sopts.lang = CFREE_LANG_ASM; + sopts.compile.code = copts.code; + sopts.compile.diagnostics = copts.diagnostics; + sopts.compile.language_options = &copts; + memset(&sin, 0, sizeof(sin)); + sin.bytes = asm_input; + sin.lang = CFREE_LANG_ASM; + st = cfree_compile_session_new(compiler, &sopts, &session); + if (st == CFREE_OK) st = cfree_compile_session_compile(session, &sin, &ob); + if (st == CFREE_OK) st = cfree_obj_builder_emit(ob, writer); + cfree_obj_builder_free(ob); + cfree_compile_session_free(session); + rc = st == CFREE_OK ? 0 : 1; + } out: if (compiler) driver_compiler_free(compiler); diff --git a/driver/cc.c b/driver/cc.c @@ -4,6 +4,7 @@ #include <cfree/core.h> #include <cfree/link.h> #include <stdint.h> +#include <string.h> #include "cflags.h" #include "driver.h" @@ -1019,8 +1020,7 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { continue; } if (driver_streq(a, "-print-libgcc-file-name")) { - if (cc_set_probe(o, CC_PROBE_PRINT_LIBGCC_FILE_NAME, NULL) != 0) - return 1; + if (cc_set_probe(o, CC_PROBE_PRINT_LIBGCC_FILE_NAME, NULL) != 0) return 1; continue; } if (driver_streq(a, "-print-multi-os-directory")) { @@ -1910,6 +1910,51 @@ out: return rc; } +static CfreeStatus cc_compile_source_obj(CfreeCompiler* compiler, + CfreeLanguage lang, + const CfreeCCompileOptions* copts, + const CfreeBytes* input, + CfreeObjBuilder** out) { + CfreeCompileSessionOptions sopts; + CfreeCompileSession* session = NULL; + CfreeSourceInput sin; + CfreeAsmCompileOptions aopts; + CfreeStatus st; + + memset(&sopts, 0, sizeof(sopts)); + memset(&aopts, 0, sizeof(aopts)); + sopts.lang = lang; + sopts.compile.code = copts->code; + sopts.compile.diagnostics = copts->diagnostics; + if (lang == CFREE_LANG_ASM) { + aopts.code = copts->code; + aopts.diagnostics = copts->diagnostics; + sopts.compile.language_options = &aopts; + } else { + sopts.compile.language_options = copts; + } + memset(&sin, 0, sizeof(sin)); + sin.bytes = *input; + sin.lang = lang; + st = cfree_compile_session_new(compiler, &sopts, &session); + if (st == CFREE_OK) st = cfree_compile_session_compile(session, &sin, out); + cfree_compile_session_free(session); + return st; +} + +static CfreeStatus cc_compile_source_emit(CfreeCompiler* compiler, + CfreeLanguage lang, + const CfreeCCompileOptions* copts, + const CfreeBytes* input, + CfreeWriter* out) { + CfreeObjBuilder* ob = NULL; + CfreeStatus st = cc_compile_source_obj(compiler, lang, copts, input, &ob); + if (st == CFREE_OK && !copts->code.emit_c_source) + st = cfree_obj_builder_emit(ob, out); + cfree_obj_builder_free(ob); + return st; +} + static int cc_run_compile_one(DriverEnv* env, const CcOptions* o, const CfreePreprocessOptions* pp, int is_memory, uint32_t index, const char* out_path) { @@ -1958,34 +2003,7 @@ static int cc_run_compile_one(DriverEnv* env, const CcOptions* o, CfreeLanguage lang = is_memory ? o->source_memory[index].lang : o->source_langs[index]; CfreeStatus st; - if (lang == CFREE_LANG_C) { - st = cfree_compile_c_obj_emit(compiler, &copts, &input, obj_w); - } else if (lang == CFREE_LANG_ASM) { - CfreeAsmCompileOptions aopts = {0}; - aopts.code = copts.code; - aopts.diagnostics = copts.diagnostics; - st = cfree_compile_asm_obj_emit(compiler, &aopts, &input, obj_w); - } else { - CfreeFrontendCompileOptions fopts = {0}; - CfreeFrontend *frontend = NULL; - CfreeObjBuilder *ob = NULL; - CfreeSourceInput sin; - fopts.code = copts.code; - fopts.diagnostics = copts.diagnostics; - fopts.language_options = &copts; - sin.bytes = input; - sin.lang = lang; - st = cfree_frontend_new(compiler, lang, &frontend); - if (st == CFREE_OK) st = cfree_obj_builder_new(compiler, &ob); - if (st == CFREE_OK) { - st = cfree_frontend_compile(frontend, &fopts, &sin, ob); - } - if (st == CFREE_OK && !fopts.code.emit_c_source) { - st = cfree_obj_builder_emit(ob, obj_w); - } - cfree_obj_builder_free(ob); - cfree_frontend_free(frontend); - } + st = cc_compile_source_emit(compiler, lang, &copts, &input, obj_w); if (st != CFREE_OK) goto out; } @@ -2052,6 +2070,7 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, CfreeLinkInputOrder* order = NULL; CfreeObjBuilder** objs = NULL; CfreeLinkScript* script = NULL; + CfreeLinkSession* link = NULL; CfreeCCompileOptions copts; uint32_t nsrc = o->nsource_files + o->nsource_memory; uint32_t i; @@ -2156,51 +2175,15 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, for (i = 0; i < o->nsource_files; ++i) { CfreeLanguage lang = o->source_langs[i]; CfreeStatus st; - if (lang == CFREE_LANG_C) { - st = cfree_compile_c_obj(compiler, &copts, &src_bytes[i], &objs[i]); - } else if (lang == CFREE_LANG_ASM) { - CfreeAsmCompileOptions aopts = {0}; - aopts.code = copts.code; - aopts.diagnostics = copts.diagnostics; - st = cfree_compile_asm_obj(compiler, &aopts, &src_bytes[i], &objs[i]); - } else { - CfreeFrontendCompileOptions fopts = {0}; - CfreeFrontend *frontend = NULL; - CfreeSourceInput sin; - fopts.code = copts.code; - fopts.diagnostics = copts.diagnostics; - fopts.language_options = &copts; - sin.bytes = src_bytes[i]; - sin.lang = lang; - st = cfree_frontend_new(compiler, lang, &frontend); - if (st == CFREE_OK) st = cfree_obj_builder_new(compiler, &objs[i]); - if (st == CFREE_OK) { - st = cfree_frontend_compile(frontend, &fopts, &sin, objs[i]); - } - cfree_frontend_free(frontend); - } + st = cc_compile_source_obj(compiler, lang, &copts, &src_bytes[i], &objs[i]); if (st != CFREE_OK) goto out; } for (i = 0; i < o->nsource_memory; ++i) { - CfreeFrontendCompileOptions fopts; - CfreeFrontendCompileOptions z = {0}; - CfreeFrontend *frontend = NULL; CfreeStatus st; - fopts = z; - fopts.code = copts.code; - fopts.diagnostics = copts.diagnostics; - fopts.language_options = &copts; - st = cfree_frontend_new(compiler, o->source_memory[i].lang, &frontend); - if (st == CFREE_OK) { - st = cfree_obj_builder_new(compiler, &objs[o->nsource_files + i]); - } - if (st == CFREE_OK) { - st = cfree_frontend_compile(frontend, &fopts, &o->source_memory[i], - objs[o->nsource_files + i]); - } - cfree_frontend_free(frontend); - if (st != CFREE_OK) - goto out; + st = cc_compile_source_obj(compiler, o->source_memory[i].lang, &copts, + &o->source_memory[i].bytes, + &objs[o->nsource_files + i]); + if (st != CFREE_OK) goto out; } if (io->open_writer(io->user, o->output_path, &out_w) != CFREE_OK) { @@ -2209,92 +2192,82 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, } { - CfreeLinkInputs zero = {0}; - CfreeLinkInputs inputs; - inputs = zero; - inputs.objs = objs; - inputs.nobjs = nsrc; - inputs.obj_bytes = obj_in; - inputs.nobj_bytes = o->nobject_files; - inputs.archives = arch_in; - inputs.narchives = o->narchives; - inputs.dso_bytes = dso_in; - inputs.ndso_bytes = o->ndsos; - inputs.linker_script = script; - inputs.entry = o->entry; - inputs.build_id_mode = o->build_id_mode; - inputs.build_id_bytes = o->build_id_bytes; - inputs.build_id_len = o->build_id_len; + CfreeLinkSessionOptions lopts; + CfreeStatus st; + memset(&lopts, 0, sizeof(lopts)); + lopts.output_kind = + o->shared ? CFREE_LINK_OUTPUT_SHARED : CFREE_LINK_OUTPUT_EXE; + lopts.entry = o->entry; + lopts.linker_script = script; + lopts.build_id_mode = o->build_id_mode; + lopts.build_id_bytes = o->build_id_bytes; + lopts.build_id_len = o->build_id_len; + lopts.gc_sections = o->gc_sections; + lopts.pie = o->pie; + lopts.interp_path = o->interp_path; + lopts.soname = o->soname; + if (o->new_dtags) { + lopts.runpaths = o->rpaths; + lopts.nrunpaths = o->nrpaths; + } else { + lopts.rpaths = o->rpaths; + lopts.nrpaths = o->nrpaths; + } + lopts.allow_undefined = 1; + + st = cfree_link_session_new(compiler, &lopts, &link); if (order) { uint32_t oi; - for (oi = 0; oi < o->nlink_items; ++oi) { + for (oi = 0; oi < o->nlink_items && st == CFREE_OK; ++oi) { const CcLinkItem* item = &o->link_items[oi]; - CfreeLinkInputOrder* dst = &order[oi]; switch ((CcLinkItemKind)item->kind) { case CC_LINK_SOURCE_FILE: - dst->kind = CFREE_LINK_INPUT_OBJ; - dst->index = item->index; + st = cfree_link_session_add_obj(link, objs[item->index]); break; case CC_LINK_SOURCE_MEMORY: - dst->kind = CFREE_LINK_INPUT_OBJ; - dst->index = o->nsource_files + item->index; + st = cfree_link_session_add_obj( + link, objs[o->nsource_files + item->index]); break; case CC_LINK_OBJECT: - dst->kind = CFREE_LINK_INPUT_OBJ_BYTES; - dst->index = item->index; + st = cfree_link_session_add_obj_bytes(link, &obj_in[item->index]); break; case CC_LINK_ARCHIVE: - dst->kind = CFREE_LINK_INPUT_ARCHIVE; - dst->index = item->index; + st = cfree_link_session_add_archive_bytes(link, + &arch_in[item->index]); break; case CC_LINK_DSO: - dst->kind = CFREE_LINK_INPUT_DSO; - dst->index = item->index; + st = cfree_link_session_add_dso_bytes(link, &dso_in[item->index]); break; case CC_LINK_LIB: { const CcPendingLib* pl = &o->pending_libs[item->index]; - dst->kind = (pl->resolved_kind == CC_LINK_DSO) - ? CFREE_LINK_INPUT_DSO - : CFREE_LINK_INPUT_ARCHIVE; - dst->index = pl->resolved_index; + if (pl->resolved_kind == CC_LINK_DSO) { + st = cfree_link_session_add_dso_bytes( + link, &dso_in[pl->resolved_index]); + } else { + st = cfree_link_session_add_archive_bytes( + link, &arch_in[pl->resolved_index]); + } break; } } } - inputs.order = order; - inputs.norder = o->nlink_items; - } - - if (o->shared) { - CfreeSharedLinkOptions z = {0}; - CfreeSharedLinkOptions s; - s = z; - s.inputs = inputs; - s.soname = o->soname; - if (o->new_dtags) { - s.runpaths = o->rpaths; - s.nrunpaths = o->nrpaths; - } else { - s.rpaths = o->rpaths; - s.nrpaths = o->nrpaths; - } - s.allow_undefined = 1; - s.gc_sections = o->gc_sections; - rc = cfree_link_shared(compiler, &s, out_w) == CFREE_OK ? 0 : 1; } else { - CfreeExeLinkOptions z = {0}; - CfreeExeLinkOptions link_opts; - link_opts = z; - link_opts.inputs = inputs; - link_opts.gc_sections = o->gc_sections; - link_opts.pie = o->pie; - link_opts.interp_path = o->interp_path; - rc = cfree_link_exe(compiler, &link_opts, out_w) == CFREE_OK ? 0 : 1; + for (i = 0; i < nsrc && st == CFREE_OK; ++i) + st = cfree_link_session_add_obj(link, objs[i]); + for (i = 0; i < o->nobject_files && st == CFREE_OK; ++i) + st = cfree_link_session_add_obj_bytes(link, &obj_in[i]); + for (i = 0; i < o->narchives && st == CFREE_OK; ++i) + st = cfree_link_session_add_archive_bytes(link, &arch_in[i]); + for (i = 0; i < o->ndsos && st == CFREE_OK; ++i) + st = cfree_link_session_add_dso_bytes(link, &dso_in[i]); } + if (st == CFREE_OK) st = cfree_link_session_emit(link, out_w); + rc = st == CFREE_OK ? 0 : 1; } out: if (out_w) cfree_writer_close(out_w); + cfree_link_session_free(link); if (rc == 0 && o->output_path) { if (driver_mark_executable_output(o->output_path) != 0) { driver_errf(CC_TOOL, "failed to set executable mode: %s", o->output_path); @@ -2368,11 +2341,10 @@ int driver_cc(int argc, char** argv) { if (co.nsource_files || co.nsource_memory) { int add_headers; if (co.hosted.profile_name) { - add_headers = driver_runtime_append_freestanding_headers(&runtime, - &co.cf); + add_headers = + driver_runtime_append_freestanding_headers(&runtime, &co.cf); } else { - add_headers = driver_runtime_add_freestanding_headers(&runtime, - &co.cf); + add_headers = driver_runtime_add_freestanding_headers(&runtime, &co.cf); } if (add_headers != 0) { driver_errf(CC_TOOL, "failed to add freestanding headers"); diff --git a/driver/dbg.c b/driver/dbg.c @@ -1,17 +1,18 @@ -#include <stddef.h> -#include <stdint.h> - -#include "cflags.h" -#include "driver.h" -#include "inputs.h" - #include <cfree/arch.h> #include <cfree/compile.h> #include <cfree/core.h> #include <cfree/dbg.h> #include <cfree/dwarf.h> #include <cfree/jit.h> +#include <cfree/link.h> #include <cfree/object.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "cflags.h" +#include "driver.h" +#include "inputs.h" /* `cfree dbg` — interactive JIT debugger. * @@ -47,19 +48,19 @@ * ============================================================ */ typedef struct DbgOpts { - DriverEnv *env; + DriverEnv* env; size_t argv_bound; int opt_level; int debug_info; - const char *entry; + const char* entry; CfreeLanguage default_lang; int has_default_lang; DriverCflags cf; DriverInputs inputs; - char **prog_argv; + char** prog_argv; uint32_t prog_argc; } DbgOpts; @@ -141,7 +142,7 @@ void driver_help_dbg(void) { "usage\n"); } -static int dbg_alloc_arrays(DbgOpts *o, int argc) { +static int dbg_alloc_arrays(DbgOpts* o, int argc) { size_t bound = (size_t)argc; o->argv_bound = bound; o->prog_argv = driver_alloc_zeroed(o->env, bound * sizeof(*o->prog_argv)); @@ -149,8 +150,7 @@ static int dbg_alloc_arrays(DbgOpts *o, int argc) { driver_errf(DBG_TOOL, "out of memory"); return 1; } - if (driver_inputs_init(&o->inputs, o->env, DBG_TOOL, argc) != 0) - return 1; + if (driver_inputs_init(&o->inputs, o->env, DBG_TOOL, argc) != 0) return 1; if (driver_cflags_init(&o->cf, o->env, argc) != 0) { driver_errf(DBG_TOOL, "out of memory"); return 1; @@ -158,9 +158,8 @@ static int dbg_alloc_arrays(DbgOpts *o, int argc) { return 0; } -static int dbg_parse_language_name(const char *name, CfreeLanguage *out) { - if (!name || !*name || !out) - return 0; +static int dbg_parse_language_name(const char* name, CfreeLanguage* out) { + if (!name || !*name || !out) return 0; if (driver_streq(name, "c")) { *out = CFREE_LANG_C; return 1; @@ -180,7 +179,7 @@ static int dbg_parse_language_name(const char *name, CfreeLanguage *out) { return 0; } -static int dbg_set_default_language(DbgOpts *o, const char *name) { +static int dbg_set_default_language(DbgOpts* o, const char* name) { CfreeLanguage lang = CFREE_LANG_COUNT; if (!dbg_parse_language_name(name, &lang)) { driver_errf(DBG_TOOL, "unsupported language: %s", name ? name : ""); @@ -191,14 +190,13 @@ static int dbg_set_default_language(DbgOpts *o, const char *name) { return 0; } -static int dbg_parse(int argc, char **argv, DbgOpts *o) { +static int dbg_parse(int argc, char** argv, DbgOpts* o) { int i; int after_dash_dash = 0; - if (dbg_alloc_arrays(o, argc) != 0) - return 1; + if (dbg_alloc_arrays(o, argc) != 0) return 1; for (i = 1; i < argc; ++i) { - const char *a = argv[i]; + const char* a = argv[i]; if (after_dash_dash) { o->prog_argv[o->prog_argc++] = argv[i]; @@ -212,10 +210,8 @@ static int dbg_parse(int argc, char **argv, DbgOpts *o) { { int r = driver_cflags_try_consume(&o->cf, o->env, DBG_TOOL, argc, argv, &i); - if (r < 0) - return 1; - if (r > 0) - continue; + if (r < 0) return 1; + if (r > 0) continue; } if (driver_streq(a, "-g")) { @@ -250,18 +246,15 @@ static int dbg_parse(int argc, char **argv, DbgOpts *o) { driver_errf(DBG_TOOL, "%s requires an argument", a); return 1; } - if (dbg_set_default_language(o, argv[i]) != 0) - return 1; + if (dbg_set_default_language(o, argv[i]) != 0) return 1; continue; } if (driver_strneq(a, "--language=", 11)) { - if (dbg_set_default_language(o, a + 11) != 0) - return 1; + if (dbg_set_default_language(o, a + 11) != 0) return 1; continue; } if (driver_strneq(a, "--lang=", 7)) { - if (dbg_set_default_language(o, a + 7) != 0) - return 1; + if (dbg_set_default_language(o, a + 7) != 0) return 1; continue; } @@ -272,8 +265,7 @@ static int dbg_parse(int argc, char **argv, DbgOpts *o) { { int r = driver_inputs_classify(&o->inputs, a); - if (r < 0) - return 1; + if (r < 0) return 1; if (r == 0) { driver_errf(DBG_TOOL, "input does not have a recognized suffix: %s", a); return 1; @@ -281,8 +273,7 @@ static int dbg_parse(int argc, char **argv, DbgOpts *o) { } } - if (!o->entry) - o->entry = "main"; + if (!o->entry) o->entry = "main"; if (!o->debug_info) { /* Without -g there are no source lines or variable locations to * read at runtime; force it on so `b file:line` and `p name` @@ -293,7 +284,7 @@ static int dbg_parse(int argc, char **argv, DbgOpts *o) { return 0; } -static void dbg_options_release(DbgOpts *o) { +static void dbg_options_release(DbgOpts* o) { size_t bound = o->argv_bound; driver_inputs_release(&o->inputs); driver_cflags_fini(&o->cf, o->env); @@ -303,11 +294,10 @@ static void dbg_options_release(DbgOpts *o) { /* Compile every C source through a compiler owned by the caller and JIT-link * the result. Compiler ownership stays with the caller so DWARF lookups * during the REPL session can run against the live compiler. */ -static int dbg_compile_and_jit(DbgOpts *o, CfreeCompiler *compiler, - const CfreeJitHost *host, CfreeJit **out_jit) { +static int dbg_compile_and_jit(DbgOpts* o, CfreeCompiler* compiler, + const CfreeJitHost* host, CfreeJit** out_jit) { CfreeCCompileOptions copts; - const char *link_entry = - driver_inputs_count(&o->inputs) ? o->entry : NULL; + const char* link_entry = driver_inputs_count(&o->inputs) ? o->entry : NULL; { CfreeCCompileOptions z = {0}; copts = z; @@ -316,11 +306,11 @@ static int dbg_compile_and_jit(DbgOpts *o, CfreeCompiler *compiler, copts.code.debug_info = o->debug_info; driver_cflags_fill_pp(&o->cf, &copts.preprocess); return driver_inputs_compile_and_jit(&o->inputs, compiler, host, &copts, - link_entry, driver_dlsym_resolver, - NULL, out_jit); + link_entry, driver_dlsym_resolver, NULL, + out_jit); } -static void dbg_fill_compile_options(DbgOpts *o, CfreeCCompileOptions *copts) { +static void dbg_fill_compile_options(DbgOpts* o, CfreeCCompileOptions* copts) { { CfreeCCompileOptions z = {0}; *copts = z; @@ -348,7 +338,7 @@ typedef struct Bp { int id; /* user-facing handle, 1.. */ int enabled; BpKind kind; - char *spec; /* heap-owned NUL-terminated copy */ + char* spec; /* heap-owned NUL-terminated copy */ size_t spec_size; uint64_t addr; uint64_t skip_count; /* silent skips before the first stop */ @@ -361,23 +351,23 @@ typedef struct Bp { * ============================================================ */ typedef struct DbgState { - DriverEnv *env; - CfreeCompiler *compiler; + DriverEnv* env; + CfreeCompiler* compiler; CfreeContext ctx; CfreeCCompileOptions copts; - CfreeJit *jit; - CfreeJitSession *session; - const CfreeObjFile *view; - CfreeDebugInfo *dwarf; - void *entry_addr; - const char *entry_name; + CfreeJit* jit; + CfreeJitSession* session; + const CfreeObjFile* view; + CfreeDebugInfo* dwarf; + void* entry_addr; + const char* entry_name; CfreeLanguage default_jit_lang; - const char *default_jit_name; - CfreeFrontend *frontends[CFREE_LANG_COUNT]; + const char* default_jit_name; + CfreeCompileSession* compile_sessions[CFREE_LANG_COUNT]; int prog_argc; - char **prog_argv; + char** prog_argv; - Bp *bps; + Bp* bps; uint32_t nbps; uint32_t bps_cap; int next_bp_id; @@ -391,10 +381,9 @@ typedef struct DbgState { /* SIGINT trampoline. The handler in env.c calls our cb with this state; * we forward into the session. cfree_jit_session_interrupt is documented * async-signal-safe. */ -static void dbg_on_sigint(void *user) { - DbgState *s = (DbgState *)user; - if (s && s->session) - cfree_jit_session_interrupt(s->session); +static void dbg_on_sigint(void* user) { + DbgState* s = (DbgState*)user; + if (s && s->session) cfree_jit_session_interrupt(s->session); } /* PC-space translation between the JIT runtime address space (where @@ -405,11 +394,11 @@ static void dbg_on_sigint(void *user) { * boundary. Fallback is pass-through so out-of-image PCs (e.g. * stops inside libc on a future multi-input setup) don't return 0 * and silently degrade lookups. */ -static uint64_t dbg_pc_rt_to_img(DbgState *s, uint64_t rt) { +static uint64_t dbg_pc_rt_to_img(DbgState* s, uint64_t rt) { uint64_t v = cfree_jit_runtime_to_image(s->jit, rt); return v ? v : rt; } -static uint64_t dbg_pc_img_to_rt(DbgState *s, uint64_t img) { +static uint64_t dbg_pc_img_to_rt(DbgState* s, uint64_t img) { uint64_t v = cfree_jit_image_to_runtime(s->jit, img); return v ? v : img; } @@ -418,8 +407,8 @@ static uint64_t dbg_pc_img_to_rt(DbgState *s, uint64_t img) { * frame->pc (subprogram_at, param_iter_new, vars_at_new, unwind_step). * The register snapshot and CFA stay in their original (runtime) form * because dw_eval_expr / loc_read interpret them as live host values. */ -static CfreeUnwindFrame dbg_frame_for_dwarf(DbgState *s, - const CfreeUnwindFrame *rt) { +static CfreeUnwindFrame dbg_frame_for_dwarf(DbgState* s, + const CfreeUnwindFrame* rt) { CfreeUnwindFrame out = *rt; out.pc = dbg_pc_rt_to_img(s, rt->pc); return out; @@ -432,9 +421,8 @@ static CfreeUnwindFrame dbg_frame_for_dwarf(DbgState *s, * .debug_info; DLOC_REG / DLOC_FRAME_OFS / DLOC_EXPR derive their * effective address from live register state or are evaluated against * the frame, both of which are already in runtime space. */ -static void dbg_translate_loc(DbgState *s, CfreeDwarfVarLoc *loc) { - if (!loc) - return; +static void dbg_translate_loc(DbgState* s, CfreeDwarfVarLoc* loc) { + if (!loc) return; if (loc->kind == CFREE_DLOC_GLOBAL) loc->v.global = dbg_pc_img_to_rt(s, loc->v.global); } @@ -455,40 +443,34 @@ static int dbg_isxdigit(int c) { } static int dbg_xval(int c) { - if (dbg_isdigit(c)) - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; + if (dbg_isdigit(c)) return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; return c - 'A' + 10; } -static char *dbg_dup(DriverEnv *env, const char *s, size_t n, - size_t *size_out) { - char *p = driver_alloc(env, n + 1); - if (!p) - return NULL; +static char* dbg_dup(DriverEnv* env, const char* s, size_t n, + size_t* size_out) { + char* p = driver_alloc(env, n + 1); + if (!p) return NULL; driver_memcpy(p, s, n); p[n] = '\0'; - if (size_out) - *size_out = n + 1; + if (size_out) *size_out = n + 1; return p; } /* Parse a 0x-prefixed hex literal or a decimal literal into *out. Returns * the number of characters consumed, or 0 on failure. */ -static size_t dbg_parse_uint(const char *s, uint64_t *out) { +static size_t dbg_parse_uint(const char* s, uint64_t* out) { size_t i = 0; uint64_t v = 0; if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { i = 2; - if (!dbg_isxdigit((unsigned char)s[i])) - return 0; + if (!dbg_isxdigit((unsigned char)s[i])) return 0; for (; dbg_isxdigit((unsigned char)s[i]); ++i) { v = (v << 4) | (uint64_t)dbg_xval((unsigned char)s[i]); } } else { - if (!dbg_isdigit((unsigned char)s[0])) - return 0; + if (!dbg_isdigit((unsigned char)s[0])) return 0; for (; dbg_isdigit((unsigned char)s[i]); ++i) { v = v * 10 + (uint64_t)(s[i] - '0'); } @@ -501,12 +483,11 @@ static size_t dbg_parse_uint(const char *s, uint64_t *out) { * Breakpoint table operations * ============================================================ */ -static Bp *dbg_bp_grow(DbgState *s) { +static Bp* dbg_bp_grow(DbgState* s) { uint32_t nc; size_t old_size, new_size; - Bp *nb; - if (s->nbps < s->bps_cap) - return &s->bps[s->nbps]; + Bp* nb; + if (s->nbps < s->bps_cap) return &s->bps[s->nbps]; nc = s->bps_cap ? s->bps_cap * 2 : 8; old_size = (size_t)s->bps_cap * sizeof(Bp); @@ -519,27 +500,25 @@ static Bp *dbg_bp_grow(DbgState *s) { } /* Zero the freshly grown tail so future driver_free walks it cleanly. */ { - char *z = (char *)nb + old_size; + char* z = (char*)nb + old_size; size_t n = new_size - old_size; size_t j; - for (j = 0; j < n; ++j) - z[j] = 0; + for (j = 0; j < n; ++j) z[j] = 0; } s->bps = nb; s->bps_cap = nc; return &s->bps[s->nbps]; } -static Bp *dbg_bp_find(DbgState *s, int id) { +static Bp* dbg_bp_find(DbgState* s, int id) { uint32_t i; for (i = 0; i < s->nbps; ++i) { - if (s->bps[i].id == id) - return &s->bps[i]; + if (s->bps[i].id == id) return &s->bps[i]; } return NULL; } -static void dbg_bp_release(DbgState *s, Bp *b) { +static void dbg_bp_release(DbgState* s, Bp* b) { if (b->session_id) { cfree_jit_session_breakpoint_clear(s->session, b->session_id); b->session_id = 0; @@ -551,7 +530,7 @@ static void dbg_bp_release(DbgState *s, Bp *b) { } } -static int dbg_bp_remove(DbgState *s, int id) { +static int dbg_bp_remove(DbgState* s, int id) { uint32_t i; for (i = 0; i < s->nbps; ++i) { if (s->bps[i].id == id) { @@ -559,8 +538,7 @@ static int dbg_bp_remove(DbgState *s, int id) { /* Shift tail down to keep the array dense; ids stay stable. */ { uint32_t j; - for (j = i + 1; j < s->nbps; ++j) - s->bps[j - 1] = s->bps[j]; + for (j = i + 1; j < s->nbps; ++j) s->bps[j - 1] = s->bps[j]; } s->nbps--; { @@ -573,10 +551,9 @@ static int dbg_bp_remove(DbgState *s, int id) { return 1; } -static void dbg_bps_release_all(DbgState *s) { +static void dbg_bps_release_all(DbgState* s) { uint32_t i; - for (i = 0; i < s->nbps; ++i) - dbg_bp_release(s, &s->bps[i]); + for (i = 0; i < s->nbps; ++i) dbg_bp_release(s, &s->bps[i]); if (s->bps) { driver_free(s->env, s->bps, (size_t)s->bps_cap * sizeof(Bp)); s->bps = NULL; @@ -585,11 +562,11 @@ static void dbg_bps_release_all(DbgState *s) { } } -static void dbg_frontends_release(DbgState *s) { +static void dbg_compile_sessions_release(DbgState* s) { uint32_t i; for (i = 0; i < (uint32_t)CFREE_LANG_COUNT; ++i) { - cfree_frontend_free(s->frontends[i]); - s->frontends[i] = NULL; + cfree_compile_session_free(s->compile_sessions[i]); + s->compile_sessions[i] = NULL; } } @@ -606,16 +583,16 @@ static void dbg_frontends_release(DbgState *s) { * Returns 0 on success, 1 on parse / resolution failure (already * reported via driver_errf). */ -static int dbg_resolve_loc(DbgState *s, const char *spec, BpKind *kind_out, - uint64_t *addr_out) { +static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, + uint64_t* addr_out) { /* file:line — uniquely identifiable by a colon NOT preceded by + and * followed by digits. We require the suffix after ':' to be all * digits so we don't confuse, say, hypothetical `func:42` (which * isn't a thing in C). */ - const char *colon = driver_strchr(spec, ':'); + const char* colon = driver_strchr(spec, ':'); if (colon && dbg_isdigit((unsigned char)colon[1])) { size_t file_n = (size_t)(colon - spec); - char *file; + char* file; uint64_t line64; size_t used; size_t file_size; @@ -661,8 +638,7 @@ static int dbg_resolve_loc(DbgState *s, const char *spec, BpKind *kind_out, driver_errf(DBG_TOOL, " %s (0x%llx)", cands[k].file, (unsigned long long)cands[k].pc); } - if (n > 8u) - driver_errf(DBG_TOOL, " ... and %u more", n - 8u); + if (n > 8u) driver_errf(DBG_TOOL, " ... and %u more", n - 8u); driver_errf(DBG_TOOL, "use a longer path suffix (e.g. b dir/%s:%u)", file, (uint32_t)line64); driver_free(s->env, file, file_size); @@ -696,11 +672,11 @@ static int dbg_resolve_loc(DbgState *s, const char *spec, BpKind *kind_out, /* sym[+off] */ { - const char *plus = driver_strchr(spec, '+'); + const char* plus = driver_strchr(spec, '+'); size_t name_n = plus ? (size_t)(plus - spec) : driver_strlen(spec); - char *name; + char* name; size_t name_size; - void *resolved; + void* resolved; uint64_t off = 0; if (name_n == 0) { @@ -734,7 +710,7 @@ static int dbg_resolve_loc(DbgState *s, const char *spec, BpKind *kind_out, * runs. */ { union { - void *p; + void* p; uint64_t u; } cv; cv.p = resolved; @@ -748,10 +724,10 @@ static int dbg_resolve_loc(DbgState *s, const char *spec, BpKind *kind_out, * Stop rendering * ============================================================ */ -static void dbg_print_pc(DbgState *s, uint64_t pc) { - const char *sym = NULL; +static void dbg_print_pc(DbgState* s, uint64_t pc) { + const char* sym = NULL; uint64_t off = 0; - const char *file = NULL; + const char* file = NULL; uint32_t line = 0; uint32_t col = 0; @@ -767,43 +743,42 @@ static void dbg_print_pc(DbgState *s, uint64_t pc) { &col) == CFREE_OK && file) { driver_printf(" at %s:%u", file, line); - if (col) - driver_printf(":%u", col); + if (col) driver_printf(":%u", col); } } -static void dbg_render_stop(DbgState *s, const CfreeStopInfo *st) { +static void dbg_render_stop(DbgState* s, const CfreeStopInfo* st) { switch (st->kind) { - case CFREE_STOP_BREAKPOINT: { - Bp *b = NULL; - uint32_t i; - for (i = 0; i < s->nbps; ++i) { - if (s->bps[i].session_id == st->bp_id) { - b = &s->bps[i]; - break; + case CFREE_STOP_BREAKPOINT: { + Bp* b = NULL; + uint32_t i; + for (i = 0; i < s->nbps; ++i) { + if (s->bps[i].session_id == st->bp_id) { + b = &s->bps[i]; + break; + } } + if (b) + driver_printf("Breakpoint %d (%s) hit at ", b->id, b->spec); + else + driver_printf("Breakpoint hit at "); + dbg_print_pc(s, st->regs.pc); + driver_printf("\n"); + break; } - if (b) - driver_printf("Breakpoint %d (%s) hit at ", b->id, b->spec); - else - driver_printf("Breakpoint hit at "); - dbg_print_pc(s, st->regs.pc); - driver_printf("\n"); - break; - } - case CFREE_STOP_SIGNAL: - driver_printf("Stopped on signal %d at ", st->signal); - dbg_print_pc(s, st->regs.pc); - driver_printf("\n"); - break; - case CFREE_STOP_INTERRUPT: - driver_printf("Interrupted at "); - dbg_print_pc(s, st->regs.pc); - driver_printf("\n"); - break; - case CFREE_STOP_EXIT: - driver_printf("Program exited with code %d\n", st->exit_code); - break; + case CFREE_STOP_SIGNAL: + driver_printf("Stopped on signal %d at ", st->signal); + dbg_print_pc(s, st->regs.pc); + driver_printf("\n"); + break; + case CFREE_STOP_INTERRUPT: + driver_printf("Interrupted at "); + dbg_print_pc(s, st->regs.pc); + driver_printf("\n"); + break; + case CFREE_STOP_EXIT: + driver_printf("Program exited with code %d\n", st->exit_code); + break; } } @@ -824,7 +799,7 @@ typedef enum DbgRunMode { RUN_STEP_OUT, /* finish — _resume(step_out) */ } DbgRunMode; -static int dbg_drive(DbgState *s, DbgRunMode mode) { +static int dbg_drive(DbgState* s, DbgRunMode mode) { CfreeStatus rc; if (mode == RUN_FRESH && s->has_stop) { @@ -862,23 +837,23 @@ static int dbg_drive(DbgState *s, DbgRunMode mode) { } else { CfreeResumeMode rm = CFREE_RESUME_CONTINUE; switch (mode) { - case RUN_STEP_INSN: - rm = CFREE_RESUME_STEP_INSN; - break; - case RUN_STEP_LINE: - rm = CFREE_RESUME_STEP_LINE; - break; - case RUN_NEXT_LINE: - rm = CFREE_RESUME_NEXT_LINE; - break; - case RUN_STEP_OUT: - rm = CFREE_RESUME_STEP_OUT; - break; - case RUN_CONTINUE: - rm = CFREE_RESUME_CONTINUE; - break; - case RUN_FRESH: - break; /* unreachable */ + case RUN_STEP_INSN: + rm = CFREE_RESUME_STEP_INSN; + break; + case RUN_STEP_LINE: + rm = CFREE_RESUME_STEP_LINE; + break; + case RUN_NEXT_LINE: + rm = CFREE_RESUME_NEXT_LINE; + break; + case RUN_STEP_OUT: + rm = CFREE_RESUME_STEP_OUT; + break; + case RUN_CONTINUE: + rm = CFREE_RESUME_CONTINUE; + break; + case RUN_FRESH: + break; /* unreachable */ } rc = cfree_jit_session_resume(s->session, rm, &s->last_stop); } @@ -895,21 +870,20 @@ static int dbg_drive(DbgState *s, DbgRunMode mode) { s->has_stop = 1; dbg_render_stop(s, &s->last_stop); - if (s->last_stop.kind == CFREE_STOP_EXIT) - s->has_stop = 0; + if (s->last_stop.kind == CFREE_STOP_EXIT) s->has_stop = 0; return 0; } /* Forward declarations: backtrace renders parameter values via the * type-aware printer defined below. */ -static void dbg_print_value(DbgState *, const CfreeDwarfType *, const uint8_t *, +static void dbg_print_value(DbgState*, const CfreeDwarfType*, const uint8_t*, size_t got, int depth); -static int dbg_read_value(DbgState *, const CfreeDwarfVarLoc *, - const CfreeUnwindFrame *, uint8_t *stack_buf, - size_t stack_cap, uint8_t **buf_out, - size_t *alloc_out, size_t *got_out); -static void dbg_release_value_buf(DbgState *, uint8_t *buf, size_t alloc); -static char *dbg_take_word(char *line, char **word_out); +static int dbg_read_value(DbgState*, const CfreeDwarfVarLoc*, + const CfreeUnwindFrame*, uint8_t* stack_buf, + size_t stack_cap, uint8_t** buf_out, + size_t* alloc_out, size_t* got_out); +static void dbg_release_value_buf(DbgState*, uint8_t* buf, size_t alloc); +static char* dbg_take_word(char* line, char** word_out); /* ============================================================ * Backtrace @@ -919,7 +893,7 @@ static char *dbg_take_word(char *line, char **word_out); * Parameter rendering uses cfree_dwarf_param_iter_* against the frame's * PC and the unwound register snapshot. Inlined frames are flagged. */ -static void dbg_cmd_bt(DbgState *s) { +static void dbg_cmd_bt(DbgState* s) { CfreeUnwindFrame frame; int level = 0; @@ -943,7 +917,7 @@ static void dbg_cmd_bt(DbgState *s) { driver_printf("0x%llx", (unsigned long long)frame.pc); { - const char *sym = NULL; + const char* sym = NULL; uint64_t off = 0; if (cfree_jit_addr_to_sym(s->jit, frame.pc, &sym, &off) == CFREE_OK && sym) { @@ -958,7 +932,7 @@ static void dbg_cmd_bt(DbgState *s) { have_sp = (cfree_dwarf_subprogram_at(s->dwarf, img_frame.pc, &sp) == CFREE_OK); if (have_sp && sp.name) { - CfreeDwarfParamIter *it = NULL; + CfreeDwarfParamIter* it = NULL; CfreeDwarfVar p; int first = 1; driver_printf(" in %s%s (", sp.name, sp.inlined ? " [inlined]" : ""); @@ -966,13 +940,12 @@ static void dbg_cmd_bt(DbgState *s) { for (;;) { CfreeIterResult r; uint8_t stack_buf[64]; - uint8_t *buf; + uint8_t* buf; size_t alloc; size_t got; r = cfree_dwarf_param_iter_next(it, &p); if (r != CFREE_ITER_ITEM) break; - if (!first) - driver_printf(", "); + if (!first) driver_printf(", "); driver_printf("%s=", p.name ? p.name : "?"); dbg_translate_loc(s, &p.loc); if (dbg_read_value(s, &p.loc, &frame, stack_buf, sizeof(stack_buf), @@ -990,15 +963,14 @@ static void dbg_cmd_bt(DbgState *s) { } { - const char *file = NULL; + const char* file = NULL; uint32_t line = 0; uint32_t col = 0; CfreeStatus rc = cfree_dwarf_addr_to_line(s->dwarf, img_frame.pc, &file, &line, &col); if (rc == CFREE_OK && file) { driver_printf(" at %s:%u", file, line); - if (col) - driver_printf(":%u", col); + if (col) driver_printf(":%u", col); } else if (rc == CFREE_NOT_FOUND) { driver_printf(" [no debug info for this frame]"); } @@ -1011,8 +983,7 @@ static void dbg_cmd_bt(DbgState *s) { * frame in, then copy back to `frame` so the next iteration's * lookups translate from the new runtime PC. */ step = cfree_dwarf_unwind_step(s->dwarf, &img_frame); - if (step == CFREE_NOT_FOUND) - break; /* bottom of stack */ + if (step == CFREE_NOT_FOUND) break; /* bottom of stack */ if (step != CFREE_OK) { driver_errf(DBG_TOOL, "unwind step failed"); break; @@ -1037,32 +1008,29 @@ static void dbg_cmd_bt(DbgState *s) { * value only — callers print any leading "name = " and the trailing * newline. */ -static uint64_t dbg_load_le_u(const uint8_t *buf, size_t n) { +static uint64_t dbg_load_le_u(const uint8_t* buf, size_t n) { uint64_t v = 0; size_t i; - for (i = 0; i < n && i < 8; ++i) - v |= ((uint64_t)buf[i]) << (8 * i); + for (i = 0; i < n && i < 8; ++i) v |= ((uint64_t)buf[i]) << (8 * i); return v; } -static int64_t dbg_load_le_s(const uint8_t *buf, size_t n) { +static int64_t dbg_load_le_s(const uint8_t* buf, size_t n) { uint64_t v = dbg_load_le_u(buf, n); if (n > 0 && n < 8) { uint64_t sign = (uint64_t)1 << (8 * n - 1); - if (v & sign) - v |= ~((sign << 1) - 1); + if (v & sign) v |= ~((sign << 1) - 1); } return (int64_t)v; } static void dbg_indent(int n) { int i; - for (i = 0; i < n; ++i) - driver_printf(" "); + for (i = 0; i < n; ++i) driver_printf(" "); } -static void dbg_print_value(DbgState *s, const CfreeDwarfType *type, - const uint8_t *buf, size_t got, int depth) { +static void dbg_print_value(DbgState* s, const CfreeDwarfType* type, + const uint8_t* buf, size_t got, int depth) { CfreeDwarfTypeInfo ti; if (!type) { @@ -1079,8 +1047,7 @@ static void dbg_print_value(DbgState *s, const CfreeDwarfType *type, { size_t i; driver_printf("{"); - for (i = 0; i < got; ++i) - driver_printf(" %02x", buf[i]); + for (i = 0; i < got; ++i) driver_printf(" %02x", buf[i]); driver_printf(" }"); return; } @@ -1088,141 +1055,139 @@ static void dbg_print_value(DbgState *s, const CfreeDwarfType *type, ti = cfree_dwarf_type_info(type); switch (ti.kind) { - case CFREE_DT_VOID: - driver_printf("void"); - return; - case CFREE_DT_SINT: - case CFREE_DT_CHAR: - driver_printf("%lld", (long long)dbg_load_le_s(buf, got)); - return; - case CFREE_DT_UINT: - case CFREE_DT_BOOL: - driver_printf("%llu", (unsigned long long)dbg_load_le_u(buf, got)); - return; - case CFREE_DT_PTR: - driver_printf("0x%llx", (unsigned long long)dbg_load_le_u(buf, got)); - return; - case CFREE_DT_FLOAT: - if (got == 4) { - union { - uint32_t u; - float f; - } cv; - cv.u = (uint32_t)dbg_load_le_u(buf, 4); - driver_printf("%g", (double)cv.f); - } else if (got == 8) { - union { - uint64_t u; - double d; - } cv; - cv.u = dbg_load_le_u(buf, 8); - driver_printf("%g", cv.d); - } else { - size_t i; - driver_printf("<float-%zu", got); - for (i = 0; i < got; ++i) - driver_printf(" %02x", buf[i]); - driver_printf(">"); - } - return; - case CFREE_DT_ENUM: { - int64_t v = dbg_load_le_s(buf, got); - CfreeDwarfEnumIter *it = NULL; - CfreeDwarfEnumVal ev; - const char *match = NULL; - if (cfree_dwarf_enum_iter_new(s->dwarf, type, &it) == CFREE_OK) { - for (;;) { - CfreeIterResult r = cfree_dwarf_enum_iter_next(it, &ev); - if (r != CFREE_ITER_ITEM) break; - if (ev.value == v) { - match = ev.name; - break; + case CFREE_DT_VOID: + driver_printf("void"); + return; + case CFREE_DT_SINT: + case CFREE_DT_CHAR: + driver_printf("%lld", (long long)dbg_load_le_s(buf, got)); + return; + case CFREE_DT_UINT: + case CFREE_DT_BOOL: + driver_printf("%llu", (unsigned long long)dbg_load_le_u(buf, got)); + return; + case CFREE_DT_PTR: + driver_printf("0x%llx", (unsigned long long)dbg_load_le_u(buf, got)); + return; + case CFREE_DT_FLOAT: + if (got == 4) { + union { + uint32_t u; + float f; + } cv; + cv.u = (uint32_t)dbg_load_le_u(buf, 4); + driver_printf("%g", (double)cv.f); + } else if (got == 8) { + union { + uint64_t u; + double d; + } cv; + cv.u = dbg_load_le_u(buf, 8); + driver_printf("%g", cv.d); + } else { + size_t i; + driver_printf("<float-%zu", got); + for (i = 0; i < got; ++i) driver_printf(" %02x", buf[i]); + driver_printf(">"); + } + return; + case CFREE_DT_ENUM: { + int64_t v = dbg_load_le_s(buf, got); + CfreeDwarfEnumIter* it = NULL; + CfreeDwarfEnumVal ev; + const char* match = NULL; + if (cfree_dwarf_enum_iter_new(s->dwarf, type, &it) == CFREE_OK) { + for (;;) { + CfreeIterResult r = cfree_dwarf_enum_iter_next(it, &ev); + if (r != CFREE_ITER_ITEM) break; + if (ev.value == v) { + match = ev.name; + break; + } } + cfree_dwarf_enum_iter_free(it); } - cfree_dwarf_enum_iter_free(it); - } - if (match) - driver_printf("%s (%lld)", match, (long long)v); - else - driver_printf("%lld", (long long)v); - return; - } - case CFREE_DT_TYPEDEF: - dbg_print_value(s, ti.inner, buf, got, depth); - return; - case CFREE_DT_ARRAY: { - uint32_t n = ti.element_count; - size_t esz = 0; - uint32_t i; - if (ti.inner) { - CfreeDwarfTypeInfo ein = cfree_dwarf_type_info(ti.inner); - esz = ein.byte_size; - } - if (esz == 0 || n == 0 || (size_t)n * esz > got) { - size_t k; - driver_printf("{"); - for (k = 0; k < got; ++k) - driver_printf(" %02x", buf[k]); - driver_printf(" }"); + if (match) + driver_printf("%s (%lld)", match, (long long)v); + else + driver_printf("%lld", (long long)v); return; } - driver_printf("{\n"); - for (i = 0; i < n; ++i) { - dbg_indent(depth + 1); - driver_printf("[%u] = ", i); - dbg_print_value(s, ti.inner, buf + (size_t)i * esz, esz, depth + 1); - driver_printf(",\n"); - } - dbg_indent(depth); - driver_printf("}"); - return; - } - case CFREE_DT_STRUCT: - case CFREE_DT_UNION: { - CfreeDwarfFieldIter *it = NULL; - CfreeDwarfField f; - driver_printf("{\n"); - if (cfree_dwarf_field_iter_new(s->dwarf, type, &it) == CFREE_OK) { - for (;;) { - CfreeIterResult r = cfree_dwarf_field_iter_next(it, &f); - if (r != CFREE_ITER_ITEM) break; - size_t fsz = 0; + case CFREE_DT_TYPEDEF: + dbg_print_value(s, ti.inner, buf, got, depth); + return; + case CFREE_DT_ARRAY: { + uint32_t n = ti.element_count; + size_t esz = 0; + uint32_t i; + if (ti.inner) { + CfreeDwarfTypeInfo ein = cfree_dwarf_type_info(ti.inner); + esz = ein.byte_size; + } + if (esz == 0 || n == 0 || (size_t)n * esz > got) { + size_t k; + driver_printf("{"); + for (k = 0; k < got; ++k) driver_printf(" %02x", buf[k]); + driver_printf(" }"); + return; + } + driver_printf("{\n"); + for (i = 0; i < n; ++i) { dbg_indent(depth + 1); - driver_printf(".%s = ", (f.name && *f.name) ? f.name : "<anon>"); - if (f.bit_size) { - /* Bitfield: read up to 8 bytes spanning the storage - * unit at byte_offset, shift, mask. */ - size_t off = f.byte_offset; - size_t take = (off + 8 <= got) ? 8 : (off < got ? got - off : 0); - uint64_t raw = take ? dbg_load_le_u(buf + off, take) : 0; - uint64_t mask = (f.bit_size >= 64) - ? (uint64_t)-1 - : (((uint64_t)1 << f.bit_size) - 1); - uint64_t v = (raw >> f.bit_offset) & mask; - driver_printf("%llu", (unsigned long long)v); - } else { - if (f.type) { - CfreeDwarfTypeInfo fti = cfree_dwarf_type_info(f.type); - fsz = fti.byte_size; - } - if (f.type && fsz > 0 && (size_t)f.byte_offset + fsz <= got) { - dbg_print_value(s, f.type, buf + f.byte_offset, fsz, depth + 1); + driver_printf("[%u] = ", i); + dbg_print_value(s, ti.inner, buf + (size_t)i * esz, esz, depth + 1); + driver_printf(",\n"); + } + dbg_indent(depth); + driver_printf("}"); + return; + } + case CFREE_DT_STRUCT: + case CFREE_DT_UNION: { + CfreeDwarfFieldIter* it = NULL; + CfreeDwarfField f; + driver_printf("{\n"); + if (cfree_dwarf_field_iter_new(s->dwarf, type, &it) == CFREE_OK) { + for (;;) { + CfreeIterResult r = cfree_dwarf_field_iter_next(it, &f); + if (r != CFREE_ITER_ITEM) break; + size_t fsz = 0; + dbg_indent(depth + 1); + driver_printf(".%s = ", (f.name && *f.name) ? f.name : "<anon>"); + if (f.bit_size) { + /* Bitfield: read up to 8 bytes spanning the storage + * unit at byte_offset, shift, mask. */ + size_t off = f.byte_offset; + size_t take = (off + 8 <= got) ? 8 : (off < got ? got - off : 0); + uint64_t raw = take ? dbg_load_le_u(buf + off, take) : 0; + uint64_t mask = (f.bit_size >= 64) + ? (uint64_t)-1 + : (((uint64_t)1 << f.bit_size) - 1); + uint64_t v = (raw >> f.bit_offset) & mask; + driver_printf("%llu", (unsigned long long)v); } else { - driver_printf("<truncated>"); + if (f.type) { + CfreeDwarfTypeInfo fti = cfree_dwarf_type_info(f.type); + fsz = fti.byte_size; + } + if (f.type && fsz > 0 && (size_t)f.byte_offset + fsz <= got) { + dbg_print_value(s, f.type, buf + f.byte_offset, fsz, depth + 1); + } else { + driver_printf("<truncated>"); + } } + driver_printf(",\n"); } - driver_printf(",\n"); + cfree_dwarf_field_iter_free(it); } - cfree_dwarf_field_iter_free(it); + dbg_indent(depth); + driver_printf("}"); + return; } - dbg_indent(depth); - driver_printf("}"); - return; - } - case CFREE_DT_FUNC: - driver_printf("<function@0x%llx>", - (unsigned long long)dbg_load_le_u(buf, got)); - return; + case CFREE_DT_FUNC: + driver_printf("<function@0x%llx>", + (unsigned long long)dbg_load_le_u(buf, got)); + return; } driver_printf("<?>"); } @@ -1230,9 +1195,9 @@ static void dbg_print_value(DbgState *s, const CfreeDwarfType *type, /* CfreeDwarfReadMemFn adapter: forwards a DWARF-driven memory read into * the JIT session's address space. The user pointer carries the * CfreeJitSession. */ -static CfreeStatus dbg_dwarf_read_mem(void *user, uint64_t addr, void *dst, +static CfreeStatus dbg_dwarf_read_mem(void* user, uint64_t addr, void* dst, size_t n) { - CfreeJitSession *sess = (CfreeJitSession *)user; + CfreeJitSession* sess = (CfreeJitSession*)user; if (!sess) return CFREE_INVALID; return cfree_jit_session_read_mem(sess, addr, dst, n); } @@ -1241,11 +1206,11 @@ static CfreeStatus dbg_dwarf_read_mem(void *user, uint64_t addr, void *dst, * type. On success returns 0 and sets *buf_out (which may point at * stack_buf or at a heap allocation) plus *got_out. The caller frees * *buf_out via dbg_release_value_buf when done. */ -static int dbg_read_value(DbgState *s, const CfreeDwarfVarLoc *loc, - const CfreeUnwindFrame *frame, uint8_t *stack_buf, - size_t stack_cap, uint8_t **buf_out, - size_t *alloc_out, size_t *got_out) { - uint8_t *buf = stack_buf; +static int dbg_read_value(DbgState* s, const CfreeDwarfVarLoc* loc, + const CfreeUnwindFrame* frame, uint8_t* stack_buf, + size_t stack_cap, uint8_t** buf_out, + size_t* alloc_out, size_t* got_out) { + uint8_t* buf = stack_buf; size_t alloc = 0; size_t cap = stack_cap; size_t got = 0; @@ -1253,14 +1218,12 @@ static int dbg_read_value(DbgState *s, const CfreeDwarfVarLoc *loc, if (loc->byte_size > cap) { alloc = loc->byte_size; buf = driver_alloc(s->env, alloc); - if (!buf) - return 1; + if (!buf) return 1; cap = alloc; } if (cfree_dwarf_loc_read(s->dwarf, loc, frame, dbg_dwarf_read_mem, s->session, buf, cap, &got) != CFREE_OK) { - if (alloc) - driver_free(s->env, buf, alloc); + if (alloc) driver_free(s->env, buf, alloc); return 1; } *buf_out = buf; @@ -1269,19 +1232,18 @@ static int dbg_read_value(DbgState *s, const CfreeDwarfVarLoc *loc, return 0; } -static void dbg_release_value_buf(DbgState *s, uint8_t *buf, size_t alloc) { - if (alloc) - driver_free(s->env, buf, alloc); +static void dbg_release_value_buf(DbgState* s, uint8_t* buf, size_t alloc) { + if (alloc) driver_free(s->env, buf, alloc); } /* ============================================================ * `p name` * ============================================================ */ -static void dbg_cmd_print(DbgState *s, const char *name) { +static void dbg_cmd_print(DbgState* s, const char* name) { CfreeDwarfVarLoc loc; uint8_t stack_buf[64]; - uint8_t *buf; + uint8_t* buf; size_t alloc; size_t got; @@ -1292,11 +1254,10 @@ static void dbg_cmd_print(DbgState *s, const char *name) { { CfreeStatus rc = - s->dwarf - ? cfree_dwarf_var_at(s->dwarf, - dbg_pc_rt_to_img(s, s->last_stop.regs.pc), - name, &loc) - : CFREE_NOT_FOUND; + s->dwarf ? cfree_dwarf_var_at(s->dwarf, + dbg_pc_rt_to_img(s, s->last_stop.regs.pc), + name, &loc) + : CFREE_NOT_FOUND; if (rc == CFREE_OK) { dbg_translate_loc(s, &loc); if (dbg_read_value(s, &loc, &s->last_stop.regs, stack_buf, @@ -1313,10 +1274,10 @@ static void dbg_cmd_print(DbgState *s, const char *name) { /* DWARF didn't know about it — try a global symbol. */ { - void *p = cfree_jit_lookup(s->jit, name); + void* p = cfree_jit_lookup(s->jit, name); if (p) { union { - void *p; + void* p; uint64_t u; } cv; cv.p = p; @@ -1337,7 +1298,7 @@ static void dbg_cmd_print(DbgState *s, const char *name) { * variables. v1 supports integer/pointer scalars only — float and * aggregate writes are out of scope. */ -static void dbg_cmd_set(DbgState *s, const char *name, uint64_t value) { +static void dbg_cmd_set(DbgState* s, const char* name, uint64_t value) { CfreeDwarfVarLoc loc; uint8_t buf[8]; size_t sz; @@ -1349,11 +1310,10 @@ static void dbg_cmd_set(DbgState *s, const char *name, uint64_t value) { } { CfreeStatus rc = - s->dwarf - ? cfree_dwarf_var_at(s->dwarf, - dbg_pc_rt_to_img(s, s->last_stop.regs.pc), - name, &loc) - : CFREE_NOT_FOUND; + s->dwarf ? cfree_dwarf_var_at(s->dwarf, + dbg_pc_rt_to_img(s, s->last_stop.regs.pc), + name, &loc) + : CFREE_NOT_FOUND; if (rc != CFREE_OK) { driver_errf(DBG_TOOL, "no variable named '%s'", name); return; @@ -1362,42 +1322,42 @@ static void dbg_cmd_set(DbgState *s, const char *name, uint64_t value) { dbg_translate_loc(s, &loc); sz = (loc.byte_size == 0 || loc.byte_size > 8) ? 8 : loc.byte_size; - for (i = 0; i < sz; ++i) - buf[i] = (uint8_t)(value >> (8 * i)); + for (i = 0; i < sz; ++i) buf[i] = (uint8_t)(value >> (8 * i)); switch (loc.kind) { - case CFREE_DLOC_FRAME_OFS: { - uint64_t addr = s->last_stop.regs.cfa + (uint64_t)(int64_t)loc.v.frame_ofs; - if (cfree_jit_session_write_mem(s->session, addr, buf, sz) != CFREE_OK) { - driver_errf(DBG_TOOL, "memory write failed"); - } - return; - } - case CFREE_DLOC_GLOBAL: - if (cfree_jit_session_write_mem(s->session, loc.v.global, buf, sz) != - CFREE_OK) { - driver_errf(DBG_TOOL, "memory write failed"); - } - return; - case CFREE_DLOC_REG: { - CfreeUnwindFrame fr = s->last_stop.regs; - if (loc.v.reg >= 32) { - driver_errf(DBG_TOOL, "register %u outside the snapshot range", - loc.v.reg); + case CFREE_DLOC_FRAME_OFS: { + uint64_t addr = + s->last_stop.regs.cfa + (uint64_t)(int64_t)loc.v.frame_ofs; + if (cfree_jit_session_write_mem(s->session, addr, buf, sz) != CFREE_OK) { + driver_errf(DBG_TOOL, "memory write failed"); + } return; } - fr.regs[loc.v.reg] = value; - if (cfree_jit_session_set_regs(s->session, &fr) != CFREE_OK) { - driver_errf(DBG_TOOL, "register write failed"); + case CFREE_DLOC_GLOBAL: + if (cfree_jit_session_write_mem(s->session, loc.v.global, buf, sz) != + CFREE_OK) { + driver_errf(DBG_TOOL, "memory write failed"); + } + return; + case CFREE_DLOC_REG: { + CfreeUnwindFrame fr = s->last_stop.regs; + if (loc.v.reg >= 32) { + driver_errf(DBG_TOOL, "register %u outside the snapshot range", + loc.v.reg); + return; + } + fr.regs[loc.v.reg] = value; + if (cfree_jit_session_set_regs(s->session, &fr) != CFREE_OK) { + driver_errf(DBG_TOOL, "register write failed"); + return; + } + s->last_stop.regs = fr; return; } - s->last_stop.regs = fr; - return; - } - case CFREE_DLOC_EXPR: - driver_errf(DBG_TOOL, "cannot set '%s': location is a DWARF expression", - name); - return; + case CFREE_DLOC_EXPR: + driver_errf(DBG_TOOL, "cannot set '%s': location is a DWARF expression", + name); + return; } } @@ -1407,7 +1367,7 @@ static void dbg_cmd_set(DbgState *s, const char *name, uint64_t value) { * Move PC without resuming. The session validates that the new PC lies * within the JIT image. */ -static void dbg_cmd_jump(DbgState *s, uint64_t pc) { +static void dbg_cmd_jump(DbgState* s, uint64_t pc) { CfreeUnwindFrame fr; if (!s->has_stop) { driver_errf(DBG_TOOL, "no program is stopped"); @@ -1428,8 +1388,8 @@ static void dbg_cmd_jump(DbgState *s, uint64_t pc) { * `info locals` / `info args` / `info reg` * ============================================================ */ -static void dbg_cmd_info_vars(DbgState *s, uint32_t mask, const char *label) { - CfreeDwarfVarIter *it = NULL; +static void dbg_cmd_info_vars(DbgState* s, uint32_t mask, const char* label) { + CfreeDwarfVarIter* it = NULL; CfreeDwarfVar v; int printed = 0; @@ -1452,7 +1412,7 @@ static void dbg_cmd_info_vars(DbgState *s, uint32_t mask, const char *label) { CfreeIterResult r = cfree_dwarf_vars_at_next(it, &v); if (r != CFREE_ITER_ITEM) break; uint8_t stack_buf[64]; - uint8_t *buf; + uint8_t* buf; size_t alloc; size_t got; printed = 1; @@ -1468,11 +1428,10 @@ static void dbg_cmd_info_vars(DbgState *s, uint32_t mask, const char *label) { dbg_release_value_buf(s, buf, alloc); } cfree_dwarf_vars_at_free(it); - if (!printed) - driver_printf("No %s.\n", label); + if (!printed) driver_printf("No %s.\n", label); } -static void dbg_cmd_info_reg(DbgState *s) { +static void dbg_cmd_info_reg(DbgState* s) { CfreeArchKind arch = driver_host_target().arch; uint32_t n = cfree_arch_register_count(arch); uint32_t i; @@ -1490,10 +1449,8 @@ static void dbg_cmd_info_reg(DbgState *s) { (unsigned long long)s->last_stop.regs.cfa); for (i = 0; i < n; ++i) { CfreeArchReg r; - if (cfree_arch_register_at(arch, i, &r) != CFREE_OK) - continue; - if (r.dwarf_idx >= 32) - continue; /* outside CfreeUnwindFrame.regs */ + if (cfree_arch_register_at(arch, i, &r) != CFREE_OK) continue; + if (r.dwarf_idx >= 32) continue; /* outside CfreeUnwindFrame.regs */ driver_printf("%-6s 0x%016llx\n", r.name, (unsigned long long)s->last_stop.regs.regs[r.dwarf_idx]); } @@ -1505,33 +1462,28 @@ static void dbg_cmd_info_reg(DbgState *s) { /* Tiny glob matcher: '*' matches any run, '?' matches any single byte. * NULL pattern matches every name. */ -static int dbg_glob(const char *pat, const char *s) { - if (!pat) - return 1; +static int dbg_glob(const char* pat, const char* s) { + if (!pat) return 1; while (*pat && *s) { if (*pat == '*') { - if (pat[1] == '\0') - return 1; + if (pat[1] == '\0') return 1; while (*s) { - if (dbg_glob(pat + 1, s)) - return 1; + if (dbg_glob(pat + 1, s)) return 1; ++s; } return dbg_glob(pat + 1, s); } - if (*pat != '?' && *pat != *s) - return 0; + if (*pat != '?' && *pat != *s) return 0; ++pat; ++s; } - while (*pat == '*') - ++pat; + while (*pat == '*') ++pat; return *pat == '\0' && *s == '\0'; } -static void dbg_cmd_info_syms(DbgState *s, CfreeSymKind want, - const char *pattern) { - CfreeJitSymIter *it = NULL; +static void dbg_cmd_info_syms(DbgState* s, CfreeSymKind want, + const char* pattern) { + CfreeJitSymIter* it = NULL; CfreeJitSym sym; int printed = 0; @@ -1542,19 +1494,16 @@ static void dbg_cmd_info_syms(DbgState *s, CfreeSymKind want, for (;;) { CfreeIterResult r = cfree_jit_sym_iter_next(it, &sym); if (r != CFREE_ITER_ITEM) break; - if (sym.kind != want) - continue; - if (pattern && !dbg_glob(pattern, sym.name)) - continue; + if (sym.kind != want) continue; + if (pattern && !dbg_glob(pattern, sym.name)) continue; driver_printf("0x%016llx %s\n", (unsigned long long)sym.addr, sym.name); printed = 1; } cfree_jit_sym_iter_free(it); - if (!printed) - driver_printf("(none)\n"); + if (!printed) driver_printf("(none)\n"); } -static int dbg_refresh_dwarf(DbgState *s) { +static int dbg_refresh_dwarf(DbgState* s) { if (s->dwarf) { cfree_dwarf_free(s->dwarf); s->dwarf = NULL; @@ -1572,17 +1521,15 @@ static int dbg_refresh_dwarf(DbgState *s) { return 0; } -static int dbg_buf_append(DbgState *s, char **buf, size_t *len, size_t *cap, - const char *src, size_t n) { +static int dbg_buf_append(DbgState* s, char** buf, size_t* len, size_t* cap, + const char* src, size_t n) { if (*len + n + 1u > *cap) { size_t nc = *cap ? *cap * 2u : 1024u; - char *nb; - while (nc < *len + n + 1u) - nc *= 2u; - nb = (char *)s->env->heap->realloc(s->env->heap, *buf, *cap, nc, - _Alignof(char)); - if (!nb) - return 1; + char* nb; + while (nc < *len + n + 1u) nc *= 2u; + nb = (char*)s->env->heap->realloc(s->env->heap, *buf, *cap, nc, + _Alignof(char)); + if (!nb) return 1; *buf = nb; *cap = nc; } @@ -1592,7 +1539,7 @@ static int dbg_buf_append(DbgState *s, char **buf, size_t *len, size_t *cap, return 0; } -static int dbg_brace_delta(const char *p) { +static int dbg_brace_delta(const char* p) { int d = 0; while (*p) { if (*p == '{') @@ -1604,130 +1551,142 @@ static int dbg_brace_delta(const char *p) { return d; } -static const char *dbg_jit_language_name(CfreeLanguage lang) { +static const char* dbg_jit_language_name(CfreeLanguage lang) { switch (lang) { - case CFREE_LANG_ASM: - return "asm"; - case CFREE_LANG_TOY: - return "toy"; - case CFREE_LANG_WASM: - return "wasm"; - case CFREE_LANG_C: - case CFREE_LANG_COUNT: - break; + case CFREE_LANG_ASM: + return "asm"; + case CFREE_LANG_TOY: + return "toy"; + case CFREE_LANG_WASM: + return "wasm"; + case CFREE_LANG_C: + case CFREE_LANG_COUNT: + break; } return "c"; } -static const char *dbg_jit_language_suffix(CfreeLanguage lang) { +static const char* dbg_jit_language_suffix(CfreeLanguage lang) { switch (lang) { - case CFREE_LANG_ASM: - return ".s"; - case CFREE_LANG_TOY: - return ".toy"; - case CFREE_LANG_WASM: - return ".wat"; - case CFREE_LANG_C: - case CFREE_LANG_COUNT: - break; + case CFREE_LANG_ASM: + return ".s"; + case CFREE_LANG_TOY: + return ".toy"; + case CFREE_LANG_WASM: + return ".wat"; + case CFREE_LANG_C: + case CFREE_LANG_COUNT: + break; } return ".c"; } -static const char *dbg_jit_default_name(CfreeLanguage lang) { +static const char* dbg_jit_default_name(CfreeLanguage lang) { switch (lang) { - case CFREE_LANG_ASM: - return "<dbg-jit.s>"; - case CFREE_LANG_TOY: - return "<dbg-jit.toy>"; - case CFREE_LANG_WASM: - return "<dbg-jit.wat>"; - case CFREE_LANG_C: - case CFREE_LANG_COUNT: - break; + case CFREE_LANG_ASM: + return "<dbg-jit.s>"; + case CFREE_LANG_TOY: + return "<dbg-jit.toy>"; + case CFREE_LANG_WASM: + return "<dbg-jit.wat>"; + case CFREE_LANG_C: + case CFREE_LANG_COUNT: + break; } return "<dbg-jit.c>"; } -static CfreeLanguage dbg_jit_language_for_tag(DbgState *s, const char *tag, - const char **name_out) { +static CfreeLanguage dbg_jit_language_for_tag(DbgState* s, const char* tag, + const char** name_out) { if (!tag || !*tag) { - if (name_out) - *name_out = s->default_jit_name; + if (name_out) *name_out = s->default_jit_name; return s->default_jit_lang; } if (driver_streq(tag, "c")) { - if (name_out) - *name_out = "<dbg-jit.c>"; + if (name_out) *name_out = "<dbg-jit.c>"; return CFREE_LANG_C; } if (driver_streq(tag, "toy")) { - if (name_out) - *name_out = "<dbg-jit.toy>"; + if (name_out) *name_out = "<dbg-jit.toy>"; return CFREE_LANG_TOY; } if (driver_streq(tag, "asm") || driver_streq(tag, "s")) { - if (name_out) - *name_out = "<dbg-jit.s>"; + if (name_out) *name_out = "<dbg-jit.s>"; return CFREE_LANG_ASM; } if (driver_streq(tag, "wasm") || driver_streq(tag, "wat")) { - if (name_out) - *name_out = "<dbg-jit.wat>"; + if (name_out) *name_out = "<dbg-jit.wat>"; return CFREE_LANG_WASM; } - if (name_out) - *name_out = tag; + if (name_out) *name_out = tag; return cfree_language_for_path(tag); } -static CfreeStatus dbg_frontend_for(DbgState *s, CfreeLanguage lang, - CfreeFrontend **out) { +static CfreeStatus dbg_compile_session_for(DbgState* s, CfreeLanguage lang, + CfreeCompileSession** out) { + CfreeCompileSessionOptions sopts; CfreeStatus st; - if (!out || (unsigned)lang >= CFREE_LANG_COUNT) return CFREE_INVALID; + + if (!s || !out || (unsigned)lang >= CFREE_LANG_COUNT) return CFREE_INVALID; *out = NULL; - if (!s->frontends[lang]) { - st = cfree_frontend_new(s->compiler, lang, &s->frontends[lang]); - if (st != CFREE_OK) return st; + if (s->compile_sessions[lang]) { + *out = s->compile_sessions[lang]; + return CFREE_OK; } - *out = s->frontends[lang]; + { + CfreeCompileSessionOptions z = {0}; + sopts = z; + } + sopts.lang = lang; + sopts.compile.code = s->copts.code; + sopts.compile.diagnostics = s->copts.diagnostics; + sopts.compile.language_options = &s->copts; + st = cfree_compile_session_new(s->compiler, &sopts, + &s->compile_sessions[lang]); + if (st != CFREE_OK) return st; + *out = s->compile_sessions[lang]; return CFREE_OK; } -static int dbg_jit_compile_append_ex(DbgState *s, CfreeLanguage lang, - const char *input_name, const char *src, +static int dbg_jit_compile_append_ex(DbgState* s, CfreeLanguage lang, + const char* input_name, const char* src, size_t len, CfreeFrontendInputKind input_kind, - const char *repl_entry_name) { + const char* repl_entry_name) { CfreeSourceInput sin; - CfreeFrontendCompileOptions fopts; - CfreeFrontend *frontend = NULL; - CfreeObjBuilder *ob = NULL; + CfreeCompileSession* session = NULL; + CfreeObjBuilder* ob = NULL; CfreeStatus st; s->jit_counter++; + memset(&sin, 0, sizeof(sin)); sin.bytes.name = input_name ? input_name : dbg_jit_default_name(lang); - sin.bytes.data = (const uint8_t *)src; + sin.bytes.data = (const uint8_t*)src; sin.bytes.len = len; sin.lang = lang; - { - CfreeFrontendCompileOptions z = {0}; - fopts = z; - } - fopts.code = s->copts.code; - fopts.diagnostics = s->copts.diagnostics; - fopts.language_options = &s->copts; - fopts.input_kind = input_kind; - fopts.repl_entry_name = repl_entry_name; - st = dbg_frontend_for(s, lang, &frontend); - if (st == CFREE_OK) st = cfree_obj_builder_new(s->compiler, &ob); - if (st == CFREE_OK) st = cfree_frontend_compile(frontend, &fopts, &sin, ob); + sin.input_kind = input_kind; + sin.repl_entry_name = repl_entry_name; + st = dbg_compile_session_for(s, lang, &session); + if (st == CFREE_OK) st = cfree_compile_session_compile(session, &sin, &ob); if (st != CFREE_OK || !ob) { if (ob) cfree_obj_builder_free(ob); driver_errf(DBG_TOOL, "jit compile failed"); return 1; } - if (cfree_jit_append_obj(s->jit, ob) != CFREE_OK) { + { + CfreeLinkSessionOptions lopts = {0}; + CfreeLinkSession* link = NULL; + CfreeJitPublishOptions popts = {0}; + CfreeJitPublishResult pres; + lopts.output_kind = CFREE_LINK_OUTPUT_RELOCATABLE; + st = cfree_link_session_new(s->compiler, &lopts, &link); + if (st == CFREE_OK) st = cfree_link_session_add_obj(link, ob); + popts.kind = CFREE_JIT_PUBLISH_APPEND_OBJECTS; + popts.link = link; + if (st == CFREE_OK) st = cfree_jit_publish(s->jit, &popts, &pres); + cfree_link_session_free(link); + } + if (st != CFREE_OK) { driver_errf(DBG_TOOL, "jit append failed"); return 1; } @@ -1738,29 +1697,27 @@ static int dbg_jit_compile_append_ex(DbgState *s, CfreeLanguage lang, return 0; } -static int dbg_jit_compile_append(DbgState *s, CfreeLanguage lang, - const char *input_name, const char *src, +static int dbg_jit_compile_append(DbgState* s, CfreeLanguage lang, + const char* input_name, const char* src, size_t len) { return dbg_jit_compile_append_ex(s, lang, input_name, src, len, CFREE_FRONTEND_INPUT_REPL_TOPLEVEL, NULL); } -static int dbg_parse_jit_lang_arg(DbgState *s, const char *rest, - CfreeLanguage *lang_out, - const char **input_name_out, - const char **after_out) { - const char *p = rest; - const char *input_name = NULL; +static int dbg_parse_jit_lang_arg(DbgState* s, const char* rest, + CfreeLanguage* lang_out, + const char** input_name_out, + const char** after_out) { + const char* p = rest; + const char* input_name = NULL; CfreeLanguage lang; - while (*p && dbg_isspace((unsigned char)*p)) - ++p; + while (*p && dbg_isspace((unsigned char)*p)) ++p; if (*p && *p != '{') { - const char *tag = p; + const char* tag = p; size_t tag_n; char tag_buf[64]; - while (*p && !dbg_isspace((unsigned char)*p) && *p != '{') - ++p; + while (*p && !dbg_isspace((unsigned char)*p) && *p != '{') ++p; tag_n = (size_t)(p - tag); if (tag_n == 0 || tag_n >= sizeof(tag_buf)) { driver_errf(DBG_TOOL, "language/name is too long"); @@ -1769,8 +1726,7 @@ static int dbg_parse_jit_lang_arg(DbgState *s, const char *rest, driver_memcpy(tag_buf, tag, tag_n); tag_buf[tag_n] = '\0'; lang = dbg_jit_language_for_tag(s, tag_buf, &input_name); - while (*p && dbg_isspace((unsigned char)*p)) - ++p; + while (*p && dbg_isspace((unsigned char)*p)) ++p; } else { lang = dbg_jit_language_for_tag(s, NULL, &input_name); } @@ -1781,16 +1737,15 @@ static int dbg_parse_jit_lang_arg(DbgState *s, const char *rest, return 0; } -static void dbg_cmd_jit(DbgState *s, const char *rest) { - char *src = NULL; +static void dbg_cmd_jit(DbgState* s, const char* rest) { + char* src = NULL; size_t len = 0, cap = 0; - const char *p; - const char *input_name; + const char* p; + const char* input_name; CfreeLanguage lang; int depth; - if (dbg_parse_jit_lang_arg(s, rest, &lang, &input_name, &p) != 0) - return; + if (dbg_parse_jit_lang_arg(s, rest, &lang, &input_name, &p) != 0) return; if (*p != '{') { driver_errf(DBG_TOOL, "usage: jit [c|toy|asm|name.ext] { ... }"); return; @@ -1798,17 +1753,14 @@ static void dbg_cmd_jit(DbgState *s, const char *rest) { ++p; depth = 1 + dbg_brace_delta(p); { - const char *end = p + driver_strlen(p); + const char* end = p + driver_strlen(p); if (depth <= 0) { - while (end > p && end[-1] != '}') - --end; - if (end > p) - --end; + while (end > p && end[-1] != '}') --end; + if (end > p) --end; } if (dbg_buf_append(s, &src, &len, &cap, p, (size_t)(end - p)) != 0) goto oom; - if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) - goto oom; + if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; } while (depth > 0) { char line[LINE_CAP]; @@ -1822,20 +1774,17 @@ static void dbg_cmd_jit(DbgState *s, const char *rest) { } depth += dbg_brace_delta(line); if (depth <= 0) { - char *close = line; - while (*close && *close != '}') - ++close; + char* close = line; + while (*close && *close != '}') ++close; if (dbg_buf_append(s, &src, &len, &cap, line, (size_t)(close - line)) != 0) goto oom; - if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) - goto oom; + if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; break; } if (dbg_buf_append(s, &src, &len, &cap, line, driver_strlen(line)) != 0) goto oom; - if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) - goto oom; + if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; } (void)dbg_jit_compile_append(s, lang, input_name, src, len); @@ -1844,19 +1793,17 @@ static void dbg_cmd_jit(DbgState *s, const char *rest) { oom: driver_errf(DBG_TOOL, "out of memory"); out: - if (src) - driver_free(s->env, src, cap); + if (src) driver_free(s->env, src, cap); } -static void dbg_cmd_edit(DbgState *s, const char *rest) { +static void dbg_cmd_edit(DbgState* s, const char* rest) { CfreeLanguage lang; - const char *input_name; - const char *p; - uint8_t *src = NULL; + const char* input_name; + const char* p; + uint8_t* src = NULL; size_t len = 0; - if (dbg_parse_jit_lang_arg(s, rest, &lang, &input_name, &p) != 0) - return; + if (dbg_parse_jit_lang_arg(s, rest, &lang, &input_name, &p) != 0) return; if (*p) { driver_errf(DBG_TOOL, "usage: edit [c|toy|asm|name.ext]"); return; @@ -1870,34 +1817,32 @@ static void dbg_cmd_edit(DbgState *s, const char *rest) { driver_errf(DBG_TOOL, "empty editor buffer; nothing appended"); goto out; } - (void)dbg_jit_compile_append(s, lang, input_name, (const char *)src, len); + (void)dbg_jit_compile_append(s, lang, input_name, (const char*)src, len); out: driver_free(s->env, src, len); } -static void dbg_cmd_language(DbgState *s, const char *rest) { +static void dbg_cmd_language(DbgState* s, const char* rest) { char tmp[WORD_CAP]; - const char *p = rest; + const char* p = rest; size_t n = 0; CfreeLanguage lang; - const char *name; + const char* name; - while (*p && dbg_isspace((unsigned char)*p)) - ++p; - while (p[n] && !dbg_isspace((unsigned char)p[n])) - ++n; + while (*p && dbg_isspace((unsigned char)*p)) ++p; + while (p[n] && !dbg_isspace((unsigned char)p[n])) ++n; if (n == 0) { - const CfreePreprocessOptions *pp = &s->copts.preprocess; + const CfreePreprocessOptions* pp = &s->copts.preprocess; driver_printf("Language: %s\n", dbg_jit_language_name(s->default_jit_lang)); driver_printf( "Language options: input=%s opt=-O%d debug=%s includes=%u " - "system-includes=%u defines=%u undefines=%u frontend=%s\n", - s->default_jit_name ? s->default_jit_name : "", - s->copts.code.opt_level, s->copts.code.debug_info ? "on" : "off", - (unsigned)pp->ninclude_dirs, (unsigned)pp->nsystem_include_dirs, - (unsigned)pp->ndefines, (unsigned)pp->nundefines, - s->frontends[s->default_jit_lang] ? "cached" : "not-created"); + "system-includes=%u defines=%u undefines=%u session=%s\n", + s->default_jit_name ? s->default_jit_name : "", s->copts.code.opt_level, + s->copts.code.debug_info ? "on" : "off", (unsigned)pp->ninclude_dirs, + (unsigned)pp->nsystem_include_dirs, (unsigned)pp->ndefines, + (unsigned)pp->nundefines, + s->compile_sessions[s->default_jit_lang] ? "cached" : "not-created"); return; } if (n >= sizeof(tmp)) { @@ -1917,15 +1862,13 @@ static void dbg_cmd_language(DbgState *s, const char *rest) { driver_printf("Language: %s\n", dbg_jit_language_name(lang)); } -static size_t dbg_u64_dec(char *dst, size_t cap, uint64_t v) { +static size_t dbg_u64_dec(char* dst, size_t cap, uint64_t v) { char tmp[32]; size_t n = 0; size_t i; - if (!dst || cap == 0) - return 0; + if (!dst || cap == 0) return 0; if (v == 0) { - if (cap < 2u) - return 0; + if (cap < 2u) return 0; dst[0] = '0'; dst[1] = '\0'; return 1; @@ -1934,16 +1877,14 @@ static size_t dbg_u64_dec(char *dst, size_t cap, uint64_t v) { tmp[n++] = (char)('0' + (v % 10u)); v /= 10u; } - if (n + 1u > cap) - return 0; - for (i = 0; i < n; ++i) - dst[i] = tmp[n - 1u - i]; + if (n + 1u > cap) return 0; + for (i = 0; i < n; ++i) dst[i] = tmp[n - 1u - i]; dst[n] = '\0'; return n; } -static int dbg_call_u64_entry(DbgState *s, void *entry, const uint64_t *args, - uint32_t nargs, uint64_t *ret_out) { +static int dbg_call_u64_entry(DbgState* s, void* entry, const uint64_t* args, + uint32_t nargs, uint64_t* ret_out) { uint64_t ret = 0; CfreeStopInfo stop; @@ -1960,8 +1901,7 @@ static int dbg_call_u64_entry(DbgState *s, void *entry, const uint64_t *args, driver_restore_sigint(); s->last_stop = stop; s->has_stop = (stop.kind != CFREE_STOP_EXIT); - if (ret_out) - *ret_out = ret; + if (ret_out) *ret_out = ret; if (stop.kind != CFREE_STOP_EXIT) { s->has_stop = 1; dbg_render_stop(s, &stop); @@ -1970,41 +1910,37 @@ static int dbg_call_u64_entry(DbgState *s, void *entry, const uint64_t *args, return 0; } -static void dbg_cmd_expr(DbgState *s, const char *expr) { - char *body = NULL; +static void dbg_cmd_expr(DbgState* s, const char* expr) { + char* body = NULL; size_t body_len = 0, body_cap = 0; char num[32]; char name[64]; size_t num_len; size_t prefix_len; - void *entry; + void* entry; uint64_t ret = 0; uint64_t id; int is_block = 0; - while (*expr && dbg_isspace((unsigned char)*expr)) - ++expr; + while (*expr && dbg_isspace((unsigned char)*expr)) ++expr; if (!*expr) { driver_errf(DBG_TOOL, "usage: expr EXPR | expr { STATEMENTS }"); return; } if (*expr == '{') { - const char *p = expr + 1; + const char* p = expr + 1; int depth = 1 + dbg_brace_delta(p); - const char *end = p + driver_strlen(p); + const char* end = p + driver_strlen(p); is_block = 1; if (depth <= 0) { - while (end > p && end[-1] != '}') - --end; - if (end > p) - --end; + while (end > p && end[-1] != '}') --end; + if (end > p) --end; } if (dbg_buf_append(s, &body, &body_len, &body_cap, p, (size_t)(end - p)) != 0) goto oom; - if (dbg_buf_append(s, &body, &body_len, &body_cap, "\n", 1) != 0) - goto oom; + if (dbg_buf_append(s, &body, &body_len, &body_cap, "\n", 1) != 0) goto oom; while (depth > 0) { char line[LINE_CAP]; int n; @@ -2017,9 +1953,8 @@ static void dbg_cmd_expr(DbgState *s, const char *expr) { } depth += dbg_brace_delta(line); if (depth <= 0) { - char *close = line; - while (*close && *close != '}') - ++close; + char* close = line; + while (*close && *close != '}') ++close; if (dbg_buf_append(s, &body, &body_len, &body_cap, line, (size_t)(close - line)) != 0) goto oom; @@ -2050,7 +1985,7 @@ static void dbg_cmd_expr(DbgState *s, const char *expr) { driver_memcpy(name + prefix_len, num, num_len + 1u); { - const char *src = is_block ? body : expr; + const char* src = is_block ? body : expr; size_t len = is_block ? body_len : driver_strlen(expr); CfreeFrontendInputKind kind = is_block ? CFREE_FRONTEND_INPUT_REPL_BLOCK : CFREE_FRONTEND_INPUT_REPL_EXPR; @@ -2075,18 +2010,17 @@ static void dbg_cmd_expr(DbgState *s, const char *expr) { oom: driver_errf(DBG_TOOL, "out of memory"); out: - if (body) - driver_free(s->env, body, body_cap); + if (body) driver_free(s->env, body, body_cap); } -static void dbg_cmd_call(DbgState *s, const char *rest) { - char *tmp; +static void dbg_cmd_call(DbgState* s, const char* rest) { + char* tmp; size_t tmp_size; - char *sym; - char *p; + char* sym; + char* p; uint64_t args[8]; uint32_t nargs = 0; - void *entry; + void* entry; uint64_t ret = 0; tmp = dbg_dup(s->env, rest, driver_strlen(rest), &tmp_size); @@ -2105,12 +2039,11 @@ static void dbg_cmd_call(DbgState *s, const char *rest) { goto out; } while (*p) { - char *a; + char* a; uint64_t v; size_t used; p = dbg_take_word(p, &a); - if (!*a) - break; + if (!*a) break; if (nargs == 8u) { driver_errf(DBG_TOOL, "call supports at most 8 arguments"); goto out; @@ -2137,7 +2070,7 @@ out: * Examine memory: reads `count` bytes (default 16) at `addr` from the * worker's address space and prints them as 16-byte rows. */ -static void dbg_cmd_examine(DbgState *s, uint64_t addr, size_t count) { +static void dbg_cmd_examine(DbgState* s, uint64_t addr, size_t count) { uint8_t buf[256]; size_t remaining = count; @@ -2157,8 +2090,7 @@ static void dbg_cmd_examine(DbgState *s, uint64_t addr, size_t count) { size_t j; size_t row = chunk - i < 16 ? chunk - i : 16; driver_printf("0x%llx:", (unsigned long long)(addr + i)); - for (j = 0; j < row; ++j) - driver_printf(" %02x", buf[i + j]); + for (j = 0; j < row; ++j) driver_printf(" %02x", buf[i + j]); driver_printf("\n"); } addr += chunk; @@ -2177,8 +2109,8 @@ static void dbg_cmd_examine(DbgState *s, uint64_t addr, size_t count) { #define DBG_LIST_CTX 5 /* lines printed before/after the target */ -static void dbg_cmd_list(DbgState *s, const char *spec) { - const char *colon; +static void dbg_cmd_list(DbgState* s, const char* spec) { + const char* colon; size_t flen; char path[1024]; uint64_t line_u; @@ -2186,7 +2118,7 @@ static void dbg_cmd_list(DbgState *s, const char *spec) { uint64_t pc; int rc; CfreeFileData fd; - const CfreeFileIO *io; + const CfreeFileIO* io; if (!s->dwarf) { driver_errf(DBG_TOOL, "no DWARF: cannot resolve %s", spec); @@ -2250,20 +2182,19 @@ static void dbg_cmd_list(DbgState *s, const char *spec) { uint32_t lo = target > DBG_LIST_CTX ? target - DBG_LIST_CTX : 1; uint32_t hi = target + DBG_LIST_CTX; uint32_t cur = 1; - const uint8_t *p = fd.data; - const uint8_t *end = fd.data + fd.size; - const uint8_t *line_start = p; + const uint8_t* p = fd.data; + const uint8_t* end = fd.data + fd.size; + const uint8_t* line_start = p; while (p <= end) { int eol = (p == end) || (*p == '\n'); if (eol) { if (cur >= lo && cur <= hi) { size_t len = (size_t)(p - line_start); driver_printf("%6u%s %.*s\n", cur, cur == target ? " >" : " ", - (int)len, (const char *)line_start); + (int)len, (const char*)line_start); } ++cur; - if (p == end) - break; + if (p == end) break; line_start = p + 1; } ++p; @@ -2274,8 +2205,7 @@ static void dbg_cmd_list(DbgState *s, const char *spec) { } } - if (io->release) - io->release(io->user, &fd); + if (io->release) io->release(io->user, &fd); } /* ============================================================ @@ -2286,7 +2216,7 @@ static void dbg_cmd_list(DbgState *s, const char *spec) { * is used when no skip/cap is in effect; otherwise the spec form. The * driver does not yet wire conditions, but the spec callback slot is left * NULL so this remains forward-compatible. */ -static int dbg_bp_arm(DbgState *s, Bp *b) { +static int dbg_bp_arm(DbgState* s, Bp* b) { CfreeStatus st; if (b->skip_count == 0 && b->max_hits == 0) { st = cfree_jit_session_breakpoint_set(s->session, b->addr, &b->session_id); @@ -2303,21 +2233,19 @@ static int dbg_bp_arm(DbgState *s, Bp *b) { return st == CFREE_OK ? 0 : 1; } -static void dbg_cmd_break(DbgState *s, const char *spec) { +static void dbg_cmd_break(DbgState* s, const char* spec) { BpKind kind; uint64_t addr; - Bp *b; + Bp* b; if (!*spec) { driver_errf(DBG_TOOL, "usage: b <0xADDR | sym[+off] | file.c:line>"); return; } - if (dbg_resolve_loc(s, spec, &kind, &addr) != 0) - return; + if (dbg_resolve_loc(s, spec, &kind, &addr) != 0) return; b = dbg_bp_grow(s); - if (!b) - return; + if (!b) return; { Bp z = {0}; @@ -2346,7 +2274,7 @@ static void dbg_cmd_break(DbgState *s, const char *spec) { b->session_id ? "" : " [disarmed]"); } -static void dbg_cmd_info_b(DbgState *s) { +static void dbg_cmd_info_b(DbgState* s) { uint32_t i; if (s->nbps == 0) { driver_printf("No breakpoints.\n"); @@ -2354,7 +2282,7 @@ static void dbg_cmd_info_b(DbgState *s) { } driver_printf("Num Enb Address Skip Max Spec\n"); for (i = 0; i < s->nbps; ++i) { - Bp *b = &s->bps[i]; + Bp* b = &s->bps[i]; driver_printf("%-4d %-4s 0x%-18llx %-6llu %-6llu %s%s\n", b->id, b->enabled ? "y" : "n", (unsigned long long)b->addr, (unsigned long long)b->skip_count, @@ -2363,8 +2291,8 @@ static void dbg_cmd_info_b(DbgState *s) { } } -static void dbg_cmd_ignore(DbgState *s, int id, uint64_t count) { - Bp *b = dbg_bp_find(s, id); +static void dbg_cmd_ignore(DbgState* s, int id, uint64_t count) { + Bp* b = dbg_bp_find(s, id); if (!b) { driver_errf(DBG_TOOL, "no breakpoint %d", id); return; @@ -2384,14 +2312,14 @@ static void dbg_cmd_ignore(DbgState *s, int id, uint64_t count) { (unsigned long long)count); } -static void dbg_cmd_delete(DbgState *s, int id) { +static void dbg_cmd_delete(DbgState* s, int id) { if (dbg_bp_remove(s, id) != 0) { driver_errf(DBG_TOOL, "no breakpoint %d", id); } } -static void dbg_cmd_set_enabled(DbgState *s, int id, int enable) { - Bp *b = dbg_bp_find(s, id); +static void dbg_cmd_set_enabled(DbgState* s, int id, int enable) { + Bp* b = dbg_bp_find(s, id); if (!b) { driver_errf(DBG_TOOL, "no breakpoint %d", id); return; @@ -2454,18 +2382,13 @@ static void dbg_cmd_help(void) { " info variables [PATTERN] list JIT globals matching PATTERN\n"); } -static CfreeLanguage dbg_default_language_from_inputs(const DbgOpts *o) { - if (o->has_default_lang) - return o->default_lang; - if (o->inputs.nsources) - return cfree_language_for_path(o->inputs.sources[0]); - if (o->inputs.nsource_memory) - return o->inputs.source_memory[0].lang; +static CfreeLanguage dbg_default_language_from_inputs(const DbgOpts* o) { + if (o->has_default_lang) return o->default_lang; + if (o->inputs.nsources) return cfree_language_for_path(o->inputs.sources[0]); + if (o->inputs.nsource_memory) return o->inputs.source_memory[0].lang; return CFREE_LANG_C; } - - /* ============================================================ * Tokenizer / dispatch * ============================================================ */ @@ -2474,43 +2397,38 @@ static CfreeLanguage dbg_default_language_from_inputs(const DbgOpts *o) { * Returns the start of the next region (i.e. the rest of the line, with * its own leading whitespace skipped). The input buffer is mutated: * the byte after the first word is replaced with a NUL. */ -static char *dbg_take_word(char *line, char **word_out) { - char *p = line; - char *w; - while (*p && dbg_isspace((unsigned char)*p)) - ++p; +static char* dbg_take_word(char* line, char** word_out) { + char* p = line; + char* w; + while (*p && dbg_isspace((unsigned char)*p)) ++p; if (!*p) { *word_out = p; return p; } w = p; - while (*p && !dbg_isspace((unsigned char)*p)) - ++p; + while (*p && !dbg_isspace((unsigned char)*p)) ++p; if (*p) { *p = '\0'; ++p; } - while (*p && dbg_isspace((unsigned char)*p)) - ++p; + while (*p && dbg_isspace((unsigned char)*p)) ++p; *word_out = w; return p; } -static int dbg_dispatch(DbgState *s, char *line) { +static int dbg_dispatch(DbgState* s, char* line) { char raw[LINE_CAP]; size_t raw_len = driver_strlen(line); - char *cmd; - char *rest; + char* cmd; + char* rest; - if (raw_len >= sizeof(raw)) - raw_len = sizeof(raw) - 1u; + if (raw_len >= sizeof(raw)) raw_len = sizeof(raw) - 1u; driver_memcpy(raw, line, raw_len); raw[raw_len] = '\0'; rest = dbg_take_word(line, &cmd); - if (!*cmd) - return 0; /* blank line */ + if (!*cmd) return 0; /* blank line */ if (driver_streq(cmd, "h") || driver_streq(cmd, "help")) { dbg_cmd_help(); @@ -2593,13 +2511,13 @@ static int dbg_dispatch(DbgState *s, char *line) { return 0; } if (driver_streq(cmd, "b") || driver_streq(cmd, "break")) { - char *loc; + char* loc; dbg_take_word(rest, &loc); dbg_cmd_break(s, loc); return 0; } if (driver_streq(cmd, "info")) { - char *what; + char* what; rest = dbg_take_word(rest, &what); if (driver_streq(what, "b") || driver_streq(what, "break") || driver_streq(what, "breakpoints")) { @@ -2611,11 +2529,11 @@ static int dbg_dispatch(DbgState *s, char *line) { } else if (driver_streq(what, "args")) { dbg_cmd_info_vars(s, 1u << CFREE_DVR_ARG, "args"); } else if (driver_streq(what, "functions") || driver_streq(what, "func")) { - char *pat; + char* pat; dbg_take_word(rest, &pat); dbg_cmd_info_syms(s, CFREE_SK_FUNC, *pat ? pat : NULL); } else if (driver_streq(what, "variables") || driver_streq(what, "var")) { - char *pat; + char* pat; dbg_take_word(rest, &pat); dbg_cmd_info_syms(s, CFREE_SK_OBJ, *pat ? pat : NULL); } else { @@ -2624,8 +2542,8 @@ static int dbg_dispatch(DbgState *s, char *line) { return 0; } if (driver_streq(cmd, "set")) { - char *name; - char *val_s; + char* name; + char* val_s; uint64_t v; size_t used; rest = dbg_take_word(rest, &name); @@ -2655,7 +2573,7 @@ static int dbg_dispatch(DbgState *s, char *line) { return 0; } if (driver_streq(cmd, "jump") || driver_streq(cmd, "j")) { - char *addr_s; + char* addr_s; uint64_t addr; size_t used; dbg_take_word(rest, &addr_s); @@ -2672,8 +2590,8 @@ static int dbg_dispatch(DbgState *s, char *line) { return 0; } if (driver_streq(cmd, "ignore")) { - char *id_s; - char *cnt_s; + char* id_s; + char* cnt_s; uint64_t id; uint64_t cnt; size_t used; @@ -2697,7 +2615,7 @@ static int dbg_dispatch(DbgState *s, char *line) { return 0; } if (driver_streq(cmd, "d") || driver_streq(cmd, "delete")) { - char *arg; + char* arg; uint64_t id; size_t used; dbg_take_word(rest, &arg); @@ -2714,7 +2632,7 @@ static int dbg_dispatch(DbgState *s, char *line) { return 0; } if (driver_streq(cmd, "enable") || driver_streq(cmd, "disable")) { - char *arg; + char* arg; uint64_t id; size_t used; dbg_take_word(rest, &arg); @@ -2727,7 +2645,7 @@ static int dbg_dispatch(DbgState *s, char *line) { return 0; } if (driver_streq(cmd, "p") || driver_streq(cmd, "print")) { - char *name; + char* name; dbg_take_word(rest, &name); if (!*name) { driver_errf(DBG_TOOL, "usage: p <name>"); @@ -2737,7 +2655,7 @@ static int dbg_dispatch(DbgState *s, char *line) { return 0; } if (driver_streq(cmd, "list") || driver_streq(cmd, "l")) { - char *loc; + char* loc; dbg_take_word(rest, &loc); if (!*loc) { driver_errf(DBG_TOOL, "usage: list file:line"); @@ -2747,8 +2665,8 @@ static int dbg_dispatch(DbgState *s, char *line) { return 0; } if (driver_streq(cmd, "x") || driver_streq(cmd, "examine")) { - char *addr_s; - char *count_s; + char* addr_s; + char* count_s; uint64_t addr; uint64_t count = 16; size_t used; @@ -2791,7 +2709,7 @@ static int dbg_dispatch(DbgState *s, char *line) { * REPL * ============================================================ */ -static void dbg_repl(DbgState *s) { +static void dbg_repl(DbgState* s) { char line[LINE_CAP]; driver_printf("cfree dbg — 'h' for help, 'q' to quit\n"); for (;;) { @@ -2811,8 +2729,7 @@ static void dbg_repl(DbgState *s) { driver_printf("\n"); continue; } - if (dbg_dispatch(s, line)) - return; + if (dbg_dispatch(s, line)) return; } } @@ -2820,11 +2737,11 @@ static void dbg_repl(DbgState *s) { * Top-level entry * ============================================================ */ -int driver_dbg(int argc, char **argv) { +int driver_dbg(int argc, char** argv) { DriverEnv env; DbgOpts o = {0}; - CfreeCompiler *compiler = NULL; - CfreeJit *jit = NULL; + CfreeCompiler* compiler = NULL; + CfreeJit* jit = NULL; DbgState st = {0}; CfreeContext ctx; CfreeJitHost jhost; @@ -2899,8 +2816,7 @@ int driver_dbg(int argc, char **argv) { st.view = cfree_jit_view(jit); if (st.view) { - if (cfree_dwarf_open(&ctx, st.view, &st.dwarf) != CFREE_OK) - st.dwarf = NULL; + if (cfree_dwarf_open(&ctx, st.view, &st.dwarf) != CFREE_OK) st.dwarf = NULL; if (st.dwarf && st.session) { cfree_jit_session_attach_dwarf(st.session, st.dwarf); } @@ -2909,11 +2825,9 @@ int driver_dbg(int argc, char **argv) { dbg_repl(&st); dbg_bps_release_all(&st); - dbg_frontends_release(&st); - if (st.dwarf) - cfree_dwarf_free(st.dwarf); - if (st.session) - cfree_jit_session_free(st.session); + dbg_compile_sessions_release(&st); + if (st.dwarf) cfree_dwarf_free(st.dwarf); + if (st.session) cfree_jit_session_free(st.session); cfree_jit_free(jit); driver_compiler_free(compiler); dbg_options_release(&o); diff --git a/driver/inputs.c b/driver/inputs.c @@ -2,8 +2,9 @@ #include <stddef.h> #include <stdint.h> +#include <string.h> -int driver_inputs_init(DriverInputs *in, DriverEnv *env, const char *tool, +int driver_inputs_init(DriverInputs* in, DriverEnv* env, const char* tool, int argc) { size_t bound = (size_t)argc; in->env = env; @@ -23,10 +24,9 @@ int driver_inputs_init(DriverInputs *in, DriverEnv *env, const char *tool, return 0; } -void driver_inputs_release(DriverInputs *in) { +void driver_inputs_release(DriverInputs* in) { size_t bound = in->bound; - if (in->stdin_buf) - driver_free(in->env, in->stdin_buf, in->stdin_size); + if (in->stdin_buf) driver_free(in->env, in->stdin_buf, in->stdin_size); if (in->sources) driver_free(in->env, in->sources, bound * sizeof(*in->sources)); if (in->source_memory) @@ -40,8 +40,8 @@ void driver_inputs_release(DriverInputs *in) { /* Slurp stdin into the single source_memory entry. Guarded against * duplicates so a user typo (`cfree run - -`) is surfaced rather than * silently leaking the first slurp. */ -static int inputs_record_stdin(DriverInputs *in) { - CfreeSourceInput *slot; +static int inputs_record_stdin(DriverInputs* in) { + CfreeSourceInput* slot; if (in->stdin_buf) { driver_errf(in->tool, "'-' (stdin) may appear at most once"); return -1; @@ -58,9 +58,8 @@ static int inputs_record_stdin(DriverInputs *in) { return 1; } -int driver_inputs_classify(DriverInputs *in, const char *arg) { - if (driver_streq(arg, "-")) - return inputs_record_stdin(in); +int driver_inputs_classify(DriverInputs* in, const char* arg) { + if (driver_streq(arg, "-")) return inputs_record_stdin(in); if (driver_has_suffix(arg, ".c") || driver_has_suffix(arg, ".toy") || driver_has_suffix(arg, ".s") || driver_has_suffix(arg, ".wat") || driver_has_suffix(arg, ".wasm")) { @@ -78,45 +77,40 @@ int driver_inputs_classify(DriverInputs *in, const char *arg) { return 0; } -uint32_t driver_inputs_count(const DriverInputs *in) { +uint32_t driver_inputs_count(const DriverInputs* in) { return in->nsources + in->nsource_memory + in->nobject_files + in->narchives; } -const char *driver_inputs_first_name(const DriverInputs *in) { - if (in->nsources) - return in->sources[0]; - if (in->nsource_memory) - return in->source_memory[0].bytes.name; - if (in->nobject_files) - return in->object_files[0]; - if (in->narchives) - return in->archives[0]; +const char* driver_inputs_first_name(const DriverInputs* in) { + if (in->nsources) return in->sources[0]; + if (in->nsource_memory) return in->source_memory[0].bytes.name; + if (in->nobject_files) return in->object_files[0]; + if (in->narchives) return in->archives[0]; return NULL; } /* Load every input through env.file_io, compile sources via `compiler` with * `copts`, and JIT-link. The compiler must outlive the JIT — it backs * jit->c, which cfree_jit_lookup dereferences. */ -int driver_inputs_compile_and_jit(DriverInputs *in, CfreeCompiler *compiler, - const CfreeJitHost *host, - const CfreeCCompileOptions *copts, - const char *entry, - void *(*extern_resolver)(void *, - const char *), - void *extern_resolver_user, - CfreeJit **out_jit) { - DriverEnv *env = in->env; - const char *tool = in->tool; +int driver_inputs_compile_and_jit(DriverInputs* in, CfreeCompiler* compiler, + const CfreeJitHost* host, + const CfreeCCompileOptions* copts, + const char* entry, + void* (*extern_resolver)(void*, const char*), + void* extern_resolver_user, + CfreeJit** out_jit) { + DriverEnv* env = in->env; + const char* tool = in->tool; CfreeContext ctx = driver_env_to_context(env); - const CfreeFileIO *io = ctx.file_io; - DriverLoad *src_lf = NULL; - DriverLoad *obj_lf = NULL; - DriverLoad *arch_lf = NULL; - CfreeBytes *src_bytes = NULL; /* per-path source bytes for loads */ - CfreeBytes *obj_in = NULL; - CfreeLinkArchiveInput *arch_in = NULL; - CfreeObjBuilder **objs = NULL; - CfreeJitLinkOptions link_opts; + const CfreeFileIO* io = ctx.file_io; + DriverLoad* src_lf = NULL; + DriverLoad* obj_lf = NULL; + DriverLoad* arch_lf = NULL; + CfreeBytes* src_bytes = NULL; /* per-path source bytes for loads */ + CfreeBytes* obj_in = NULL; + CfreeLinkArchiveInput* arch_in = NULL; + CfreeObjBuilder** objs = NULL; + CfreeLinkSession* link = NULL; uint32_t nsrc = in->nsources + in->nsource_memory; uint32_t i; int rc = 1; @@ -167,54 +161,46 @@ int driver_inputs_compile_and_jit(DriverInputs *in, CfreeCompiler *compiler, for (i = 0; i < in->nsources; ++i) { CfreeLanguage lang = cfree_language_for_path(in->sources[i]); + CfreeCompileSessionOptions sopts; + CfreeCompileSession* session = NULL; + CfreeSourceInput sin; CfreeStatus st; - if (lang == CFREE_LANG_C) { - st = cfree_compile_c_obj(compiler, copts, &src_bytes[i], &objs[i]); - } else if (lang == CFREE_LANG_ASM) { - CfreeAsmCompileOptions aopts = {0}; + CfreeAsmCompileOptions aopts = {0}; + memset(&sopts, 0, sizeof(sopts)); + sopts.lang = lang; + sopts.compile.code = copts->code; + sopts.compile.diagnostics = copts->diagnostics; + if (lang == CFREE_LANG_ASM) { aopts.code = copts->code; aopts.diagnostics = copts->diagnostics; - st = cfree_compile_asm_obj(compiler, &aopts, &src_bytes[i], &objs[i]); + sopts.compile.language_options = &aopts; } else { - CfreeFrontendCompileOptions fopts = {0}; - CfreeFrontend *frontend = NULL; - CfreeSourceInput sin; - fopts.code = copts->code; - fopts.diagnostics = copts->diagnostics; - fopts.language_options = copts; - sin.bytes = src_bytes[i]; - sin.lang = lang; - st = cfree_frontend_new(compiler, lang, &frontend); - if (st == CFREE_OK) st = cfree_obj_builder_new(compiler, &objs[i]); - if (st == CFREE_OK) { - st = cfree_frontend_compile(frontend, &fopts, &sin, objs[i]); - } - cfree_frontend_free(frontend); + sopts.compile.language_options = copts; } + memset(&sin, 0, sizeof(sin)); + sin.bytes = src_bytes[i]; + sin.lang = lang; + st = cfree_compile_session_new(compiler, &sopts, &session); + if (st == CFREE_OK) + st = cfree_compile_session_compile(session, &sin, &objs[i]); + cfree_compile_session_free(session); if (st != CFREE_OK) goto out; } for (i = 0; i < in->nsource_memory; ++i) { - /* For in-memory inputs, dispatch through the registered frontend so - * lang tagging is honoured. */ - CfreeFrontendCompileOptions fopts; - CfreeFrontendCompileOptions z = {0}; - CfreeFrontend *frontend = NULL; + CfreeCompileSessionOptions sopts; + CfreeCompileSession* session = NULL; CfreeStatus st; - fopts = z; - fopts.code = copts->code; - fopts.diagnostics = copts->diagnostics; - fopts.language_options = copts; - st = cfree_frontend_new(compiler, in->source_memory[i].lang, &frontend); - if (st == CFREE_OK) { - st = cfree_obj_builder_new(compiler, &objs[in->nsources + i]); - } - if (st == CFREE_OK) { - st = cfree_frontend_compile(frontend, &fopts, &in->source_memory[i], - objs[in->nsources + i]); - } - cfree_frontend_free(frontend); - if (st != CFREE_OK) - goto out; + memset(&sopts, 0, sizeof(sopts)); + sopts.lang = in->source_memory[i].lang; + sopts.compile.code = copts->code; + sopts.compile.diagnostics = copts->diagnostics; + sopts.compile.language_options = copts; + st = cfree_compile_session_new(compiler, &sopts, &session); + if (st == CFREE_OK) + st = cfree_compile_session_compile(session, &in->source_memory[i], + &objs[in->nsources + i]); + cfree_compile_session_free(session); + if (st != CFREE_OK) goto out; } for (i = 0; i < in->nobject_files; ++i) { @@ -232,48 +218,44 @@ int driver_inputs_compile_and_jit(DriverInputs *in, CfreeCompiler *compiler, } { - CfreeJitLinkOptions z = {0}; - link_opts = z; + CfreeLinkSessionOptions lopts; + CfreeStatus st; + memset(&lopts, 0, sizeof(lopts)); + lopts.output_kind = CFREE_LINK_OUTPUT_JIT; + lopts.entry = entry; + lopts.jit_host = host; + lopts.extern_resolver = extern_resolver; + lopts.extern_resolver_user = extern_resolver_user; + st = cfree_link_session_new(compiler, &lopts, &link); + for (i = 0; st == CFREE_OK && i < nsrc; ++i) + st = cfree_link_session_add_obj(link, objs[i]); + for (i = 0; st == CFREE_OK && i < in->nobject_files; ++i) + st = cfree_link_session_add_obj_bytes(link, &obj_in[i]); + for (i = 0; st == CFREE_OK && i < in->narchives; ++i) + st = cfree_link_session_add_archive_bytes(link, &arch_in[i]); + if (st == CFREE_OK) st = cfree_link_session_jit(link, out_jit); + rc = st == CFREE_OK ? 0 : 1; } - link_opts.inputs.objs = objs; - link_opts.inputs.nobjs = nsrc; - link_opts.inputs.obj_bytes = obj_in; - link_opts.inputs.nobj_bytes = in->nobject_files; - link_opts.inputs.archives = arch_in; - link_opts.inputs.narchives = in->narchives; - link_opts.inputs.entry = entry; - link_opts.extern_resolver = extern_resolver; - link_opts.extern_resolver_user = extern_resolver_user; - - rc = cfree_link_jit(compiler, &link_opts, host, out_jit) == CFREE_OK ? 0 : 1; out: + cfree_link_session_free(link); if (arch_lf) { - for (i = 0; i < in->narchives; ++i) - driver_release_bytes(io, &arch_lf[i]); + for (i = 0; i < in->narchives; ++i) driver_release_bytes(io, &arch_lf[i]); } if (obj_lf) { for (i = 0; i < in->nobject_files; ++i) driver_release_bytes(io, &obj_lf[i]); } if (src_lf) { - for (i = 0; i < in->nsources; ++i) - driver_release_bytes(io, &src_lf[i]); + for (i = 0; i < in->nsources; ++i) driver_release_bytes(io, &src_lf[i]); } - if (arch_in) - driver_free(env, arch_in, in->narchives * sizeof(*arch_in)); - if (arch_lf) - driver_free(env, arch_lf, in->narchives * sizeof(*arch_lf)); - if (obj_in) - driver_free(env, obj_in, in->nobject_files * sizeof(*obj_in)); - if (obj_lf) - driver_free(env, obj_lf, in->nobject_files * sizeof(*obj_lf)); - if (src_lf) - driver_free(env, src_lf, in->nsources * sizeof(*src_lf)); - if (src_bytes) - driver_free(env, src_bytes, in->nsources * sizeof(*src_bytes)); - if (objs) - driver_free(env, objs, nsrc * sizeof(*objs)); + if (arch_in) driver_free(env, arch_in, in->narchives * sizeof(*arch_in)); + if (arch_lf) driver_free(env, arch_lf, in->narchives * sizeof(*arch_lf)); + if (obj_in) driver_free(env, obj_in, in->nobject_files * sizeof(*obj_in)); + if (obj_lf) driver_free(env, obj_lf, in->nobject_files * sizeof(*obj_lf)); + if (src_lf) driver_free(env, src_lf, in->nsources * sizeof(*src_lf)); + if (src_bytes) driver_free(env, src_bytes, in->nsources * sizeof(*src_bytes)); + if (objs) driver_free(env, objs, nsrc * sizeof(*objs)); return rc; } diff --git a/driver/ld.c b/driver/ld.c @@ -2,6 +2,7 @@ #include <cfree/link.h> #include <cfree/object.h> #include <stdint.h> +#include <string.h> #include "driver.h" #include "lib_resolve.h" @@ -104,9 +105,9 @@ typedef struct LdOptions { uint32_t nrpaths; const char** rpath_links; /* -rpath-link DIR (advisory) */ uint32_t nrpath_links; - int new_dtags; /* 1=DT_RUNPATH (default), 0=DT_RPATH */ - int export_dynamic; /* -E / --export-dynamic */ - int gc_sections; /* --gc-sections / --no-gc-sections */ + int new_dtags; /* 1=DT_RUNPATH (default), 0=DT_RPATH */ + int export_dynamic; /* -E / --export-dynamic */ + int gc_sections; /* --gc-sections / --no-gc-sections */ int allow_undefined; /* shared output undefined-symbol policy */ /* --build-id state */ @@ -191,7 +192,8 @@ void driver_help_ld(void) { " --no-gc-sections Disable section GC (default)\n" " -E, --export-dynamic Promote defined globals into dynsym\n" " (no-op for -shared; recorded for exe)\n" - " --no-undefined Reject unresolved symbols in -shared output\n" + " --no-undefined Reject unresolved symbols in -shared " + "output\n" " -z defs Same as --no-undefined\n" "\n" "BUILD ID\n" @@ -501,9 +503,9 @@ static int ld_parse(int argc, char** argv, LdOptions* o) { char* resolved; size_t resolved_size; LibResolveKind kind; - LibResolveMode mode = - (o->cur_link_mode == CFREE_LM_STATIC) ? LIB_RESOLVE_STATIC_ONLY - : LIB_RESOLVE_DYNAMIC_PREFER; + LibResolveMode mode = (o->cur_link_mode == CFREE_LM_STATIC) + ? LIB_RESOLVE_STATIC_ONLY + : LIB_RESOLVE_DYNAMIC_PREFER; if (driver_lib_resolve(o->env, val, mode, o->lib_dirs, o->nlib_dirs, &resolved, &resolved_size, &kind) != 0) { driver_errf(LD_TOOL, "cannot find -l%s", val); @@ -847,10 +849,7 @@ static int ld_run_link(LdOptions* o) { CfreeLinkArchiveInput* arch_in = NULL; CfreeBytes* dso_in = NULL; CfreeLinkScript* script = NULL; - CfreeLinkInputs inputs; - CfreeExeLinkOptions link_opts; - CfreeSharedLinkOptions shared_opts; - CfreeRelocatableLinkOptions reloc_opts; + CfreeLinkSession* link = NULL; uint32_t i; int rc = 1; @@ -962,35 +961,29 @@ static int ld_run_link(LdOptions* o) { goto out; } - { - CfreeLinkInputs zero = {0}; - inputs = zero; + if (o->soname || o->nrpaths || o->nrpath_links) { + if (!o->shared) { + driver_errf(LD_TOOL, "-soname/-rpath/-rpath-link require -shared"); + goto out; + } } - inputs.obj_bytes = obj_in; - inputs.nobj_bytes = o->nobject_files; - inputs.archives = arch_in; - inputs.narchives = o->narchives; - inputs.dso_bytes = dso_in; - inputs.ndso_bytes = o->ndsos; - inputs.order = o->order; - inputs.norder = o->norder; - inputs.linker_script = script; - inputs.entry = o->entry; - inputs.build_id_mode = o->build_id_mode; - inputs.build_id_bytes = o->build_id_bytes; - inputs.build_id_len = o->build_id_len; - if (o->relocatable) { - CfreeRelocatableLinkOptions zero = {0}; - reloc_opts = zero; - reloc_opts.inputs = inputs; - rc = cfree_link_relocatable(compiler, &reloc_opts, writer) == CFREE_OK ? 0 - : 1; - } else if (o->shared) { - CfreeSharedLinkOptions zero = {0}; - shared_opts = zero; - shared_opts.inputs = inputs; - shared_opts.soname = o->soname; + { + CfreeLinkSessionOptions lopts; + CfreeStatus st; + memset(&lopts, 0, sizeof(lopts)); + lopts.output_kind = o->relocatable ? CFREE_LINK_OUTPUT_RELOCATABLE + : o->shared ? CFREE_LINK_OUTPUT_SHARED + : CFREE_LINK_OUTPUT_EXE; + lopts.entry = o->entry; + lopts.linker_script = script; + lopts.build_id_mode = o->build_id_mode; + lopts.build_id_bytes = o->build_id_bytes; + lopts.build_id_len = o->build_id_len; + lopts.gc_sections = o->gc_sections; + lopts.pie = o->pie; + lopts.interp_path = o->interp_path; + lopts.soname = o->soname; /* Per --enable-new-dtags / --disable-new-dtags: when new_dtags is * set (the default), -rpath entries land in DT_RUNPATH; otherwise * in DT_RPATH. -rpath-link is link-time-only and is forwarded as @@ -999,34 +992,50 @@ static int ld_run_link(LdOptions* o) { * write itself, so this matches GNU-ld behaviour where rpath-link * does not appear in DT_*PATH). */ if (o->new_dtags) { - shared_opts.runpaths = o->rpaths; - shared_opts.nrunpaths = o->nrpaths; + lopts.runpaths = o->rpaths; + lopts.nrunpaths = o->nrpaths; } else { - shared_opts.rpaths = o->rpaths; - shared_opts.nrpaths = o->nrpaths; + lopts.rpaths = o->rpaths; + lopts.nrpaths = o->nrpaths; } /* By default shared output may resolve symbols against its loader at * runtime; --no-undefined / -z defs tightens that policy. */ - shared_opts.allow_undefined = o->allow_undefined ? 1 : 0; - shared_opts.gc_sections = o->gc_sections; + lopts.allow_undefined = o->allow_undefined ? 1 : 0; (void)o->export_dynamic; - rc = cfree_link_shared(compiler, &shared_opts, writer) == CFREE_OK ? 0 : 1; - } else { - CfreeExeLinkOptions zero = {0}; - link_opts = zero; - link_opts.inputs = inputs; - link_opts.gc_sections = o->gc_sections; - link_opts.pie = o->pie; - link_opts.interp_path = o->interp_path; - if (o->soname || o->nrpaths || o->nrpath_links) { - driver_errf(LD_TOOL, "-soname/-rpath/-rpath-link require -shared"); - goto out; - } - rc = cfree_link_exe(compiler, &link_opts, writer) == CFREE_OK ? 0 : 1; + + st = cfree_link_session_new(compiler, &lopts, &link); + if (o->order && o->norder) { + for (i = 0; i < o->norder && st == CFREE_OK; ++i) { + const CfreeLinkInputOrder* ord = &o->order[i]; + switch ((CfreeLinkInputOrderKind)ord->kind) { + case CFREE_LINK_INPUT_OBJ: + case CFREE_LINK_INPUT_OBJ_BYTES: + st = cfree_link_session_add_obj_bytes(link, &obj_in[ord->index]); + break; + case CFREE_LINK_INPUT_ARCHIVE: + st = cfree_link_session_add_archive_bytes(link, + &arch_in[ord->index]); + break; + case CFREE_LINK_INPUT_DSO: + st = cfree_link_session_add_dso_bytes(link, &dso_in[ord->index]); + break; + } + } + } else { + for (i = 0; i < o->nobject_files && st == CFREE_OK; ++i) + st = cfree_link_session_add_obj_bytes(link, &obj_in[i]); + for (i = 0; i < o->narchives && st == CFREE_OK; ++i) + st = cfree_link_session_add_archive_bytes(link, &arch_in[i]); + for (i = 0; i < o->ndsos && st == CFREE_OK; ++i) + st = cfree_link_session_add_dso_bytes(link, &dso_in[i]); + } + if (st == CFREE_OK) st = cfree_link_session_emit(link, writer); + rc = st == CFREE_OK ? 0 : 1; } out: if (writer) cfree_writer_close(writer); + cfree_link_session_free(link); /* Match compiler/linker drivers: successful link outputs get executable * file modes while still respecting the process umask. Done after closing * the writer so the bits are stable on disk. */ diff --git a/driver/runtime.c b/driver/runtime.c @@ -4,6 +4,7 @@ #include <cfree/compile.h> #include <cfree/core.h> #include <stdint.h> +#include <string.h> #include "lang/c/c.h" @@ -503,16 +504,51 @@ static int rt_compile_source(DriverEnv* env, goto out; asm_input.data = cfree_writer_mem_bytes(pp_writer, &asm_input.len); } - st = cfree_compile_asm_obj_emit(compiler, &aopts, &asm_input, writer); + { + CfreeCompileSessionOptions sopts; + CfreeCompileSession* session = NULL; + CfreeSourceInput sin; + CfreeObjBuilder* ob = NULL; + memset(&sopts, 0, sizeof(sopts)); + sopts.lang = CFREE_LANG_ASM; + sopts.compile.code = aopts.code; + sopts.compile.diagnostics = aopts.diagnostics; + sopts.compile.language_options = &aopts; + memset(&sin, 0, sizeof(sin)); + sin.bytes = asm_input; + sin.lang = CFREE_LANG_ASM; + st = cfree_compile_session_new(compiler, &sopts, &session); + if (st == CFREE_OK) + st = cfree_compile_session_compile(session, &sin, &ob); + if (st == CFREE_OK) st = cfree_obj_builder_emit(ob, writer); + cfree_obj_builder_free(ob); + cfree_compile_session_free(session); + } } else { CfreeCCompileOptions copts = {0}; + CfreeCompileSessionOptions sopts; + CfreeCompileSession* session = NULL; + CfreeSourceInput sin; + CfreeObjBuilder* ob = NULL; char** owned_dirs = NULL; size_t* owned_sizes = NULL; uint32_t owned_count = 0; if (rt_prepare_pp(env, support, variant, 0, &copts.preprocess, &owned_dirs, &owned_sizes, &owned_count) != 0) goto out; - st = cfree_compile_c_obj_emit(compiler, &copts, &input, writer); + memset(&sopts, 0, sizeof(sopts)); + sopts.lang = CFREE_LANG_C; + sopts.compile.code = copts.code; + sopts.compile.diagnostics = copts.diagnostics; + sopts.compile.language_options = &copts; + memset(&sin, 0, sizeof(sin)); + sin.bytes = input; + sin.lang = CFREE_LANG_C; + st = cfree_compile_session_new(compiler, &sopts, &session); + if (st == CFREE_OK) st = cfree_compile_session_compile(session, &sin, &ob); + if (st == CFREE_OK) st = cfree_obj_builder_emit(ob, writer); + cfree_obj_builder_free(ob); + cfree_compile_session_free(session); rt_free_pp(env, &copts.preprocess, owned_dirs, owned_sizes, owned_count); } if (st != CFREE_OK || cfree_writer_status(writer) != CFREE_OK) { diff --git a/include/cfree/cg.h b/include/cfree/cg.h @@ -110,13 +110,13 @@ typedef struct CfreeCgFuncSig { typedef struct CfreeCgField { CfreeSym name; /* 0 for anonymous fields/tuple elements */ CfreeCgTypeId type; - uint32_t align_override; /* 0 = natural, 1 = packed, >1 explicit align */ - uint32_t max_align; /* 0 = natural, otherwise cap field alignment */ - uint32_t flags; /* CfreeCgFieldFlag */ - uint16_t bit_width; /* valid for bit-fields, may be 0 for barriers */ - uint16_t bit_offset; /* filled by record-field queries */ + uint32_t align_override; /* 0 = natural, 1 = packed, >1 explicit align */ + uint32_t max_align; /* 0 = natural, otherwise cap field alignment */ + uint32_t flags; /* CfreeCgFieldFlag */ + uint16_t bit_width; /* valid for bit-fields, may be 0 for barriers */ + uint16_t bit_offset; /* filled by record-field queries */ uint32_t bit_storage_size; /* bytes, filled by record-field queries */ - int bit_signed; /* signed extraction for bit-field loads */ + int bit_signed; /* signed extraction for bit-field loads */ } CfreeCgField; typedef enum CfreeCgFieldFlag { @@ -159,8 +159,7 @@ CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler*, CfreeSym name, CfreeCgTypeId cfree_cg_type_record(CfreeCompiler*, CfreeSym tag, const CfreeCgField* fields, uint32_t nfields); -CfreeCgTypeId cfree_cg_type_record_ex(CfreeCompiler*, - const CfreeCgRecordDesc*); +CfreeCgTypeId cfree_cg_type_record_ex(CfreeCompiler*, const CfreeCgRecordDesc*); CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler*, CfreeSym tag, CfreeCgTypeId base, const CfreeCgEnumValue* values, @@ -182,7 +181,7 @@ CfreeCgTypeId cfree_cg_type_func_ret(CfreeCompiler*, CfreeCgTypeId); CfreeCgAbiAttrs cfree_cg_type_func_ret_attrs(CfreeCompiler*, CfreeCgTypeId); uint32_t cfree_cg_type_func_nparams(CfreeCompiler*, CfreeCgTypeId); CfreeCgFuncParam cfree_cg_type_func_param(CfreeCompiler*, CfreeCgTypeId, - uint32_t index); + uint32_t index); CfreeCgCallConv cfree_cg_type_func_call_conv(CfreeCompiler*, CfreeCgTypeId); int cfree_cg_type_func_is_variadic(CfreeCompiler*, CfreeCgTypeId); @@ -318,9 +317,9 @@ typedef enum CfreeCgObjectFlag { typedef struct CfreeCgObjectAttrs { CfreeCgTlsModel tls_model; - uint32_t flags; /* CfreeCgObjectFlag */ + uint32_t flags; /* CfreeCgObjectFlag */ CfreeSym section; /* 0 = target default */ - uint32_t align; /* 0 = natural */ + uint32_t align; /* 0 = natural */ } CfreeCgObjectAttrs; typedef enum CfreeCgDeclKind { @@ -372,8 +371,10 @@ CfreeSym cfree_cg_c_linkage_name(CfreeCompiler*, CfreeSym source_name); * Lifecycle and Source Locations * ============================================================ */ -CfreeStatus cfree_cg_new(CfreeCompiler*, CfreeObjBuilder* out, - const CfreeCodeOptions*, CfreeCg** cg_out); +CfreeStatus cfree_cg_new(CfreeCompiler*, CfreeCg** cg_out); +CfreeStatus cfree_cg_begin_obj(CfreeCg*, CfreeObjBuilder* out, + const CfreeCodeOptions*); +CfreeStatus cfree_cg_end_obj(CfreeCg*); void cfree_cg_free(CfreeCg*); /* Sticky source location. Function, scope, local, param, instruction, and @@ -569,11 +570,11 @@ void cfree_cg_store(CfreeCg*, CfreeCgMemAccess access); /* [lv, rv] -> [] */ * The frontend allocates a local of CFREE_CG_BUILTIN_VARARG_STATE and pushes * that local's address before each operation. The implementation reads and * writes the state in memory according to the target ABI. */ -void cfree_cg_vararg_start(CfreeCg*); /* pop &state */ +void cfree_cg_vararg_start(CfreeCg*); /* pop &state */ void cfree_cg_vararg_next(CfreeCg*, - CfreeCgTypeId type); /* pop &state; push value */ -void cfree_cg_vararg_end(CfreeCg*); /* pop &state */ -void cfree_cg_vararg_copy(CfreeCg*); /* pop &dst, &src */ + CfreeCgTypeId type); /* pop &state; push value */ +void cfree_cg_vararg_end(CfreeCg*); /* pop &state */ +void cfree_cg_vararg_copy(CfreeCg*); /* pop &dst, &src */ /* ============================================================ * Integer Operations @@ -744,40 +745,40 @@ void cfree_cg_ret_void(CfreeCg*); typedef enum CfreeCgIntrinsic { CFREE_CG_INTRIN_TRAP, - CFREE_CG_INTRIN_CLZ, /* zero input returns bit width */ - CFREE_CG_INTRIN_CTZ, /* zero input returns bit width */ + CFREE_CG_INTRIN_CLZ, /* zero input returns bit width */ + CFREE_CG_INTRIN_CTZ, /* zero input returns bit width */ CFREE_CG_INTRIN_POPCOUNT, CFREE_CG_INTRIN_BSWAP, - CFREE_CG_INTRIN_SETJMP, /* pop &buf; push i32 */ - CFREE_CG_INTRIN_LONGJMP, /* pop &buf, val; no return */ - CFREE_CG_INTRIN_SADD_OVERFLOW, /* pop a, b; push result, overflow */ - CFREE_CG_INTRIN_UADD_OVERFLOW, /* pop a, b; push result, overflow */ - CFREE_CG_INTRIN_SSUB_OVERFLOW, /* pop a, b; push result, overflow */ - CFREE_CG_INTRIN_USUB_OVERFLOW, /* pop a, b; push result, overflow */ - CFREE_CG_INTRIN_SMUL_OVERFLOW, /* pop a, b; push result, overflow */ - CFREE_CG_INTRIN_UMUL_OVERFLOW, /* pop a, b; push result, overflow */ - CFREE_CG_INTRIN_FMA, /* pop a, b, c; push a * b + c */ - CFREE_CG_INTRIN_PREFETCH, /* pop addr; no result */ - CFREE_CG_INTRIN_EXPECT, /* pop val, expected; push val */ - CFREE_CG_INTRIN_ASSUME_ALIGNED, /* pop ptr; push aligned ptr */ - CFREE_CG_INTRIN_SYSCALL, /* pop nr, args...; push long */ - CFREE_CG_INTRIN_IRQ_SAVE, /* push unsigned long */ - CFREE_CG_INTRIN_IRQ_RESTORE, /* pop prev */ + CFREE_CG_INTRIN_SETJMP, /* pop &buf; push i32 */ + CFREE_CG_INTRIN_LONGJMP, /* pop &buf, val; no return */ + CFREE_CG_INTRIN_SADD_OVERFLOW, /* pop a, b; push result, overflow */ + CFREE_CG_INTRIN_UADD_OVERFLOW, /* pop a, b; push result, overflow */ + CFREE_CG_INTRIN_SSUB_OVERFLOW, /* pop a, b; push result, overflow */ + CFREE_CG_INTRIN_USUB_OVERFLOW, /* pop a, b; push result, overflow */ + CFREE_CG_INTRIN_SMUL_OVERFLOW, /* pop a, b; push result, overflow */ + CFREE_CG_INTRIN_UMUL_OVERFLOW, /* pop a, b; push result, overflow */ + CFREE_CG_INTRIN_FMA, /* pop a, b, c; push a * b + c */ + CFREE_CG_INTRIN_PREFETCH, /* pop addr; no result */ + CFREE_CG_INTRIN_EXPECT, /* pop val, expected; push val */ + CFREE_CG_INTRIN_ASSUME_ALIGNED, /* pop ptr; push aligned ptr */ + CFREE_CG_INTRIN_SYSCALL, /* pop nr, args...; push long */ + CFREE_CG_INTRIN_IRQ_SAVE, /* push unsigned long */ + CFREE_CG_INTRIN_IRQ_RESTORE, /* pop prev */ CFREE_CG_INTRIN_IRQ_DISABLE, CFREE_CG_INTRIN_IRQ_ENABLE, - CFREE_CG_INTRIN_DMB, /* pop CfreeCgBarrierScope */ - CFREE_CG_INTRIN_DSB, /* pop CfreeCgBarrierScope */ + CFREE_CG_INTRIN_DMB, /* pop CfreeCgBarrierScope */ + CFREE_CG_INTRIN_DSB, /* pop CfreeCgBarrierScope */ CFREE_CG_INTRIN_ISB, - CFREE_CG_INTRIN_DCACHE_CLEAN, /* pop ptr, size */ + CFREE_CG_INTRIN_DCACHE_CLEAN, /* pop ptr, size */ CFREE_CG_INTRIN_DCACHE_INVALIDATE, CFREE_CG_INTRIN_DCACHE_CLEAN_INVALIDATE, CFREE_CG_INTRIN_ICACHE_INVALIDATE, CFREE_CG_INTRIN_CPU_NOP, CFREE_CG_INTRIN_CPU_YIELD, CFREE_CG_INTRIN_WFI, - CFREE_CG_INTRIN_WFE, /* arm/aarch64 only */ - CFREE_CG_INTRIN_SEV, /* arm/aarch64 only */ - CFREE_CG_INTRIN_CORO_SWITCH, /* pop from, to, value; push value */ + CFREE_CG_INTRIN_WFE, /* arm/aarch64 only */ + CFREE_CG_INTRIN_SEV, /* arm/aarch64 only */ + CFREE_CG_INTRIN_CORO_SWITCH, /* pop from, to, value; push value */ } CfreeCgIntrinsic; typedef enum CfreeCgBarrierScope { @@ -791,8 +792,8 @@ typedef enum CfreeCgBarrierScope { /* Pops nargs operands. Pushes result_type unless result_type is * CFREE_CG_TYPE_NONE or void. Overflow intrinsics push two values: - * result, overflow_bool regardless of result_type. Syscall uses nargs = argc + 1: - * the syscall number plus 0..6 long arguments. Runtime-extension intrinsics + * result, overflow_bool regardless of result_type. Syscall uses nargs = argc + + * 1: the syscall number plus 0..6 long arguments. Runtime-extension intrinsics * mirror rt/include/cfree/{syscall,baremetal,coro}.h and must diagnose targets * where the primitive has no legal lowering. */ void cfree_cg_intrinsic(CfreeCg*, CfreeCgIntrinsic, uint32_t nargs, @@ -846,8 +847,8 @@ void cfree_cg_atomic_rmw(CfreeCg*, CfreeCgMemAccess access, CfreeCgAtomicOp, CfreeCgMemOrder order); /* Stack: [ptr, expected, desired] -> [prior, ok_bool]. */ void cfree_cg_atomic_cmpxchg(CfreeCg*, CfreeCgMemAccess access, - CfreeCgMemOrder success, - CfreeCgMemOrder failure, int weak); + CfreeCgMemOrder success, CfreeCgMemOrder failure, + int weak); void cfree_cg_atomic_fence(CfreeCg*, CfreeCgMemOrder); /* ============================================================ @@ -892,7 +893,7 @@ typedef struct CfreeCgInlineAsm { uint32_t ninputs; const CfreeSym* clobbers; uint32_t nclobbers; - uint32_t flags; /* CfreeCgAsmFlag */ + uint32_t flags; /* CfreeCgAsmFlag */ uint32_t clobber_abi_sets; /* CfreeCgAsmClobberAbiSet */ } CfreeCgInlineAsm; @@ -982,8 +983,7 @@ void cfree_cg_data_symdiff(CfreeCg*, CfreeCgSym lhs, CfreeCgSym rhs, * ============================================================ */ static inline void cfree_cg_push_bytes(CfreeCg* cg, const uint8_t* data, - size_t len, - CfreeCgTypeId pointee_type) { + size_t len, CfreeCgTypeId pointee_type) { CfreeCgSym sym = cfree_cg_const_data(cg, data, len, 0, pointee_type); cfree_cg_push_symbol_addr(cg, sym, 0); } @@ -1041,24 +1041,23 @@ static inline void cfree_cg_musttail_call_symbol(CfreeCg* cg, CfreeCgSym sym, * op is CFREE_CG_INT_ADD or CFREE_CG_INT_SUB. ty is the promoted integer type * of the lvalue. */ static inline void cfree_cg_inc_dec(CfreeCg* cg, CfreeCgIntBinOp op, int post, - CfreeCgTypeId ty, - CfreeCgMemAccess access) { + CfreeCgTypeId ty, CfreeCgMemAccess access) { cfree_cg_dup(cg); /* [lv, lv] */ cfree_cg_load(cg, access); /* [lv, old] */ if (post) { - cfree_cg_dup(cg); /* [lv, old, old] */ - cfree_cg_push_int(cg, 1, ty); /* [lv, old, old, 1] */ - cfree_cg_int_binop(cg, op, 0); /* [lv, old, new] */ - cfree_cg_rot3(cg); /* [old, new, lv] */ - cfree_cg_swap(cg); /* [old, lv, new] */ - cfree_cg_store(cg, access); /* [old] */ + cfree_cg_dup(cg); /* [lv, old, old] */ + cfree_cg_push_int(cg, 1, ty); /* [lv, old, old, 1] */ + cfree_cg_int_binop(cg, op, 0); /* [lv, old, new] */ + cfree_cg_rot3(cg); /* [old, new, lv] */ + cfree_cg_swap(cg); /* [old, lv, new] */ + cfree_cg_store(cg, access); /* [old] */ } else { - cfree_cg_push_int(cg, 1, ty); /* [lv, old, 1] */ - cfree_cg_int_binop(cg, op, 0); /* [lv, new] */ - cfree_cg_dup(cg); /* [lv, new, new] */ - cfree_cg_rot3(cg); /* [new, new, lv] */ - cfree_cg_swap(cg); /* [new, lv, new] */ - cfree_cg_store(cg, access); /* [new] */ + cfree_cg_push_int(cg, 1, ty); /* [lv, old, 1] */ + cfree_cg_int_binop(cg, op, 0); /* [lv, new] */ + cfree_cg_dup(cg); /* [lv, new, new] */ + cfree_cg_rot3(cg); /* [new, new, lv] */ + cfree_cg_swap(cg); /* [new, lv, new] */ + cfree_cg_store(cg, access); /* [new] */ } } @@ -1115,7 +1114,8 @@ static inline void cfree_cg_bitset(CfreeCg* cg, CfreeCgTypeId ty, uint32_t lo, cfree_cg_rot3(cg); /* [dst, dst_cleared, src] */ if (lo > 0) { cfree_cg_push_int(cg, lo, ty); - cfree_cg_int_binop(cg, CFREE_CG_INT_SHL, 0); /* [dst, dst_cleared, src<<lo] */ + cfree_cg_int_binop(cg, CFREE_CG_INT_SHL, + 0); /* [dst, dst_cleared, src<<lo] */ } cfree_cg_push_int(cg, field_mask, ty); cfree_cg_int_binop(cg, CFREE_CG_INT_AND, 0); /* [dst, dst_cleared, bits] */ diff --git a/include/cfree/compile.h b/include/cfree/compile.h @@ -21,26 +21,21 @@ typedef enum CfreeLanguage { CFREE_LANG_COUNT = 4, } CfreeLanguage; -typedef struct CfreeSourceInput { - CfreeBytes bytes; - CfreeLanguage lang; -} CfreeSourceInput; - typedef struct CfreeDefine { - const char *name; - const char *body; /* NULL means "1" */ + const char* name; + const char* body; /* NULL means "1" */ } CfreeDefine; typedef CfreeDefine CfreePredefinedMacro; typedef struct CfreePreprocessOptions { - const char *const *include_dirs; + const char* const* include_dirs; uint32_t ninclude_dirs; - const char *const *system_include_dirs; + const char* const* system_include_dirs; uint32_t nsystem_include_dirs; - const CfreeDefine *defines; + const CfreeDefine* defines; uint32_t ndefines; - const char *const *undefines; + const char* const* undefines; uint32_t nundefines; } CfreePreprocessOptions; @@ -67,22 +62,29 @@ typedef enum CfreeFrontendInputKind { CFREE_FRONTEND_INPUT_REPL_BLOCK = 3, } CfreeFrontendInputKind; +typedef struct CfreeSourceInput { + CfreeBytes bytes; + CfreeLanguage lang; + CfreeFrontendInputKind input_kind; + const char* repl_entry_name; +} CfreeSourceInput; + typedef struct CfreeFrontendCompileOptions { CfreeCodeOptions code; CfreeDiagnosticOptions diagnostics; - const void *language_options; + const void* language_options; CfreeFrontendInputKind input_kind; - const char *repl_entry_name; + const char* repl_entry_name; } CfreeFrontendCompileOptions; typedef struct CfreeFrontend CfreeFrontend; typedef struct CfreeFrontendState CfreeFrontendState; -typedef CfreeFrontendState *(*CfreeFrontendNewFn)(CfreeCompiler *); +typedef CfreeFrontendState* (*CfreeFrontendNewFn)(CfreeCompiler*); typedef CfreeStatus (*CfreeFrontendCompileFn)( - CfreeFrontendState *, const CfreeFrontendCompileOptions *, - const CfreeSourceInput *, CfreeObjBuilder *out); -typedef void (*CfreeFrontendFreeFn)(CfreeFrontendState *); + CfreeFrontendState*, const CfreeFrontendCompileOptions*, + const CfreeSourceInput*, CfreeObjBuilder* out); +typedef void (*CfreeFrontendFreeFn)(CfreeFrontendState*); typedef struct CfreeFrontendVTable { CfreeFrontendNewFn new_frontend; @@ -90,44 +92,39 @@ typedef struct CfreeFrontendVTable { CfreeFrontendFreeFn free_frontend; } CfreeFrontendVTable; -CfreeLanguage cfree_language_for_path(const char *path); -CfreeStatus cfree_register_frontend(CfreeCompiler *, CfreeLanguage, - const CfreeFrontendVTable *); -CfreeStatus cfree_frontend_new(CfreeCompiler *, CfreeLanguage, - CfreeFrontend **out); -CfreeStatus cfree_frontend_compile(CfreeFrontend *, - const CfreeFrontendCompileOptions *, - const CfreeSourceInput *, - CfreeObjBuilder *out); -void cfree_frontend_free(CfreeFrontend *); - -uint32_t cfree_compiler_arch_predefines(CfreeCompiler *, - const CfreePredefinedMacro **out); - -CfreeStatus cfree_compile_c_obj(CfreeCompiler *, const CfreeCCompileOptions *, - const CfreeBytes *, CfreeObjBuilder **out); -CfreeStatus cfree_compile_c_obj_emit(CfreeCompiler *, - const CfreeCCompileOptions *, - const CfreeBytes *, CfreeWriter *out); -CfreeStatus cfree_compile_asm_obj(CfreeCompiler *, - const CfreeAsmCompileOptions *, - const CfreeBytes *, CfreeObjBuilder **out); -CfreeStatus cfree_compile_asm_obj_emit(CfreeCompiler *, - const CfreeAsmCompileOptions *, - const CfreeBytes *, CfreeWriter *out); +CfreeLanguage cfree_language_for_path(const char* path); +CfreeStatus cfree_register_frontend(CfreeCompiler*, CfreeLanguage, + const CfreeFrontendVTable*); + +uint32_t cfree_compiler_arch_predefines(CfreeCompiler*, + const CfreePredefinedMacro** out); + +typedef struct CfreeCompileSessionOptions { + CfreeLanguage lang; + CfreeFrontendCompileOptions compile; +} CfreeCompileSessionOptions; + +CfreeStatus cfree_compile_session_new(CfreeCompiler*, + const CfreeCompileSessionOptions*, + CfreeCompileSession** out); +CfreeStatus cfree_compile_session_compile(CfreeCompileSession*, + const CfreeSourceInput*, + CfreeObjBuilder** out); +void cfree_compile_session_free(CfreeCompileSession*); + typedef struct CfreeDepIter CfreeDepIter; typedef struct CfreeDepEdge { - const char *includer_name; - const char *included_name; + const char* includer_name; + const char* included_name; CfreeSrcLoc include_loc; uint8_t from_system_path; uint8_t bracketed; uint8_t pad[2]; } CfreeDepEdge; -CfreeStatus cfree_dep_iter_new(CfreeCompiler *, CfreeDepIter **out); -CfreeIterResult cfree_dep_iter_next(CfreeDepIter *, CfreeDepEdge *out); -void cfree_dep_iter_free(CfreeDepIter *); +CfreeStatus cfree_dep_iter_new(CfreeCompiler*, CfreeDepIter** out); +CfreeIterResult cfree_dep_iter_next(CfreeDepIter*, CfreeDepEdge* out); +void cfree_dep_iter_free(CfreeDepIter*); #endif diff --git a/include/cfree/core.h b/include/cfree/core.h @@ -18,8 +18,10 @@ /* Opaque handles shared across component headers. */ typedef struct CfreeCompiler CfreeCompiler; +typedef struct CfreeCompileSession CfreeCompileSession; typedef struct CfreeObjBuilder CfreeObjBuilder; typedef struct CfreeObjFile CfreeObjFile; +typedef struct CfreeLinkSession CfreeLinkSession; typedef struct CfreeJit CfreeJit; typedef struct CfreeJitSession CfreeJitSession; typedef struct CfreeDebugInfo CfreeDebugInfo; @@ -52,8 +54,8 @@ typedef struct CfreeSrcLoc { } CfreeSrcLoc; typedef struct CfreeBytes { - const char *name; /* diagnostic label; may be NULL */ - const uint8_t *data; + const char* name; /* diagnostic label; may be NULL */ + const uint8_t* data; size_t len; } CfreeBytes; @@ -134,8 +136,8 @@ typedef enum CfreeSymVis { } CfreeSymVis; typedef struct CfreePathPrefixMap { - const char *old_prefix; - const char *new_prefix; + const char* old_prefix; + const char* new_prefix; } CfreePathPrefixMap; typedef struct CfreeCodeOptions { @@ -148,19 +150,19 @@ typedef struct CfreeCodeOptions { * entry point); object emission is bypassed. See doc/CBACKEND.md. */ bool emit_c_source; uint64_t epoch; /* reproducible timestamp seed; 0 means no timestamp */ - const CfreePathPrefixMap *path_map; + const CfreePathPrefixMap* path_map; uint32_t npath_map; /* Destination for emit_c_source mode. Ignored when emit_c_source is 0. */ - struct CfreeWriter *c_source_writer; + struct CfreeWriter* c_source_writer; } CfreeCodeOptions; typedef struct CfreeHeap CfreeHeap; struct CfreeHeap { - void *(*alloc)(CfreeHeap *, size_t size, size_t align); - void *(*realloc)(CfreeHeap *, void *p, size_t old_size, size_t new_size, + void* (*alloc)(CfreeHeap*, size_t size, size_t align); + void* (*realloc)(CfreeHeap*, void* p, size_t old_size, size_t new_size, size_t align); - void (*free)(CfreeHeap *, void *p, size_t size); - void *user; + void (*free)(CfreeHeap*, void* p, size_t size); + void* user; }; typedef enum CfreeDiagKind { @@ -172,83 +174,83 @@ typedef enum CfreeDiagKind { typedef struct CfreeDiagSink CfreeDiagSink; struct CfreeDiagSink { - void (*emit)(CfreeDiagSink *, CfreeDiagKind, CfreeSrcLoc, const char *fmt, + void (*emit)(CfreeDiagSink*, CfreeDiagKind, CfreeSrcLoc, const char* fmt, va_list); - void *user; + void* user; uint32_t errors; /* maintained by libcfree; hosts may read */ uint32_t warnings; /* maintained by libcfree; hosts may read */ }; typedef struct CfreeWriter CfreeWriter; struct CfreeWriter { - CfreeStatus (*write)(CfreeWriter *, const void *data, size_t n); - CfreeStatus (*seek)(CfreeWriter *, uint64_t offset); - uint64_t (*tell)(CfreeWriter *); - CfreeStatus (*status)(CfreeWriter *); - void (*close)(CfreeWriter *); + CfreeStatus (*write)(CfreeWriter*, const void* data, size_t n); + CfreeStatus (*seek)(CfreeWriter*, uint64_t offset); + uint64_t (*tell)(CfreeWriter*); + CfreeStatus (*status)(CfreeWriter*); + void (*close)(CfreeWriter*); }; -static inline CfreeStatus cfree_writer_write(CfreeWriter *w, const void *d, +static inline CfreeStatus cfree_writer_write(CfreeWriter* w, const void* d, size_t n) { return w->write(w, d, n); } -static inline CfreeStatus cfree_writer_seek(CfreeWriter *w, uint64_t off) { +static inline CfreeStatus cfree_writer_seek(CfreeWriter* w, uint64_t off) { return w->seek(w, off); } -static inline uint64_t cfree_writer_tell(CfreeWriter *w) { return w->tell(w); } -static inline CfreeStatus cfree_writer_status(CfreeWriter *w) { +static inline uint64_t cfree_writer_tell(CfreeWriter* w) { return w->tell(w); } +static inline CfreeStatus cfree_writer_status(CfreeWriter* w) { return w->status(w); } -static inline void cfree_writer_close(CfreeWriter *w) { w->close(w); } +static inline void cfree_writer_close(CfreeWriter* w) { w->close(w); } typedef struct CfreeFileData { - const uint8_t *data; + const uint8_t* data; size_t size; - void *token; + void* token; } CfreeFileData; typedef struct CfreeFileIO { - CfreeStatus (*read_all)(void *user, const char *path, CfreeFileData *out); - void (*release)(void *user, CfreeFileData *); - CfreeStatus (*open_writer)(void *user, const char *path, CfreeWriter **out); - void *user; + CfreeStatus (*read_all)(void* user, const char* path, CfreeFileData* out); + void (*release)(void* user, CfreeFileData*); + CfreeStatus (*open_writer)(void* user, const char* path, CfreeWriter** out); + void* user; } CfreeFileIO; typedef struct CfreeMetrics { - void (*scope_begin)(void *user, const char *name); - void (*scope_end)(void *user, const char *name); - void (*count)(void *user, const char *name, uint64_t value); - void *user; + void (*scope_begin)(void* user, const char* name); + void (*scope_end)(void* user, const char* name); + void (*count)(void* user, const char* name, uint64_t value); + void* user; } CfreeMetrics; typedef struct CfreeContext { - CfreeHeap *heap; + CfreeHeap* heap; /* Optional. Source compilation uses this for include resolution and output * helpers; pure byte-oriented modules such as object, archive, DWARF, and * disassembly ignore it. */ - const CfreeFileIO *file_io; - CfreeDiagSink *diag; - const CfreeMetrics *metrics; + const CfreeFileIO* file_io; + CfreeDiagSink* diag; + const CfreeMetrics* metrics; /* Unix seconds, or negative when the host provides no clock. */ int64_t now; } CfreeContext; -CfreeStatus cfree_compiler_new(CfreeTarget, const CfreeContext *, - CfreeCompiler **out); -void cfree_compiler_free(CfreeCompiler *); -CfreeTarget cfree_compiler_target(CfreeCompiler *); +CfreeStatus cfree_compiler_new(CfreeTarget, const CfreeContext*, + CfreeCompiler** out); +void cfree_compiler_free(CfreeCompiler*); +CfreeTarget cfree_compiler_target(CfreeCompiler*); -const CfreeContext *cfree_compiler_context(CfreeCompiler *); +const CfreeContext* cfree_compiler_context(CfreeCompiler*); -const char *cfree_compiler_file_name(CfreeCompiler *, uint32_t file_id); +const char* cfree_compiler_file_name(CfreeCompiler*, uint32_t file_id); -CfreeSym cfree_sym_intern(CfreeCompiler *, const char *str); -CfreeSym cfree_sym_intern_len(CfreeCompiler *, const char *str, size_t len); -const char *cfree_sym_str(CfreeCompiler *, CfreeSym, size_t *len_out); +CfreeSym cfree_sym_intern(CfreeCompiler*, const char* str); +CfreeSym cfree_sym_intern_len(CfreeCompiler*, const char* str, size_t len); +const char* cfree_sym_str(CfreeCompiler*, CfreeSym, size_t* len_out); -CfreeStatus cfree_writer_mem(CfreeHeap *, CfreeWriter **out); -const uint8_t *cfree_writer_mem_bytes(CfreeWriter *, size_t *len_out); +CfreeStatus cfree_writer_mem(CfreeHeap*, CfreeWriter** out); +const uint8_t* cfree_writer_mem_bytes(CfreeWriter*, size_t* len_out); #endif diff --git a/include/cfree/jit.h b/include/cfree/jit.h @@ -19,57 +19,73 @@ enum { }; typedef struct CfreeExecMemRegion { - void *write; - void *runtime; + void* write; + void* runtime; size_t size; - void *token; + void* token; } CfreeExecMemRegion; typedef struct CfreeExecMem { size_t page_size; - CfreeStatus (*reserve)(void *user, size_t size, int prot, - CfreeExecMemRegion *out); - CfreeStatus (*protect)(void *user, void *addr, size_t size, int prot); - void (*release)(void *user, CfreeExecMemRegion *region); - void (*flush_icache)(void *user, void *addr, size_t size); - void *user; + CfreeStatus (*reserve)(void* user, size_t size, int prot, + CfreeExecMemRegion* out); + CfreeStatus (*protect)(void* user, void* addr, size_t size, int prot); + void (*release)(void* user, CfreeExecMemRegion* region); + void (*flush_icache)(void* user, void* addr, size_t size); + void* user; } CfreeExecMem; typedef struct CfreeJitTls { - void *(*ctx_new)(void *user, const void *init_bytes, size_t image_filesz, + void* (*ctx_new)(void* user, const void* init_bytes, size_t image_filesz, size_t image_size, size_t align); - void (*ctx_destroy)(void *user, void *ctx); - void *user; + void (*ctx_destroy)(void* user, void* ctx); + void* user; } CfreeJitTls; typedef struct CfreeJitHost { - const CfreeExecMem *execmem; - const CfreeJitTls *tls; + const CfreeExecMem* execmem; + const CfreeJitTls* tls; } CfreeJitHost; -void cfree_jit_free(CfreeJit *); -void *cfree_jit_lookup(CfreeJit *, const char *name); -CfreeStatus cfree_jit_append_obj(CfreeJit *, CfreeObjBuilder *); -uint64_t cfree_jit_generation(CfreeJit *); -void cfree_jit_run_dtors(CfreeJit *); +void cfree_jit_free(CfreeJit*); +void* cfree_jit_lookup(CfreeJit*, const char* name); +uint64_t cfree_jit_generation(CfreeJit*); +void cfree_jit_run_dtors(CfreeJit*); -const CfreeObjFile *cfree_jit_view(CfreeJit *); -CfreeStatus cfree_jit_addr_to_sym(CfreeJit *, uint64_t addr, - const char **name_out, uint64_t *off_out); -uint64_t cfree_jit_runtime_to_image(CfreeJit *, uint64_t runtime_pc); -uint64_t cfree_jit_image_to_runtime(CfreeJit *, uint64_t image_vaddr); +typedef enum CfreeJitPublishKind { + CFREE_JIT_PUBLISH_APPEND_OBJECTS, + CFREE_JIT_PUBLISH_REPLACE_SYMBOLS, +} CfreeJitPublishKind; + +typedef struct CfreeJitPublishOptions { + uint8_t kind; /* CfreeJitPublishKind */ + CfreeLinkSession* link; +} CfreeJitPublishOptions; + +typedef struct CfreeJitPublishResult { + uint64_t generation; +} CfreeJitPublishResult; + +CfreeStatus cfree_jit_publish(CfreeJit*, const CfreeJitPublishOptions*, + CfreeJitPublishResult*); + +const CfreeObjFile* cfree_jit_view(CfreeJit*); +CfreeStatus cfree_jit_addr_to_sym(CfreeJit*, uint64_t addr, + const char** name_out, uint64_t* off_out); +uint64_t cfree_jit_runtime_to_image(CfreeJit*, uint64_t runtime_pc); +uint64_t cfree_jit_image_to_runtime(CfreeJit*, uint64_t image_vaddr); typedef struct CfreeJitSymIter CfreeJitSymIter; typedef struct CfreeJitSym { - const char *name; + const char* name; uint64_t addr; uint64_t size; CfreeSymKind kind; } CfreeJitSym; -CfreeStatus cfree_jit_sym_iter_new(CfreeJit *, CfreeJitSymIter **out); -CfreeIterResult cfree_jit_sym_iter_next(CfreeJitSymIter *, CfreeJitSym *out); -void cfree_jit_sym_iter_free(CfreeJitSymIter *); +CfreeStatus cfree_jit_sym_iter_new(CfreeJit*, CfreeJitSymIter** out); +CfreeIterResult cfree_jit_sym_iter_next(CfreeJitSymIter*, CfreeJitSym* out); +void cfree_jit_sym_iter_free(CfreeJitSymIter*); #endif diff --git a/include/cfree/link.h b/include/cfree/link.h @@ -11,7 +11,7 @@ * response-file handling are driver responsibilities. */ -typedef void *(*CfreeExternResolver)(void *user, const char *name); +typedef void* (*CfreeExternResolver)(void* user, const char* name); typedef struct CfreeJitHost CfreeJitHost; typedef enum CfreeBuildIdMode { @@ -47,14 +47,14 @@ struct CfreeLinkExpr { uint8_t kind; /* CfreeLinkExprKind */ union { int64_t int_val; - const char *name; + const char* name; struct { - const CfreeLinkExpr *lhs; - const CfreeLinkExpr *rhs; + const CfreeLinkExpr* lhs; + const CfreeLinkExpr* rhs; } bin; struct { - const CfreeLinkExpr *val; - const CfreeLinkExpr *align; + const CfreeLinkExpr* val; + const CfreeLinkExpr* align; } align; } v; }; @@ -66,15 +66,15 @@ typedef enum CfreeLinkRegionFlag { } CfreeLinkRegionFlag; typedef struct CfreeLinkRegion { - const char *name; + const char* name; uint8_t flags; /* CfreeLinkRegionFlag */ uint64_t origin; uint64_t length; } CfreeLinkRegion; typedef struct CfreeLinkInputMatch { - const char *file_pattern; /* NULL means "*" */ - const char *section_pattern; + const char* file_pattern; /* NULL means "*" */ + const char* section_pattern; int keep; } CfreeLinkInputMatch; @@ -86,35 +86,35 @@ typedef enum CfreeLinkAsnKind { typedef struct CfreeLinkAssignment { uint8_t kind; /* CfreeLinkAsnKind */ - const char *sym; - const CfreeLinkExpr *expr; + const char* sym; + const CfreeLinkExpr* expr; } CfreeLinkAssignment; typedef struct CfreeLinkOutputSection { - const char *name; - const CfreeLinkExpr *vma; - const CfreeLinkExpr *lma; - const CfreeLinkInputMatch *inputs; + const char* name; + const CfreeLinkExpr* vma; + const CfreeLinkExpr* lma; + const CfreeLinkInputMatch* inputs; uint32_t ninputs; - const char *region; - const char *load_region; - const CfreeLinkAssignment *asns; + const char* region; + const char* load_region; + const CfreeLinkAssignment* asns; uint32_t nasns; } CfreeLinkOutputSection; typedef struct CfreeLinkScript { - const char *entry; - const CfreeLinkRegion *regions; + const char* entry; + const CfreeLinkRegion* regions; uint32_t nregions; - const CfreeLinkOutputSection *sections; + const CfreeLinkOutputSection* sections; uint32_t nsections; - const CfreeLinkAssignment *top_asns; + const CfreeLinkAssignment* top_asns; uint32_t ntop_asns; } CfreeLinkScript; -CfreeStatus cfree_link_script_parse(const CfreeContext *, const char *text, - size_t len, CfreeLinkScript **out); -void cfree_link_script_free(const CfreeContext *, CfreeLinkScript *); +CfreeStatus cfree_link_script_parse(const CfreeContext*, const char* text, + size_t len, CfreeLinkScript** out); +void cfree_link_script_free(const CfreeContext*, CfreeLinkScript*); typedef enum CfreeLinkMode { CFREE_LM_DEFAULT, @@ -125,7 +125,7 @@ typedef enum CfreeLinkMode { typedef struct CfreeLinkArchiveInput { CfreeBytes bytes; - uint8_t link_mode; /* CfreeLinkMode */ + uint8_t link_mode; /* CfreeLinkMode */ bool whole_archive; uint8_t group_id; uint8_t pad; @@ -141,66 +141,54 @@ typedef enum CfreeLinkInputOrderKind { typedef struct CfreeLinkInputOrder { uint8_t kind; /* CfreeLinkInputOrderKind */ uint8_t pad[3]; - uint32_t index; /* index into the matching CfreeLinkInputs array */ + uint32_t index; } CfreeLinkInputOrder; -typedef struct CfreeLinkInputs { - CfreeObjBuilder *const *objs; - uint32_t nobjs; - const CfreeBytes *obj_bytes; - uint32_t nobj_bytes; - const CfreeLinkArchiveInput *archives; - uint32_t narchives; - const CfreeBytes *dso_bytes; - uint32_t ndso_bytes; - const CfreeLinkScript *linker_script; - const char *entry; - uint8_t build_id_mode; /* CfreeBuildIdMode */ - const uint8_t *build_id_bytes; - uint32_t build_id_len; - const CfreeLinkInputOrder *order; /* optional; NULL preserves legacy order */ - uint32_t norder; -} CfreeLinkInputs; +typedef enum CfreeLinkOutputKind { + CFREE_LINK_OUTPUT_EXE, + CFREE_LINK_OUTPUT_SHARED, + CFREE_LINK_OUTPUT_RELOCATABLE, + CFREE_LINK_OUTPUT_JIT, +} CfreeLinkOutputKind; -typedef struct CfreeExeLinkOptions { - CfreeLinkInputs inputs; +typedef struct CfreeLinkSessionOptions { + uint8_t output_kind; /* CfreeLinkOutputKind */ bool gc_sections; bool pie; - const char *interp_path; -} CfreeExeLinkOptions; + const char* interp_path; + const char* entry; + const CfreeLinkScript* linker_script; + uint8_t build_id_mode; /* CfreeBuildIdMode */ + const uint8_t* build_id_bytes; + uint32_t build_id_len; -typedef struct CfreeSharedLinkOptions { - CfreeLinkInputs inputs; - const char *soname; - const char *const *rpaths; + const char* soname; + const char* const* rpaths; uint32_t nrpaths; - const char *const *runpaths; + const char* const* runpaths; uint32_t nrunpaths; - const char *const *exports; + const char* const* exports; uint32_t nexports; bool allow_undefined; - bool gc_sections; -} CfreeSharedLinkOptions; - -typedef struct CfreeRelocatableLinkOptions { - CfreeLinkInputs inputs; -} CfreeRelocatableLinkOptions; -typedef struct CfreeJitLinkOptions { - CfreeLinkInputs inputs; - bool gc_sections; CfreeExternResolver extern_resolver; - void *extern_resolver_user; -} CfreeJitLinkOptions; - -CfreeStatus cfree_link_exe(CfreeCompiler *, const CfreeExeLinkOptions *, - CfreeWriter *out); -CfreeStatus cfree_link_shared(CfreeCompiler *, const CfreeSharedLinkOptions *, - CfreeWriter *out); -CfreeStatus cfree_link_relocatable(CfreeCompiler *, - const CfreeRelocatableLinkOptions *, - CfreeWriter *out); -CfreeStatus cfree_link_jit(CfreeCompiler *, const CfreeJitLinkOptions *, - const CfreeJitHost *, CfreeJit **out_jit); + void* extern_resolver_user; + const CfreeJitHost* jit_host; +} CfreeLinkSessionOptions; + +CfreeStatus cfree_link_session_new(CfreeCompiler*, + const CfreeLinkSessionOptions*, + CfreeLinkSession** out); +CfreeStatus cfree_link_session_add_obj(CfreeLinkSession*, CfreeObjBuilder*); +CfreeStatus cfree_link_session_add_obj_bytes(CfreeLinkSession*, + const CfreeBytes*); +CfreeStatus cfree_link_session_add_archive_bytes(CfreeLinkSession*, + const CfreeLinkArchiveInput*); +CfreeStatus cfree_link_session_add_dso_bytes(CfreeLinkSession*, + const CfreeBytes*); +CfreeStatus cfree_link_session_resolve(CfreeLinkSession*); +CfreeStatus cfree_link_session_emit(CfreeLinkSession*, CfreeWriter* out); +CfreeStatus cfree_link_session_jit(CfreeLinkSession*, CfreeJit** out_jit); +void cfree_link_session_free(CfreeLinkSession*); #endif diff --git a/lang/c/c.c b/lang/c/c.c @@ -190,10 +190,9 @@ static CfreeFrontendState* c_frontend_new(CfreeCompiler* c) { return (CfreeFrontendState*)fe; } -static CfreeStatus c_frontend_compile(CfreeFrontendState* frontend, - const CfreeFrontendCompileOptions* fe_opts, - const CfreeSourceInput* input, - CfreeObjBuilder* out) { +static CfreeStatus c_frontend_compile( + CfreeFrontendState* frontend, const CfreeFrontendCompileOptions* fe_opts, + const CfreeSourceInput* input, CfreeObjBuilder* out) { CFrontend* fe = (CFrontend*)frontend; CfreeCompiler* c; /* The libcfree pipeline plants the original CfreeCCompileOptions* in @@ -227,7 +226,8 @@ static CfreeStatus c_frontend_compile(CfreeFrontendState* frontend, cfree_frontend_metrics_scope_end(c, "compile.c.pp_new"); cfree_frontend_metrics_scope_begin(c, "compile.c.cg_new"); cg = NULL; - cg_st = cfree_cg_new(c, out, &fe_opts->code, &cg); + cg_st = cfree_cg_new(c, &cg); + if (cg_st == CFREE_OK) cg_st = cfree_cg_begin_obj(cg, out, &fe_opts->code); cfree_frontend_metrics_scope_end(c, "compile.c.cg_new"); if (!lex || !pp || cg_st != CFREE_OK || !cg) compiler_panic(c, c_no_loc(), "C compiler out of memory"); diff --git a/lang/toy/compile.c b/lang/toy/compile.c @@ -1,8 +1,7 @@ -#include "toy.h" +#include <string.h> #include "internal.h" - -#include <string.h> +#include "toy.h" typedef struct ToyFrontend { CfreeCompiler* c; @@ -11,8 +10,8 @@ typedef struct ToyFrontend { int poisoned; } ToyFrontend; -static int toy_buf_append(ToyFrontend* fe, char** buf, size_t* len, - size_t* cap, const char* src, size_t n) { +static int toy_buf_append(ToyFrontend* fe, char** buf, size_t* len, size_t* cap, + const char* src, size_t n) { CfreeHeap* h = cfree_compiler_context(fe->c)->heap; if (*len + n + 1u > *cap) { size_t nc = *cap ? *cap * 2u : 256u; @@ -135,9 +134,10 @@ static CfreeFrontendState* toy_frontend_new(CfreeCompiler* c) { return (CfreeFrontendState*)fe; } -static CfreeStatus toy_frontend_compile( - CfreeFrontendState* frontend, const CfreeFrontendCompileOptions* opts, - const CfreeSourceInput* input, CfreeObjBuilder* out) { +static CfreeStatus toy_frontend_compile(CfreeFrontendState* frontend, + const CfreeFrontendCompileOptions* opts, + const CfreeSourceInput* input, + CfreeObjBuilder* out) { ToyFrontend* fe = (ToyFrontend*)frontend; CfreeCompiler* c; ToyParser p; @@ -158,17 +158,17 @@ static CfreeStatus toy_frontend_compile( return CFREE_ERR; } - st = cfree_cg_new(c, out, &opts->code, &cg); + st = cfree_cg_new(c, &cg); + if (st == CFREE_OK) st = cfree_cg_begin_obj(cg, out, &opts->code); if (st != CFREE_OK) goto done_status; if (!fe->parser_live) { - toy_parser_init(&fe->parser, c, cg, source, source_len, - input->bytes.name); + toy_parser_init(&fe->parser, c, cg, source, source_len, input->bytes.name); fe->parser.input_kind = opts->input_kind; fe->parser_live = 1; } else { - toy_parser_reinit(&fe->parser, c, cg, source, source_len, - input->bytes.name, opts->input_kind); + toy_parser_reinit(&fe->parser, c, cg, source, source_len, input->bytes.name, + opts->input_kind); } p = fe->parser; if (opts->input_kind != CFREE_FRONTEND_INPUT_TRANSLATION_UNIT && diff --git a/lang/wasm/cg.c b/lang/wasm/cg.c @@ -19,7 +19,6 @@ static CfreeCgTypeId wasm_cg_type(CfreeCompiler* c, CfreeCgBuiltinTypes b, return b.id[CFREE_CG_BUILTIN_I32]; } - static CfreeCgMemAccess wasm_cg_mem(CfreeCompiler* c, CfreeCgBuiltinTypes b, WasmValType vt) { CfreeCgMemAccess mem; @@ -454,10 +453,9 @@ static void wasm_cg_memory_check(CfreeCompiler* c, CfreeCg* cg, uint32_t width = wasm_mem_width(in->kind); uint64_t end = in->offset64 + width; CfreeCgLabel ok = cfree_cg_label_new(cg); - uint32_t max_pages = - (uint32_t)(m->memories[in->memidx].has_max - ? m->memories[in->memidx].max_pages - : m->memories[in->memidx].min_pages); + uint32_t max_pages = (uint32_t)(m->memories[in->memidx].has_max + ? m->memories[in->memidx].max_pages + : m->memories[in->memidx].min_pages); if (end > (uint64_t)max_pages * 65536u) { wasm_cg_trap_bounds(cg, rt); return; @@ -482,8 +480,8 @@ static void wasm_cg_memory_check(CfreeCompiler* c, CfreeCg* cg, } static void wasm_cg_memory_lvalue(CfreeCg* cg, const WasmCgRuntime* rt, - CfreeCgLocal instance_local, - uint32_t memidx, uint64_t offset) { + CfreeCgLocal instance_local, uint32_t memidx, + uint64_t offset) { wasm_cg_push_memory_data_ptr(cg, rt, instance_local, memidx); cfree_cg_swap(cg); cfree_cg_index(cg, offset); @@ -583,18 +581,18 @@ static void wasm_cg_checked_trunc(CfreeCompiler* c, CfreeCg* cg, WasmValType dst, int is_unsigned) { CfreeCgTypeId src_ty = wasm_cg_type(c, b, src); CfreeCgTypeId dst_ty = wasm_cg_type(c, b, dst); - CfreeCgTypeId bit_ty = b.id[src == WASM_VAL_F32 ? CFREE_CG_BUILTIN_I32 - : CFREE_CG_BUILTIN_I64]; + CfreeCgTypeId bit_ty = + b.id[src == WASM_VAL_F32 ? CFREE_CG_BUILTIN_I32 : CFREE_CG_BUILTIN_I64]; CfreeCgMemAccess src_mem = wasm_cg_mem(c, b, src); CfreeCgMemAccess bit_mem = wasm_cg_mem_type(bit_ty); CfreeCgLocalAttrs attrs; CfreeCgLocal value, bits, abs_bits; - uint64_t abs_mask = src == WASM_VAL_F32 ? UINT64_C(0x7fffffff) - : UINT64_C(0x7fffffffffffffff); - uint64_t sign_mask = src == WASM_VAL_F32 ? UINT64_C(0x80000000) - : UINT64_C(0x8000000000000000); - uint64_t inf_bits = src == WASM_VAL_F32 ? UINT64_C(0x7f800000) - : UINT64_C(0x7ff0000000000000); + uint64_t abs_mask = + src == WASM_VAL_F32 ? UINT64_C(0x7fffffff) : UINT64_C(0x7fffffffffffffff); + uint64_t sign_mask = + src == WASM_VAL_F32 ? UINT64_C(0x80000000) : UINT64_C(0x8000000000000000); + uint64_t inf_bits = + src == WASM_VAL_F32 ? UINT64_C(0x7f800000) : UINT64_C(0x7ff0000000000000); uint64_t limit_bits; memset(&attrs, 0, sizeof attrs); attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; @@ -700,7 +698,6 @@ static void wasm_cg_checked_trunc(CfreeCompiler* c, CfreeCg* cg, cfree_cg_float_to_sint(cg, dst_ty, CFREE_CG_ROUND_TOWARD_ZERO); } - static int wasm_fp_binop(uint8_t kind, CfreeCgFpBinOp* out) { switch (kind) { case WASM_INSN_F32_ADD: @@ -759,8 +756,8 @@ static void wasm_cg_call_func(CfreeCompiler* c, CfreeCg* cg, CfreeCgBuiltinTypes b, const WasmFunc* f, const WasmCgRuntime* rt, CfreeCgSym sym, CfreeCgTypeId func_type, - CfreeCgLocal instance_local, - uint32_t func_index, int must_tail) { + CfreeCgLocal instance_local, uint32_t func_index, + int must_tail) { CfreeCgLocalAttrs attrs; CfreeCgLocal args[16]; CfreeCgLocal callee = CFREE_CG_LOCAL_NONE; @@ -800,15 +797,15 @@ static void wasm_cg_call_func(CfreeCompiler* c, CfreeCg* cg, cfree_cg_load(cg, wasm_cg_mem(c, b, f->params[p])); } if (f->is_import) - cfree_cg_call(cg, f->nparams + 1u, func_type, - (CfreeCgCallAttrs){ - .tail = must_tail ? CFREE_CG_TAIL_MUST - : CFREE_CG_TAIL_DEFAULT}); + cfree_cg_call( + cg, f->nparams + 1u, func_type, + (CfreeCgCallAttrs){.tail = must_tail ? CFREE_CG_TAIL_MUST + : CFREE_CG_TAIL_DEFAULT}); else - cfree_cg_call_symbol(cg, sym, f->nparams + 1u, - (CfreeCgCallAttrs){ - .tail = must_tail ? CFREE_CG_TAIL_MUST - : CFREE_CG_TAIL_DEFAULT}); + cfree_cg_call_symbol( + cg, sym, f->nparams + 1u, + (CfreeCgCallAttrs){.tail = must_tail ? CFREE_CG_TAIL_MUST + : CFREE_CG_TAIL_DEFAULT}); if (must_tail) { if (f->nresults) wasm_cg_push_zero(c, cg, b, f->results[0]); cfree_cg_unreachable(cg); @@ -816,9 +813,10 @@ static void wasm_cg_call_func(CfreeCompiler* c, CfreeCg* cg, } void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, - CfreeObjBuilder* out, const WasmModule* m) { + CfreeObjBuilder* out, const WasmModule* m) { CfreeCg* cg = NULL; - CfreeStatus cg_st = cfree_cg_new(c, out, code_opts, &cg); + CfreeStatus cg_st = cfree_cg_new(c, &cg); + if (cg_st == CFREE_OK) cg_st = cfree_cg_begin_obj(cg, out, code_opts); if (cg_st != CFREE_OK) wasm_error(c, wasm_loc(0, 0), "wasm: failed to initialize codegen"); CfreeCgBuiltinTypes b = cfree_cg_builtin_types(c); @@ -957,11 +955,9 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_int(cg, flags, b.id[CFREE_CG_BUILTIN_I32]); cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); if (mem->data_init_len) { - CfreeCgSym data_sym = - cfree_cg_const_data(cg, mem->data, mem->data_init_len, 16, - b.id[CFREE_CG_BUILTIN_I8]); - CfreeCgMemAccess byte_mem = - wasm_cg_mem_type(b.id[CFREE_CG_BUILTIN_I8]); + CfreeCgSym data_sym = cfree_cg_const_data( + cg, mem->data, mem->data_init_len, 16, b.id[CFREE_CG_BUILTIN_I8]); + CfreeCgMemAccess byte_mem = wasm_cg_mem_type(b.id[CFREE_CG_BUILTIN_I8]); wasm_cg_push_memory_data_ptr(cg, &rt, instance_local, i); cfree_cg_push_symbol_addr(cg, data_sym, 0); cfree_cg_memcpy(cg, m->memories[i].data_init_len, byte_mem, byte_mem); @@ -1274,8 +1270,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, case WASM_INSN_RETURN_CALL: wasm_cg_call_func(c, cg, b, &m->funcs[in.imm], &rt, syms[in.imm], func_types[in.imm], instance_local, - (uint32_t)in.imm, - in.kind == WASM_INSN_RETURN_CALL); + (uint32_t)in.imm, in.kind == WASM_INSN_RETURN_CALL); break; case WASM_INSN_CALL_INDIRECT: case WASM_INSN_RETURN_CALL_INDIRECT: { @@ -1478,11 +1473,11 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_local(cg, args[p]); cfree_cg_load(cg, wasm_cg_mem(c, b, t->params[p])); } - cfree_cg_call(cg, t->nparams + 1u, ref_func_type, - (CfreeCgCallAttrs){ - .tail = in.kind == WASM_INSN_RETURN_CALL_REF - ? CFREE_CG_TAIL_MUST - : CFREE_CG_TAIL_DEFAULT}); + cfree_cg_call( + cg, t->nparams + 1u, ref_func_type, + (CfreeCgCallAttrs){.tail = in.kind == WASM_INSN_RETURN_CALL_REF + ? CFREE_CG_TAIL_MUST + : CFREE_CG_TAIL_DEFAULT}); if (in.kind == WASM_INSN_RETURN_CALL_REF) { if (t->nresults) wasm_cg_push_zero(c, cg, b, t->results[0]); cfree_cg_unreachable(cg); @@ -1520,8 +1515,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_drop(cg); break; case WASM_INSN_MEMORY_SIZE: - wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, - in.memidx); + wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, in.memidx); cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); if (!m->memories[in.memidx].is64) cfree_cg_trunc(cg, b.id[CFREE_CG_BUILTIN_I32]); @@ -1543,8 +1537,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_swap(cg); cfree_cg_store(cg, wasm_cg_mem(c, b, page_vt)); cfree_cg_push_local(cg, old_pages); - wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, - in.memidx); + wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, in.memidx); cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); @@ -1560,8 +1553,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_int_cmp(cg, CFREE_CG_INT_LE_U); cfree_cg_branch_false(cg, fail); - wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, - in.memidx); + wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, in.memidx); cfree_cg_push_local(cg, old_pages); cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); cfree_cg_push_local(cg, delta); @@ -1596,7 +1588,8 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, case WASM_INSN_I64_ATOMIC_LOAD8_U: case WASM_INSN_I64_ATOMIC_LOAD16_U: case WASM_INSN_I64_ATOMIC_LOAD32_U: { - CfreeCgTypeId ty = wasm_cg_type(c, b, wasm_atomic_value_type(in.kind)); + CfreeCgTypeId ty = + wasm_cg_type(c, b, wasm_atomic_value_type(in.kind)); CfreeCgMemAccess mem = wasm_cg_mem_type(ty); mem.align = in.align; wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); @@ -2049,4 +2042,3 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, } cfree_cg_free(cg); } - diff --git a/src/api/compile.c b/src/api/compile.c @@ -3,10 +3,10 @@ #include <cfree/compile.h> #include <cfree/core.h> +#include <string.h> #include "arch/arch.h" #include "asm/asm.h" -#include "core/arena.h" #include "core/core.h" #include "core/heap.h" #include "core/metrics.h" @@ -24,6 +24,13 @@ struct CfreeFrontend { CfreeFrontendState* state; }; +struct CfreeCompileSession { + CfreeCompiler* c; + CfreeLanguage lang; + CfreeFrontend* frontend; + CfreeFrontendCompileOptions opts; +}; + static CfreeFrontendState* asm_frontend_new(CfreeCompiler* c); static CfreeStatus asm_frontend_compile(CfreeFrontendState* fe, const CfreeFrontendCompileOptions* opts, @@ -106,23 +113,6 @@ static void validate_bytes(Compiler* c, const CfreeBytes* in) { } } -static void emit_object_bytes(Compiler* c, ObjBuilder* ob, Writer* w) { - switch (c->target.obj) { - case CFREE_OBJ_ELF: - emit_elf(c, ob, w); - break; - case CFREE_OBJ_COFF: - emit_coff(c, ob, w); - break; - case CFREE_OBJ_MACHO: - emit_macho(c, ob, w); - break; - case CFREE_OBJ_WASM: - emit_wasm(c, ob, w); - break; - } -} - static const CfreeFrontendVTable* frontend_for_language(Compiler* c, CfreeLanguage lang) { if ((unsigned)lang >= CFREE_LANG_COUNT) return NULL; @@ -139,8 +129,8 @@ static void compile_frontend_state_into(Compiler* c, const CfreeSourceInput* input, ObjBuilder* ob); -CfreeStatus cfree_frontend_new(CfreeCompiler* c, CfreeLanguage lang, - CfreeFrontend** out) { +static CfreeStatus cfree_frontend_new(CfreeCompiler* c, CfreeLanguage lang, + CfreeFrontend** out) { const CfreeFrontendVTable* vtable; CfreeFrontendState* state; CfreeFrontend* frontend; @@ -168,10 +158,9 @@ CfreeStatus cfree_frontend_new(CfreeCompiler* c, CfreeLanguage lang, return CFREE_OK; } -CfreeStatus cfree_frontend_compile(CfreeFrontend* frontend, - const CfreeFrontendCompileOptions* opts, - const CfreeSourceInput* input, - CfreeObjBuilder* out) { +static CfreeStatus cfree_frontend_compile( + CfreeFrontend* frontend, const CfreeFrontendCompileOptions* opts, + const CfreeSourceInput* input, CfreeObjBuilder* out) { Compiler* c; PanicSave saved; @@ -197,7 +186,7 @@ CfreeStatus cfree_frontend_compile(CfreeFrontend* frontend, return CFREE_OK; } -void cfree_frontend_free(CfreeFrontend* frontend) { +static void cfree_frontend_free(CfreeFrontend* frontend) { Heap* h; if (!frontend) return; if (frontend->vtable && frontend->state) { @@ -207,17 +196,67 @@ void cfree_frontend_free(CfreeFrontend* frontend) { h->free(h, frontend, sizeof(*frontend)); } -typedef struct FrontendCleanup { - const CfreeFrontendVTable* vtable; - CfreeFrontendState* frontend; -} FrontendCleanup; - -static void frontend_cleanup_run(void* arg) { - FrontendCleanup* cleanup = (FrontendCleanup*)arg; - if (cleanup && cleanup->vtable && cleanup->frontend) { - cleanup->vtable->free_frontend(cleanup->frontend); - cleanup->frontend = NULL; +CfreeStatus cfree_compile_session_new(CfreeCompiler* c, + const CfreeCompileSessionOptions* opts, + CfreeCompileSession** out) { + CfreeCompileSession* s; + CfreeFrontend* frontend = NULL; + CfreeStatus st; + Heap* h; + + if (!out) return CFREE_INVALID; + *out = NULL; + if (!c || !opts || (unsigned)opts->lang >= CFREE_LANG_COUNT) + return CFREE_INVALID; + st = cfree_frontend_new(c, opts->lang, &frontend); + if (st != CFREE_OK) return st; + h = (Heap*)c->ctx->heap; + s = (CfreeCompileSession*)h->alloc(h, sizeof(*s), + _Alignof(CfreeCompileSession)); + if (!s) { + cfree_frontend_free(frontend); + return CFREE_NOMEM; + } + memset(s, 0, sizeof(*s)); + s->c = c; + s->lang = opts->lang; + s->frontend = frontend; + s->opts = opts->compile; + *out = s; + return CFREE_OK; +} + +CfreeStatus cfree_compile_session_compile(CfreeCompileSession* s, + const CfreeSourceInput* input, + CfreeObjBuilder** out) { + ObjBuilder* ob; + CfreeFrontendCompileOptions opts; + CfreeStatus st; + + if (!out) return CFREE_INVALID; + *out = NULL; + if (!s || !s->c || !s->frontend || !input) return CFREE_INVALID; + if (input->lang != s->lang) return CFREE_INVALID; + ob = obj_new((Compiler*)s->c); + if (!ob) return CFREE_NOMEM; + opts = s->opts; + opts.input_kind = input->input_kind; + opts.repl_entry_name = input->repl_entry_name; + st = cfree_frontend_compile(s->frontend, &opts, input, (CfreeObjBuilder*)ob); + if (st != CFREE_OK) { + obj_free(ob); + return st; } + *out = (CfreeObjBuilder*)ob; + return CFREE_OK; +} + +void cfree_compile_session_free(CfreeCompileSession* s) { + Heap* h; + if (!s) return; + h = (Heap*)s->c->ctx->heap; + cfree_frontend_free(s->frontend); + h->free(h, s, sizeof(*s)); } static void compile_frontend_state_into(Compiler* c, @@ -243,124 +282,6 @@ static void compile_frontend_state_into(Compiler* c, metrics_count(c, "compile.obj_relocs", obj_reloc_total(ob)); } -static void compile_frontend_oneshot_into( - Compiler* c, const CfreeFrontendVTable* vtable, - const CfreeFrontendCompileOptions* opts, const CfreeSourceInput* input, - ObjBuilder* ob) { - CfreeFrontendState* frontend; - FrontendCleanup* cleanup; - CompilerCleanup* cleanup_node; - if (!vtable) { - compiler_panic(c, no_loc(), "no frontend registered for language: %u", - (u32)input->lang); - } - - frontend = vtable->new_frontend(c); - if (!frontend) { - compiler_panic(c, no_loc(), "frontend allocation failed for input: %s", - input->bytes.name); - } - cleanup = (FrontendCleanup*)arena_alloc(c->scratch, sizeof(*cleanup), - _Alignof(FrontendCleanup)); - if (!cleanup) { - vtable->free_frontend(frontend); - compiler_panic(c, no_loc(), "frontend cleanup allocation failed"); - } - cleanup->vtable = vtable; - cleanup->frontend = frontend; - cleanup_node = compiler_defer(c, frontend_cleanup_run, cleanup); - if (!cleanup_node) { - vtable->free_frontend(frontend); - compiler_panic(c, no_loc(), "frontend cleanup allocation failed"); - } - compile_frontend_state_into(c, vtable, frontend, opts, input, ob); - compiler_undefer(c, cleanup_node); - vtable->free_frontend(frontend); - cleanup->frontend = NULL; -} - -/* ============================================================ - * C - * ============================================================ */ - -static CfreeStatus compile_c_into(Compiler* c, const CfreeCCompileOptions* opts, - const CfreeBytes* input, ObjBuilder* ob) { - CfreeFrontendCompileOptions fe; - CfreeSourceInput si; - const CfreeFrontendVTable* frontend; - - frontend = frontend_for_language(c, CFREE_LANG_C); - if (!frontend) { - compiler_panic(c, no_loc(), "no C frontend registered"); - } - - fe.code = opts->code; - fe.diagnostics = opts->diagnostics; - fe.language_options = opts; - si.bytes = *input; - si.lang = CFREE_LANG_C; - - compile_frontend_oneshot_into(c, frontend, &fe, &si, ob); - return CFREE_OK; -} - -CfreeStatus cfree_compile_c_obj(CfreeCompiler* c, - const CfreeCCompileOptions* opts, - const CfreeBytes* input, - CfreeObjBuilder** out) { - PanicSave saved; - ObjBuilder* ob; - - if (!out) return CFREE_INVALID; - *out = NULL; - if (!c || !opts || !input) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, input); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->len); - compile_c_into(c, opts, input, ob); - metrics_scope_end(c, "compile.tu"); - *out = ob; - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - -CfreeStatus cfree_compile_c_obj_emit(CfreeCompiler* c, - const CfreeCCompileOptions* opts, - const CfreeBytes* input, - CfreeWriter* out) { - PanicSave saved; - ObjBuilder* ob; - - if (!c || !opts || !input || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, input); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->len); - compile_c_into(c, opts, input, ob); - /* In emit_c_source mode the CGTarget wrote portable C source to - * opts->code.c_source_writer (the same writer `out` points at); the - * object builder still got symbols and decls but no machine code. Skip - * object serialization in that case. */ - if (!opts->code.emit_c_source) emit_object_bytes(c, ob, out); - metrics_scope_end(c, "compile.tu"); - obj_free(ob); - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - /* ============================================================ * Asm * ============================================================ */ @@ -411,76 +332,6 @@ static void asm_frontend_free(CfreeFrontendState* frontend) { h->free(h, fe, sizeof(*fe)); } -CfreeStatus cfree_compile_asm_obj(CfreeCompiler* c, - const CfreeAsmCompileOptions* opts, - const CfreeBytes* input, - CfreeObjBuilder** out) { - PanicSave saved; - ObjBuilder* ob; - - if (!out) return CFREE_INVALID; - *out = NULL; - if (!c || !opts || !input) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, input); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->len); - { - CfreeFrontendCompileOptions fe; - CfreeSourceInput si; - fe.code = opts->code; - fe.diagnostics = opts->diagnostics; - fe.language_options = opts; - si.bytes = *input; - si.lang = CFREE_LANG_ASM; - compile_frontend_oneshot_into(c, &asm_frontend_vtable, &fe, &si, ob); - } - metrics_scope_end(c, "compile.tu"); - *out = ob; - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - -CfreeStatus cfree_compile_asm_obj_emit(CfreeCompiler* c, - const CfreeAsmCompileOptions* opts, - const CfreeBytes* input, - CfreeWriter* out) { - PanicSave saved; - ObjBuilder* ob; - if (!c || !opts || !input || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, input); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->len); - { - CfreeFrontendCompileOptions fe; - CfreeSourceInput si; - fe.code = opts->code; - fe.diagnostics = opts->diagnostics; - fe.language_options = opts; - si.bytes = *input; - si.lang = CFREE_LANG_ASM; - compile_frontend_oneshot_into(c, &asm_frontend_vtable, &fe, &si, ob); - } - emit_object_bytes(c, ob, out); - metrics_scope_end(c, "compile.tu"); - obj_free(ob); - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - struct CfreeDepIter { Compiler* c; SourceDepIter* inner; diff --git a/src/api/link.c b/src/api/link.c @@ -17,232 +17,283 @@ #include <cfree/jit.h> #include <cfree/link.h> #include <setjmp.h> +#include <string.h> #include "core/core.h" #include "link/link_internal.h" CfreeJit* cfree_jit_from_image(LinkImage*); -static SrcLoc no_loc(void) { - SrcLoc l = {0, 0, 0}; - return l; -} - -static void load_inputs(Linker* l, const CfreeLinkInputs* in) { - uint32_t i; - if (in->order && in->norder) { - for (i = 0; i < in->norder; ++i) { - const CfreeLinkInputOrder* ord = &in->order[i]; - switch ((CfreeLinkInputOrderKind)ord->kind) { - case CFREE_LINK_INPUT_OBJ: - if (ord->index >= in->nobjs) - compiler_panic(l->c, no_loc(), - "link: ordered obj input index out of range"); - if (in->objs[ord->index]) link_add_obj(l, in->objs[ord->index]); - break; - case CFREE_LINK_INPUT_OBJ_BYTES: { - const CfreeBytes* b; - if (ord->index >= in->nobj_bytes) - compiler_panic(l->c, no_loc(), - "link: ordered object input index out of range"); - b = &in->obj_bytes[ord->index]; - link_add_obj_bytes(l, b->name, b->data, b->len); - break; - } - case CFREE_LINK_INPUT_ARCHIVE: { - const CfreeLinkArchiveInput* a; - if (ord->index >= in->narchives) - compiler_panic(l->c, no_loc(), - "link: ordered archive input index out of range"); - a = &in->archives[ord->index]; - link_add_archive_bytes(l, a->bytes.name, a->bytes.data, a->bytes.len, - a->whole_archive, a->link_mode, a->group_id); - break; - } - case CFREE_LINK_INPUT_DSO: { - const CfreeBytes* b; - if (ord->index >= in->ndso_bytes) - compiler_panic(l->c, no_loc(), - "link: ordered DSO input index out of range"); - b = &in->dso_bytes[ord->index]; - link_add_dso_bytes(l, b->name, b->data, b->len); - break; - } - default: - compiler_panic(l->c, no_loc(), "link: invalid ordered input kind"); - } - } - if (in->linker_script) link_set_script(l, in->linker_script); - if (in->entry) link_set_entry(l, in->entry); - (void)in->build_id_mode; - (void)in->build_id_bytes; - (void)in->build_id_len; - return; - } - for (i = 0; i < in->nobjs; ++i) { - if (in->objs[i]) link_add_obj(l, in->objs[i]); - } - for (i = 0; i < in->nobj_bytes; ++i) { - const CfreeBytes* b = &in->obj_bytes[i]; - link_add_obj_bytes(l, b->name, b->data, b->len); - } - for (i = 0; i < in->narchives; ++i) { - const CfreeLinkArchiveInput* a = &in->archives[i]; - link_add_archive_bytes(l, a->bytes.name, a->bytes.data, a->bytes.len, - a->whole_archive, a->link_mode, a->group_id); - } - for (i = 0; i < in->ndso_bytes; ++i) { - const CfreeBytes* b = &in->dso_bytes[i]; - link_add_dso_bytes(l, b->name, b->data, b->len); - } - if (in->linker_script) link_set_script(l, in->linker_script); - if (in->entry) link_set_entry(l, in->entry); - /* build_id_* fields are accepted but not yet plumbed through the - * Linker — the elf emit currently derives the build-id from the - * image bytes unconditionally. Left as a TODO when the linker - * grows a configurable build-id mode. */ - (void)in->build_id_mode; - (void)in->build_id_bytes; - (void)in->build_id_len; -} - -CfreeStatus cfree_link_exe(CfreeCompiler* c, const CfreeExeLinkOptions* opts, - CfreeWriter* out) { +static CfreeStatus link_session_guard(CfreeLinkSession* s, + void (*fn)(CfreeLinkSession*, void*), + void* arg) { PanicSave saved; - Linker* l; - LinkImage* img; - if (!c || !opts || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); + if (!s || !s->c || !s->linker || !fn) return CFREE_INVALID; + compiler_panic_save(s->c, &saved); + if (setjmp(s->c->panic)) { + compiler_run_cleanups(s->c); + s->linker = NULL; + s->image = NULL; + compiler_panic_restore(s->c, &saved); return CFREE_ERR; } - l = link_new(c); - if (!l) { - compiler_panic_restore(c, &saved); - return CFREE_NOMEM; + fn(s, arg); + compiler_panic_restore(s->c, &saved); + return CFREE_OK; +} + +static CfreeStatus link_session_remember_publish_obj(CfreeLinkSession* s, + CfreeObjBuilder* ob) { + Heap* h; + CfreeObjBuilder** nb; + u32 new_cap; + if (!s || !ob) return CFREE_INVALID; + if (s->npublish_objs < s->publish_objs_cap) { + s->publish_objs[s->npublish_objs++] = ob; + return CFREE_OK; } - load_inputs(l, &opts->inputs); - link_set_emit_static_exe(l, 1); - link_set_gc_sections(l, opts->gc_sections); - link_set_pie(l, opts->pie); - link_set_interp_path(l, opts->interp_path); - img = link_resolve(l); - link_emit_image_writer(img, out); - link_image_free(img); - link_free(l); - compiler_panic_restore(c, &saved); + h = s->c->ctx->heap; + new_cap = s->publish_objs_cap ? s->publish_objs_cap * 2u : 8u; + nb = (CfreeObjBuilder**)h->realloc( + h, s->publish_objs, sizeof(*s->publish_objs) * s->publish_objs_cap, + sizeof(*s->publish_objs) * new_cap, _Alignof(CfreeObjBuilder*)); + if (!nb) return CFREE_NOMEM; + s->publish_objs = nb; + s->publish_objs_cap = new_cap; + s->publish_objs[s->npublish_objs++] = ob; return CFREE_OK; } -CfreeStatus cfree_link_shared(CfreeCompiler* c, - const CfreeSharedLinkOptions* opts, - CfreeWriter* out) { - PanicSave saved; +CfreeStatus cfree_link_session_new(CfreeCompiler* c, + const CfreeLinkSessionOptions* opts, + CfreeLinkSession** out) { + Heap* h; + CfreeLinkSession* s; Linker* l; - LinkImage* img; - if (!c || !opts || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } + if (!out) return CFREE_INVALID; + *out = NULL; + if (!c || !opts) return CFREE_INVALID; + h = c->ctx->heap; l = link_new(c); - if (!l) { - compiler_panic_restore(c, &saved); + if (!l) return CFREE_NOMEM; + s = (CfreeLinkSession*)h->alloc(h, sizeof(*s), _Alignof(CfreeLinkSession)); + if (!s) { + link_free(l); return CFREE_NOMEM; } - load_inputs(l, &opts->inputs); - link_set_gc_sections(l, opts->gc_sections); - /* Shared output is intrinsically PIC and uses the dynamic emit path. */ - link_set_pie(l, 1); - /* soname / rpaths / runpaths / exports / allow_undefined: forwarded - * fields not yet wired into the Linker. Recorded here so the surface - * matches the public API; the linker emits a static shared-friendly - * image regardless for the time being. */ - (void)opts->soname; - (void)opts->rpaths; - (void)opts->nrpaths; - (void)opts->runpaths; - (void)opts->nrunpaths; - (void)opts->exports; - (void)opts->nexports; - (void)opts->allow_undefined; - img = link_resolve(l); - link_emit_image_writer(img, out); - link_image_free(img); - link_free(l); - compiler_panic_restore(c, &saved); + memset(s, 0, sizeof(*s)); + s->c = (Compiler*)c; + s->linker = l; + s->opts = *opts; + if (opts->output_kind > CFREE_LINK_OUTPUT_JIT) { + h->free(h, s, sizeof(*s)); + link_free(l); + return CFREE_INVALID; + } + + switch ((CfreeLinkOutputKind)opts->output_kind) { + case CFREE_LINK_OUTPUT_EXE: + link_set_emit_static_exe(l, 1); + link_set_gc_sections(l, opts->gc_sections); + link_set_pie(l, opts->pie); + link_set_interp_path(l, opts->interp_path); + break; + case CFREE_LINK_OUTPUT_SHARED: + link_set_gc_sections(l, opts->gc_sections); + link_set_pie(l, 1); + (void)opts->soname; + (void)opts->rpaths; + (void)opts->nrpaths; + (void)opts->runpaths; + (void)opts->nrunpaths; + (void)opts->exports; + (void)opts->nexports; + (void)opts->allow_undefined; + break; + case CFREE_LINK_OUTPUT_RELOCATABLE: + break; + case CFREE_LINK_OUTPUT_JIT: + if (!opts->jit_host) { + h->free(h, s, sizeof(*s)); + link_free(l); + return CFREE_INVALID; + } + link_set_jit_host(l, opts->jit_host); + link_set_jit_mode(l, 1); + link_set_gc_sections(l, opts->gc_sections); + if (!opts->entry) link_clear_entry(l); + if (opts->extern_resolver) { + link_set_extern_resolver(l, opts->extern_resolver, + opts->extern_resolver_user); + } + break; + } + if (opts->linker_script) link_set_script(l, opts->linker_script); + if (opts->entry) link_set_entry(l, opts->entry); + (void)opts->build_id_mode; + (void)opts->build_id_bytes; + (void)opts->build_id_len; + *out = s; return CFREE_OK; } -CfreeStatus cfree_link_relocatable(CfreeCompiler* c, - const CfreeRelocatableLinkOptions* opts, - CfreeWriter* out) { - PanicSave saved; - Linker* l; - if (!c || !opts || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; +typedef struct LinkAddObjArg { + CfreeObjBuilder* ob; +} LinkAddObjArg; + +static void link_session_add_obj_inner(CfreeLinkSession* s, void* arg) { + LinkAddObjArg* a = (LinkAddObjArg*)arg; + link_add_obj(s->linker, (ObjBuilder*)a->ob); +} + +CfreeStatus cfree_link_session_add_obj(CfreeLinkSession* s, + CfreeObjBuilder* ob) { + LinkAddObjArg arg; + CfreeStatus st; + if (!s || !ob || s->resolved) return CFREE_INVALID; + arg.ob = ob; + st = link_session_guard(s, link_session_add_obj_inner, &arg); + if (st != CFREE_OK) return st; + return link_session_remember_publish_obj(s, ob); +} + +typedef struct LinkAddBytesArg { + const CfreeBytes* bytes; + const CfreeLinkArchiveInput* archive; +} LinkAddBytesArg; + +static void link_session_add_obj_bytes_inner(CfreeLinkSession* s, void* arg) { + const CfreeBytes* b = ((LinkAddBytesArg*)arg)->bytes; + link_add_obj_bytes(s->linker, b->name, b->data, b->len); +} + +CfreeStatus cfree_link_session_add_obj_bytes(CfreeLinkSession* s, + const CfreeBytes* bytes) { + LinkAddBytesArg arg; + if (!s || !bytes || s->resolved) return CFREE_INVALID; + arg.bytes = bytes; + arg.archive = NULL; + s->non_obj_inputs++; + return link_session_guard(s, link_session_add_obj_bytes_inner, &arg); +} + +static void link_session_add_archive_bytes_inner(CfreeLinkSession* s, + void* arg) { + const CfreeLinkArchiveInput* a = ((LinkAddBytesArg*)arg)->archive; + link_add_archive_bytes(s->linker, a->bytes.name, a->bytes.data, a->bytes.len, + a->whole_archive, a->link_mode, a->group_id); +} + +CfreeStatus cfree_link_session_add_archive_bytes( + CfreeLinkSession* s, const CfreeLinkArchiveInput* archive) { + LinkAddBytesArg arg; + if (!s || !archive || s->resolved) return CFREE_INVALID; + arg.bytes = NULL; + arg.archive = archive; + s->non_obj_inputs++; + return link_session_guard(s, link_session_add_archive_bytes_inner, &arg); +} + +static void link_session_add_dso_bytes_inner(CfreeLinkSession* s, void* arg) { + const CfreeBytes* b = ((LinkAddBytesArg*)arg)->bytes; + link_add_dso_bytes(s->linker, b->name, b->data, b->len); +} + +CfreeStatus cfree_link_session_add_dso_bytes(CfreeLinkSession* s, + const CfreeBytes* bytes) { + LinkAddBytesArg arg; + if (!s || !bytes || s->resolved) return CFREE_INVALID; + arg.bytes = bytes; + arg.archive = NULL; + s->non_obj_inputs++; + return link_session_guard(s, link_session_add_dso_bytes_inner, &arg); +} + +static void link_session_resolve_inner(CfreeLinkSession* s, void* arg) { + (void)arg; + if ((CfreeLinkOutputKind)s->opts.output_kind == + CFREE_LINK_OUTPUT_RELOCATABLE) { + s->resolved = 1; + return; } - l = link_new(c); - if (!l) { - compiler_panic_restore(c, &saved); - return CFREE_NOMEM; + s->image = link_resolve(s->linker); + s->resolved = 1; +} + +CfreeStatus cfree_link_session_resolve(CfreeLinkSession* s) { + if (!s || s->resolved) return CFREE_INVALID; + return link_session_guard(s, link_session_resolve_inner, NULL); +} + +typedef struct LinkEmitArg { + CfreeWriter* out; +} LinkEmitArg; + +static void link_session_emit_inner(CfreeLinkSession* s, void* arg) { + CfreeWriter* out = ((LinkEmitArg*)arg)->out; + if ((CfreeLinkOutputKind)s->opts.output_kind == + CFREE_LINK_OUTPUT_RELOCATABLE) { + link_emit_relocatable_writer(s->linker, out); + } else { + link_emit_image_writer(s->image, out); } - load_inputs(l, &opts->inputs); - link_emit_relocatable_writer(l, out); - link_free(l); - compiler_panic_restore(c, &saved); - return CFREE_OK; } -CfreeStatus cfree_link_jit(CfreeCompiler* c, const CfreeJitLinkOptions* opts, - const CfreeJitHost* host, CfreeJit** out_jit) { - PanicSave saved; - Linker* l; - LinkImage* img; +CfreeStatus cfree_link_session_emit(CfreeLinkSession* s, CfreeWriter* out) { + LinkEmitArg arg; + CfreeStatus st; + if (!s || !out) return CFREE_INVALID; + if (!s->resolved) { + st = cfree_link_session_resolve(s); + if (st != CFREE_OK) return st; + } + if ((CfreeLinkOutputKind)s->opts.output_kind == CFREE_LINK_OUTPUT_JIT) + return CFREE_INVALID; + arg.out = out; + return link_session_guard(s, link_session_emit_inner, &arg); +} + +typedef struct LinkJitArg { CfreeJit* jit; +} LinkJitArg; + +static void link_session_jit_inner(CfreeLinkSession* s, void* arg) { + LinkJitArg* a = (LinkJitArg*)arg; + a->jit = cfree_jit_from_image(s->image); + if (a->jit) { + s->image = NULL; + s->linker_transferred = 1; + s->linker = NULL; + } +} + +CfreeStatus cfree_link_session_jit(CfreeLinkSession* s, CfreeJit** out_jit) { + LinkJitArg arg; + CfreeStatus st; if (!out_jit) return CFREE_INVALID; *out_jit = NULL; - if (!c || !opts || !host) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - l = link_new(c); - if (!l) { - compiler_panic_restore(c, &saved); - return CFREE_NOMEM; - } - link_set_jit_host(l, host); - link_set_jit_mode(l, 1); - if (!opts->inputs.entry) - link_clear_entry(l); - link_set_gc_sections(l, opts->gc_sections); - if (opts->extern_resolver) { - link_set_extern_resolver(l, opts->extern_resolver, - opts->extern_resolver_user); + if (!s || (CfreeLinkOutputKind)s->opts.output_kind != CFREE_LINK_OUTPUT_JIT) + return CFREE_INVALID; + if (!s->resolved) { + st = cfree_link_session_resolve(s); + if (st != CFREE_OK) return st; } - load_inputs(l, &opts->inputs); - img = link_resolve(l); - /* cfree_jit_from_image undefers the Linker / image and binds the JIT - * to them — do not link_free(l) on success. */ - jit = cfree_jit_from_image(img); - if (!jit) { - link_image_free(img); - link_free(l); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - *out_jit = jit; - compiler_panic_restore(c, &saved); + arg.jit = NULL; + st = link_session_guard(s, link_session_jit_inner, &arg); + if (st != CFREE_OK) return st; + if (!arg.jit) return CFREE_ERR; + *out_jit = arg.jit; return CFREE_OK; } + +void cfree_link_session_free(CfreeLinkSession* s) { + Heap* h; + if (!s) return; + h = s->c->ctx->heap; + if (s->image) link_image_free(s->image); + if (s->linker) link_free(s->linker); + if (s->publish_objs) { + h->free(h, s->publish_objs, sizeof(*s->publish_objs) * s->publish_objs_cap); + } + h->free(h, s, sizeof(*s)); +} diff --git a/src/cg/internal.h b/src/cg/internal.h @@ -357,8 +357,10 @@ void cfree_cg_swap(CfreeCg* g); void cfree_cg_drop(CfreeCg* g); int cfree_cg_top_const_int(CfreeCg* g, int64_t* out_value); void cfree_cg_rot3(CfreeCg* g); -CfreeStatus cfree_cg_new(CfreeCompiler* c, CfreeObjBuilder* out, - const CfreeCodeOptions* opts, CfreeCg** cg_out); +CfreeStatus cfree_cg_new(CfreeCompiler* c, CfreeCg** cg_out); +CfreeStatus cfree_cg_begin_obj(CfreeCg* g, CfreeObjBuilder* out, + const CfreeCodeOptions* opts); +CfreeStatus cfree_cg_end_obj(CfreeCg* g); void cfree_cg_free(CfreeCg* g); void cfree_cg_set_loc(CfreeCg* g, CfreeSrcLoc loc); CfreeCgSym cfree_cg_decl(CfreeCg* g, CfreeCgDecl decl); diff --git a/src/cg/session.c b/src/cg/session.c @@ -6,18 +6,98 @@ * via the per-arch ArchImpl. */ CGTarget* c_cgtarget_new(Compiler* c, ObjBuilder* o, CfreeWriter* w); -CfreeStatus cfree_cg_new(CfreeCompiler* c, CfreeObjBuilder* out, - const CfreeCodeOptions* opts, CfreeCg** cg_out) { +static void cg_free_obj_state(CfreeCg* g) { + Heap* h; + u32 i; + if (!g) return; + h = g->c->ctx->heap; + if (g->stack) { + h->free(h, g->stack, sizeof(ApiSValue) * g->cap); + g->stack = NULL; + } + if (g->locals) { + h->free(h, g->locals, sizeof(*g->locals) * g->locals_cap); + g->locals = NULL; + } + if (g->sym_types) { + h->free(h, g->sym_types, sizeof(*g->sym_types) * g->sym_cap); + g->sym_types = NULL; + } + if (g->sym_attrs) { + h->free(h, g->sym_attrs, sizeof(*g->sym_attrs) * g->sym_cap); + g->sym_attrs = NULL; + } + for (i = 0; i < 3; ++i) { + if (g->slot_pools[i].free) { + h->free(h, g->slot_pools[i].free, + sizeof(FrameSlot) * g->slot_pools[i].cap); + g->slot_pools[i].free = NULL; + } + } + if (g->data_tls_collect) { + buf_fini(&g->data_tls_bytes); + g->data_tls_collect = 0; + } + if (g->data_tls_relocs) { + h->free(h, g->data_tls_relocs, + sizeof(*g->data_tls_relocs) * g->data_tls_relocs_cap); + g->data_tls_relocs = NULL; + } + g->sp = 0; + g->cap = 0; + g->nlocals = 0; + g->locals_cap = 0; + g->sym_cap = 0; + memset(g->slot_pools, 0, sizeof(g->slot_pools)); + g->avs_in_flight = NULL; + g->avs_in_flight_n = 0; + g->fn_ret_type = 0; + g->fn_abi = NULL; + memset(&g->fn_desc, 0, sizeof(g->fn_desc)); + memset(g->fn_params, 0, sizeof(g->fn_params)); + memset(g->scopes, 0, sizeof(g->scopes)); + g->nscopes = 0; + g->scope_generation = 0; + g->rodata_counter = 0; + g->data_sec = OBJ_SEC_NONE; + g->data_sym = OBJ_SYM_NONE; + g->data_base = 0; + g->data_size = 0; + g->data_local_static_target = 0; + g->data_tls_zero_fill = 0; + g->data_tls_align = 0; + g->data_tls_nrelocs = 0; + g->data_tls_relocs_cap = 0; +} + +CfreeStatus cfree_cg_new(CfreeCompiler* c, CfreeCg** cg_out) { Heap* h; CfreeCg* g; + if (!cg_out) return CFREE_INVALID; + *cg_out = NULL; + if (!c) return CFREE_INVALID; + h = (Heap*)c->ctx->heap; + g = (CfreeCg*)h->alloc(h, sizeof(CfreeCg), _Alignof(CfreeCg)); + if (!g) return CFREE_NOMEM; + memset(g, 0, sizeof *g); + g->c = (Compiler*)c; + g->data_sec = OBJ_SEC_NONE; + g->data_sym = OBJ_SYM_NONE; + *cg_out = g; + return CFREE_OK; +} + +CfreeStatus cfree_cg_begin_obj(CfreeCg* g, CfreeObjBuilder* out, + const CfreeCodeOptions* opts) { + CfreeCompiler* c; MCEmitter* mc = NULL; CGTarget* target; Debug* debug = NULL; int opt_level = opts ? opts->opt_level : 0; int emit_c_source = opts ? (int)opts->emit_c_source : 0; - if (!cg_out) return CFREE_INVALID; - *cg_out = NULL; - if (!c || !out) return CFREE_INVALID; + if (!g || !g->c || !out) return CFREE_INVALID; + if (g->obj || g->target || g->mc || g->debug) return CFREE_INVALID; + c = (CfreeCompiler*)g->c; if (opt_level < 0 || opt_level > 2) { compiler_panic((Compiler*)c, api_no_loc(), "CfreeCg: unsupported opt_level %d", opt_level); @@ -32,7 +112,6 @@ CfreeStatus cfree_cg_new(CfreeCompiler* c, CfreeObjBuilder* out, } opt_level = 0; } - h = (Heap*)c->ctx->heap; if (!emit_c_source) { mc = mc_new((Compiler*)c, (ObjBuilder*)out); if (!mc) return CFREE_NOMEM; @@ -61,27 +140,17 @@ CfreeStatus cfree_cg_new(CfreeCompiler* c, CfreeObjBuilder* out, target = opt_cgtarget_new((Compiler*)c, target, opt_level); if (target) target->debug = debug; } - g = (CfreeCg*)h->alloc(h, sizeof(CfreeCg), _Alignof(CfreeCg)); - if (!g) { - if (debug) debug_free(debug); - cgtarget_free(target); - mc_free(mc); - return CFREE_NOMEM; - } - memset(g, 0, sizeof *g); - g->c = (Compiler*)c; g->obj = (ObjBuilder*)out; g->target = target; g->mc = mc; g->debug = debug; g->opt_level = opt_level; - *cg_out = g; return CFREE_OK; } -void cfree_cg_free(CfreeCg* g) { - Heap* h; - if (!g) return; +CfreeStatus cfree_cg_end_obj(CfreeCg* g) { + if (!g) return CFREE_INVALID; + if (!g->obj) return CFREE_INVALID; cgtarget_finalize(g->target); if (g->debug) { debug_emit(g->debug); @@ -89,23 +158,19 @@ void cfree_cg_free(CfreeCg* g) { } cgtarget_free(g->target); mc_free(g->mc); + g->obj = NULL; + g->target = NULL; + g->mc = NULL; + g->debug = NULL; + cg_free_obj_state(g); + return CFREE_OK; +} + +void cfree_cg_free(CfreeCg* g) { + Heap* h; + if (!g) return; h = g->c->ctx->heap; - if (g->stack) h->free(h, g->stack, sizeof(ApiSValue) * g->cap); - if (g->locals) { - h->free(h, g->locals, sizeof(*g->locals) * g->locals_cap); - } - if (g->sym_types) { - h->free(h, g->sym_types, sizeof(*g->sym_types) * g->sym_cap); - } - if (g->sym_attrs) { - h->free(h, g->sym_attrs, sizeof(*g->sym_attrs) * g->sym_cap); - } - for (u32 c = 0; c < 3; ++c) { - if (g->slot_pools[c].free) { - h->free(h, g->slot_pools[c].free, - sizeof(FrameSlot) * g->slot_pools[c].cap); - } - } + if (g->obj) (void)cfree_cg_end_obj(g); h->free(h, g, sizeof *g); } diff --git a/src/emu/emu.c b/src/emu/emu.c @@ -201,7 +201,8 @@ static void* translate_block(CfreeEmu* e, u64 guest_pc) { ob = obj_new(e->c); memset(&copts, 0, sizeof(copts)); copts.opt_level = e->opt_level; - st = cfree_cg_new(e->c, (CfreeObjBuilder*)ob, &copts, &cg); + st = cfree_cg_new(e->c, &cg); + if (st == CFREE_OK) st = cfree_cg_begin_obj(cg, (CfreeObjBuilder*)ob, &copts); if (st != CFREE_OK || !cg) compiler_panic(e->c, no_loc(), "emu: cfree_cg_new failed"); diff --git a/src/link/link.h b/src/link/link.h @@ -10,6 +10,20 @@ typedef struct Linker Linker; typedef struct LinkImage LinkImage; +struct CfreeLinkSession { + Compiler* c; + Linker* linker; + CfreeLinkSessionOptions opts; + LinkImage* image; + CfreeObjBuilder** publish_objs; + u32 npublish_objs; + u32 publish_objs_cap; + u32 non_obj_inputs; + u8 resolved; + u8 linker_transferred; + u8 pad[2]; +}; + typedef enum LinkInputKind { LINK_INPUT_OBJ, LINK_INPUT_OBJ_BYTES, diff --git a/src/link/link_jit.c b/src/link/link_jit.c @@ -27,10 +27,10 @@ /* Defined in src/api/objfile.c — exposes the underlying ObjBuilder of a * CfreeObjFile and the internal-only helpers for allocating an empty * CfreeObjFile (used by the JIT debug-view builder). */ -ObjBuilder *cfree_objfile_builder(const CfreeObjFile *); -CfreeObjFile *cfree_objfile_internal_new(const CfreeContext *ctx, +ObjBuilder* cfree_objfile_builder(const CfreeObjFile*); +CfreeObjFile* cfree_objfile_internal_new(const CfreeContext* ctx, CfreeTarget target, CfreeObjFmt fmt); -void cfree_objfile_internal_free(CfreeObjFile *); +void cfree_objfile_internal_free(CfreeObjFile*); #define jit_view_objfile_free(f) cfree_objfile_internal_free(f) static SrcLoc no_loc(void) { @@ -38,17 +38,16 @@ static SrcLoc no_loc(void) { return l; } -static const CfreeJitHost *jit_host_from_linker(Linker *l, Compiler *c) { - const CfreeJitHost *host = l ? l->jit_host : NULL; +static const CfreeJitHost* jit_host_from_linker(Linker* l, Compiler* c) { + const CfreeJitHost* host = l ? l->jit_host : NULL; if (!host) - compiler_panic(c, no_loc(), - "cfree_jit: link jit host is required for JIT"); + compiler_panic(c, no_loc(), "cfree_jit: link jit host is required for JIT"); return host; } -static const CfreeExecMem *require_execmem_h(const CfreeJitHost *host, - Compiler *c) { - const CfreeExecMem *m = host ? host->execmem : NULL; +static const CfreeExecMem* require_execmem_h(const CfreeJitHost* host, + Compiler* c) { + const CfreeExecMem* m = host ? host->execmem : NULL; if (!m || !m->reserve || !m->protect || !m->release) { compiler_panic(c, no_loc(), "cfree_jit: jit host execmem is required for JIT"); @@ -56,8 +55,8 @@ static const CfreeExecMem *require_execmem_h(const CfreeJitHost *host, return m; } -static u64 jit_page_size_h(const CfreeJitHost *host, Compiler *c) { - const CfreeExecMem *m = require_execmem_h(host, c); +static u64 jit_page_size_h(const CfreeJitHost* host, Compiler* c) { + const CfreeExecMem* m = require_execmem_h(host, c); return m->page_size ? (u64)m->page_size : 0x4000u; } @@ -69,8 +68,8 @@ static u64 jit_page_size_h(const CfreeJitHost *host, Compiler *c) { * its final perms. No virtual page is ever simultaneously writable and * executable. */ struct CfreeJit { - Compiler *c; - LinkImage *image; + Compiler* c; + LinkImage* image; /* Single contiguous reservation covering every segment. All segments * are sub-ranges of this region — runtime/write aliases are derived * by offsetting against (image-vaddr - image_base). Keeping them @@ -80,15 +79,15 @@ struct CfreeJit { * close together. */ CfreeExecMemRegion master; u64 image_base; /* page-aligned image vaddr that maps to master.* */ - CfreeExecMemRegion *segs; /* one per image->nsegments; views into master */ + CfreeExecMemRegion* segs; /* one per image->nsegments; views into master */ u32 nsegs; /* DWARF view, lazily constructed on first cfree_jit_view call. Built * over a private Compiler so its string pools and the new ObjBuilder * are owned end-to-end by the view; freed in cfree_jit_free. NULL * means "not yet built"; view_built distinguishes "tried and gave up" * (multi-input v1, etc.) from "untried". */ - CfreeObjFile *view; - Linker *linker; /* kept alive for append-time resolver/input context */ + CfreeObjFile* view; + Linker* linker; /* kept alive for append-time resolver/input context */ u64 append_cursor[SEG_NBUCKETS]; u64 append_limit[SEG_NBUCKETS]; u64 generation; @@ -97,13 +96,13 @@ struct CfreeJit { * borrowed from CfreeEnv (lives across the env's lifetime); `tls_ctx` * is owned by us and freed via tls_vtable->ctx_destroy in * cfree_jit_free. */ - const CfreeJitTls *tls_vtable; - void *tls_ctx; + const CfreeJitTls* tls_vtable; + void* tls_ctx; /* Borrowed JIT host: execmem + tls vtables. Mirrors the Linker's * jit_host so the JIT's lifetime accessors don't need to walk back to * the Linker (which is still live behind jit->linker but may be * decoupled in incremental flows). */ - const CfreeJitHost *jit_host; + const CfreeJitHost* jit_host; u8 view_built; u8 pad[7]; }; @@ -124,10 +123,8 @@ static int reloc_is_tlsle(RelocKind k) { static int perms_for(u32 secflags) { int p = CFREE_PROT_READ; - if (secflags & SF_EXEC) - p |= CFREE_PROT_EXEC; - if (secflags & SF_WRITE) - p |= CFREE_PROT_WRITE; + if (secflags & SF_EXEC) p |= CFREE_PROT_EXEC; + if (secflags & SF_WRITE) p |= CFREE_PROT_WRITE; return p; } @@ -139,21 +136,20 @@ static int perms_for(u32 secflags) { * one-past-end boundary (e.g. `__fini_array_end` when .fini_array is * the last section in its segment) still resolve, while preferring an * exact start-of-next-segment match when segments happen to abut. */ -static uintptr_t vaddr_to_runtime(const LinkImage *img, - const CfreeExecMemRegion *segs, u64 vaddr) { +static uintptr_t vaddr_to_runtime(const LinkImage* img, + const CfreeExecMemRegion* segs, u64 vaddr) { u32 i; for (i = 0; i < img->nsegments; ++i) { - const LinkSegment *s = &img->segments[i]; + const LinkSegment* s = &img->segments[i]; u64 lo = s->vaddr; u64 hi = lo + s->mem_size; if (vaddr >= lo && vaddr < hi) return (uintptr_t)segs[i].runtime + (uintptr_t)(vaddr - lo); } for (i = 0; i < img->nsegments; ++i) { - const LinkSegment *s = &img->segments[i]; + const LinkSegment* s = &img->segments[i]; u64 hi = s->vaddr + s->mem_size; - if (vaddr == hi) - return (uintptr_t)segs[i].runtime + (uintptr_t)s->mem_size; + if (vaddr == hi) return (uintptr_t)segs[i].runtime + (uintptr_t)s->mem_size; } return 0; } @@ -162,39 +158,37 @@ static uintptr_t vaddr_to_runtime(const LinkImage *img, * the byte position at which to apply a relocation. The PC-relative * arithmetic in link_reloc_apply uses the runtime address; the bytes * themselves get patched at the matching offset of the write alias. */ -static uintptr_t vaddr_to_write(const LinkImage *img, - const CfreeExecMemRegion *segs, u64 vaddr) { +static uintptr_t vaddr_to_write(const LinkImage* img, + const CfreeExecMemRegion* segs, u64 vaddr) { u32 i; for (i = 0; i < img->nsegments; ++i) { - const LinkSegment *s = &img->segments[i]; + const LinkSegment* s = &img->segments[i]; u64 lo = s->vaddr; u64 hi = lo + s->mem_size; if (vaddr >= lo && vaddr < hi) return (uintptr_t)segs[i].write + (uintptr_t)(vaddr - lo); } for (i = 0; i < img->nsegments; ++i) { - const LinkSegment *s = &img->segments[i]; + const LinkSegment* s = &img->segments[i]; u64 hi = s->vaddr + s->mem_size; - if (vaddr == hi) - return (uintptr_t)segs[i].write + (uintptr_t)s->mem_size; + if (vaddr == hi) return (uintptr_t)segs[i].write + (uintptr_t)s->mem_size; } return 0; } -static void jit_copy_input_section_bytes(LinkImage *img, - const CfreeExecMemRegion *segs) { - Compiler *c = img->c; - Linker *l = img->linker; +static void jit_copy_input_section_bytes(LinkImage* img, + const CfreeExecMemRegion* segs) { + Compiler* c = img->c; + Linker* l = img->linker; u32 i; for (i = 0; i < img->nsections; ++i) { - const LinkSection *ls = &img->sections[i]; - const LinkSegment *seg; - ObjBuilder *ob; - const Section *s; + const LinkSection* ls = &img->sections[i]; + const LinkSegment* seg; + ObjBuilder* ob; + const Section* s; u32 input_idx; - u8 *dst; - if (ls->input_id == LINK_INPUT_NONE) - continue; + u8* dst; + if (ls->input_id == LINK_INPUT_NONE) continue; input_idx = ls->input_id - 1u; if (ls->segment_id == LINK_SEG_NONE || ls->segment_id > img->nsegments) compiler_panic(c, no_loc(), @@ -207,11 +201,9 @@ static void jit_copy_input_section_bytes(LinkImage *img, compiler_panic(c, no_loc(), "cfree_jit_from_image: input section bytes unavailable"); s = obj_section_get(ob, ls->obj_section_id); - if (!s || s->sem == SSEM_NOBITS) - continue; - if (s->bytes.total == 0) - continue; - dst = (u8 *)segs[seg->id - 1u].write + (size_t)(ls->vaddr - seg->vaddr); + if (!s || s->sem == SSEM_NOBITS) continue; + if (s->bytes.total == 0) continue; + dst = (u8*)segs[seg->id - 1u].write + (size_t)(ls->vaddr - seg->vaddr); metrics_count(c, "jit.input_section_bytes", s->bytes.total); buf_flatten(&s->bytes, dst); } @@ -225,13 +217,11 @@ static void jit_copy_input_section_bytes(LinkImage *img, * The +16 reloc gives us the storage symbol's image vaddr; subtracting * img->tls_vaddr yields the per-thread byte offset our thunk adds to the * caller's TLS block on every access. */ -static void jit_patch_tlv_descriptors(CfreeJit *jit) { - LinkImage *img = jit->image; - Compiler *c = jit->c; - if (c->target.obj != CFREE_OBJ_MACHO) - return; - if (img->tls_memsz == 0) - return; +static void jit_patch_tlv_descriptors(CfreeJit* jit) { + LinkImage* img = jit->image; + Compiler* c = jit->c; + if (c->target.obj != CFREE_OBJ_MACHO) return; + if (img->tls_memsz == 0) return; /* Find every LinkSymId whose interned name is __tlv_bootstrap. The * symbol is emitted as a weak-undef per TU (one ObjBuilder appends @@ -243,14 +233,14 @@ static void jit_patch_tlv_descriptors(CfreeJit *jit) { * Bitmap over LinkSymId so the inner reloc test is O(1). */ Sym tlv_name = pool_intern_cstr(c->global, "__tlv_bootstrap"); u32 nsyms = LinkSyms_count(&img->syms); - Heap *h = (Heap *)c->ctx->heap; - u8 *is_tlv_bootstrap = (u8 *)h->alloc(h, nsyms + 1u, 1u); + Heap* h = (Heap*)c->ctx->heap; + u8* is_tlv_bootstrap = (u8*)h->alloc(h, nsyms + 1u, 1u); if (!is_tlv_bootstrap) compiler_panic(c, no_loc(), "cfree_jit: oom on tlv-bootstrap bitmap"); memset(is_tlv_bootstrap, 0, nsyms + 1u); int any_tlv = 0; for (u32 si = 0; si < nsyms; ++si) { - LinkSymbol *s = LinkSyms_at(&img->syms, si); + LinkSymbol* s = LinkSyms_at(&img->syms, si); if (s && s->name == tlv_name) { is_tlv_bootstrap[si + 1u] = 1u; any_tlv = 1; @@ -261,7 +251,7 @@ static void jit_patch_tlv_descriptors(CfreeJit *jit) { return; } - const CfreeJitTls *tls = jit->jit_host ? jit->jit_host->tls : NULL; + const CfreeJitTls* tls = jit->jit_host ? jit->jit_host->tls : NULL; if (!tls || !tls->ctx_new || !tls->ctx_destroy) compiler_panic(c, no_loc(), "cfree_jit: image needs TLV thunk but jit host tls is NULL " @@ -270,15 +260,15 @@ static void jit_patch_tlv_descriptors(CfreeJit *jit) { /* Snapshot the TLS image's init bytes from the write alias. The * write alias of any SF_TLS section stays readable for the lifetime * of CfreeJit; ctx_new is expected to copy what it needs. */ - const u8 *init_bytes = NULL; + const u8* init_bytes = NULL; if (img->tls_filesz) { - init_bytes = (const u8 *)vaddr_to_write(img, jit->segs, img->tls_vaddr); + init_bytes = (const u8*)vaddr_to_write(img, jit->segs, img->tls_vaddr); if (!init_bytes) compiler_panic(c, no_loc(), "cfree_jit: tls_vaddr does not map to any segment"); } size_t align = img->tls_align ? (size_t)img->tls_align : 1u; - void *ctx = tls->ctx_new(tls->user, init_bytes, (size_t)img->tls_filesz, + void* ctx = tls->ctx_new(tls->user, init_bytes, (size_t)img->tls_filesz, (size_t)img->tls_memsz, align); if (!ctx) compiler_panic(c, no_loc(), "cfree_jit: jit_tls->ctx_new returned NULL"); @@ -289,19 +279,17 @@ static void jit_patch_tlv_descriptors(CfreeJit *jit) { uintptr_t thunk_addr = (uintptr_t)&cfree_jit_tlv_thunk; u32 nrel = LinkRelocs_count(&img->relocs); for (u32 i = 0; i < nrel; ++i) { - const LinkRelocApply *r = LinkRelocs_at(&img->relocs, i); - if (r->target == LINK_SYM_NONE || !is_tlv_bootstrap[r->target]) - continue; - if (r->kind != R_ABS64) - continue; + const LinkRelocApply* r = LinkRelocs_at(&img->relocs, i); + if (r->target == LINK_SYM_NONE || !is_tlv_bootstrap[r->target]) continue; + if (r->kind != R_ABS64) continue; u64 desc_vaddr = r->write_vaddr; /* Locate the paired +16 reloc. Quadratic, but reloc counts are * small (one reloc pair per TLV var) so the inner scan amortizes. */ - const LinkRelocApply *r16 = NULL; + const LinkRelocApply* r16 = NULL; for (u32 j = 0; j < nrel; ++j) { - const LinkRelocApply *q = LinkRelocs_at(&img->relocs, j); + const LinkRelocApply* q = LinkRelocs_at(&img->relocs, j); if (q->kind == R_ABS64 && q->write_vaddr == desc_vaddr + 16u) { r16 = q; break; @@ -311,13 +299,13 @@ static void jit_patch_tlv_descriptors(CfreeJit *jit) { compiler_panic(c, no_loc(), "cfree_jit: TLV descriptor missing data-symbol reloc"); - const LinkSymbol *data_sym = LinkSyms_at(&img->syms, r16->target - 1); + const LinkSymbol* data_sym = LinkSyms_at(&img->syms, r16->target - 1); if (!data_sym || !data_sym->defined) compiler_panic(c, no_loc(), "cfree_jit: TLV descriptor data symbol is undefined"); u64 offset_in_image = (data_sym->vaddr + (u64)r16->addend) - img->tls_vaddr; - u8 *write = (u8 *)vaddr_to_write(img, jit->segs, desc_vaddr); + u8* write = (u8*)vaddr_to_write(img, jit->segs, desc_vaddr); if (!write) compiler_panic(c, no_loc(), "cfree_jit: TLV descriptor vaddr does not map"); @@ -329,13 +317,13 @@ static void jit_patch_tlv_descriptors(CfreeJit *jit) { h->free(h, is_tlv_bootstrap, nsyms + 1u); } -CfreeJit *cfree_jit_from_image(LinkImage *img) { - Compiler *c; - Heap *heap; - const CfreeExecMem *mem; - const CfreeJitHost *host; - CfreeJit *jit; - CfreeExecMemRegion *segs; +CfreeJit* cfree_jit_from_image(LinkImage* img) { + Compiler* c; + Heap* heap; + const CfreeExecMem* mem; + const CfreeJitHost* host; + CfreeJit* jit; + CfreeExecMemRegion* segs; CfreeExecMemRegion master; u64 page; u64 image_base = (u64)-1; @@ -347,8 +335,7 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { int needs_input_materialize = 0; u32 i; - if (!img) - return NULL; + if (!img) return NULL; c = img->c; heap = img->heap; host = jit_host_from_linker(img->linker, c); @@ -367,14 +354,11 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { needs_exec = 1; } else { for (i = 0; i < img->nsegments; ++i) { - const LinkSegment *seg = &img->segments[i]; + const LinkSegment* seg = &img->segments[i]; u64 hi = ALIGN_UP(seg->vaddr + seg->mem_size, page); - if (seg->vaddr < image_base) - image_base = seg->vaddr; - if (hi > image_end) - image_end = hi; - if (seg->flags & SF_EXEC) - needs_exec = 1; + if (seg->vaddr < image_base) image_base = seg->vaddr; + if (hi > image_end) image_end = hi; + if (seg->flags & SF_EXEC) needs_exec = 1; } } if (image_base & (page - 1u)) @@ -393,8 +377,7 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { * perms are applied via mem->protect on sub-ranges below. */ { int master_prot = CFREE_PROT_READ | CFREE_PROT_WRITE; - if (needs_exec) - master_prot |= CFREE_PROT_EXEC; + if (needs_exec) master_prot |= CFREE_PROT_EXEC; metrics_scope_begin(c, "jit.reserve"); if (mem->reserve(mem->user, (size_t)master_size, master_prot, &master) != 0) { @@ -406,12 +389,11 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { segs = NULL; if (img->nsegments) { - segs = (CfreeExecMemRegion *)heap->alloc( + segs = (CfreeExecMemRegion*)heap->alloc( heap, sizeof(*segs) * img->nsegments, _Alignof(CfreeExecMemRegion)); if (!segs) { mem->release(mem->user, &master); - compiler_panic(c, no_loc(), - "cfree_jit_from_image: oom on segment table"); + compiler_panic(c, no_loc(), "cfree_jit_from_image: oom on segment table"); } memset(segs, 0, sizeof(*segs) * img->nsegments); } @@ -420,11 +402,11 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { * master reservation owns the underlying mapping and is released in * cfree_jit_free. */ for (i = 0; i < img->nsegments; ++i) { - const LinkSegment *seg = &img->segments[i]; + const LinkSegment* seg = &img->segments[i]; u64 off = seg->vaddr - image_base; size_t mlen = (size_t)ALIGN_UP(seg->mem_size, page); - segs[i].write = (u8 *)master.write + off; - segs[i].runtime = (u8 *)master.runtime + off; + segs[i].write = (u8*)master.write + off; + segs[i].runtime = (u8*)master.runtime + off; segs[i].size = mlen; segs[i].token = NULL; } @@ -435,9 +417,8 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { * and are materialized directly from input Buf chunks below. */ metrics_scope_begin(c, "jit.copy_segments"); for (i = 0; i < img->nsegments; ++i) { - const LinkSegment *seg = &img->segments[i]; - if (seg->file_size == 0) - continue; + const LinkSegment* seg = &img->segments[i]; + if (seg->file_size == 0) continue; if (!img->segment_bytes[i]) { needs_input_materialize = 1; continue; @@ -458,10 +439,10 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { * alias; PC-relative arithmetic uses the runtime alias address. */ metrics_scope_begin(c, "jit.apply_relocs"); for (i = 0; i < LinkRelocs_count(&img->relocs); ++i) { - const LinkRelocApply *r = LinkRelocs_at(&img->relocs, i); - const LinkSymbol *tgt = LinkSyms_at(&img->syms, r->target - 1); + const LinkRelocApply* r = LinkRelocs_at(&img->relocs, i); + const LinkSymbol* tgt = LinkSyms_at(&img->syms, r->target - 1); u64 S, P; - u8 *P_bytes; + u8* P_bytes; if (reloc_is_tlsle(r->kind)) { /* TLSLE: S is the TP-relative offset of the target. Both * vaddrs are image-relative, so the runtime alias drops @@ -475,7 +456,7 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { S = (u64)vaddr_to_runtime(img, segs, tgt->vaddr); } P = (u64)vaddr_to_runtime(img, segs, r->write_vaddr); - P_bytes = (u8 *)vaddr_to_write(img, segs, r->write_vaddr); + P_bytes = (u8*)vaddr_to_write(img, segs, r->write_vaddr); /* Weak-undef target: vaddr is 0, address-of must evaluate to NULL * (§"weak attribute resolves to 0 at link time"). For an AArch64 * ADRP + ADD pair against such a target, the PCREL displacement @@ -532,19 +513,18 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { * accepts arbitrary [addr,size) inside the reservation. */ metrics_scope_begin(c, "jit.protect"); for (i = 0; i < img->nsegments; ++i) { - const LinkSegment *seg = &img->segments[i]; + const LinkSegment* seg = &img->segments[i]; if (mem->protect(mem->user, segs[i].runtime, segs[i].size, perms_for(seg->flags)) != 0) { mem->release(mem->user, &master); - if (segs) - heap->free(heap, segs, sizeof(*segs) * img->nsegments); + if (segs) heap->free(heap, segs, sizeof(*segs) * img->nsegments); compiler_panic(c, no_loc(), "cfree_jit_from_image: execmem.protect failed"); } } if (append_total) { - void *slack_rt = - (u8 *)master.runtime + (uintptr_t)(append_start - image_base); + void* slack_rt = + (u8*)master.runtime + (uintptr_t)(append_start - image_base); (void)mem->protect(mem->user, slack_rt, (size_t)append_total, CFREE_PROT_NONE); } @@ -555,7 +535,7 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { if (mem->flush_icache) { metrics_scope_begin(c, "jit.flush_icache"); for (i = 0; i < img->nsegments; ++i) { - const LinkSegment *seg = &img->segments[i]; + const LinkSegment* seg = &img->segments[i]; if (seg->flags & SF_EXEC) mem->flush_icache(mem->user, segs[i].runtime, segs[i].size); } @@ -568,26 +548,25 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { * runtime address. The iplt stub then loads the slot and tail- * calls the chosen implementation on every invocation. */ if (img->niplt) { - typedef void *(*ResolverFn)(void); + typedef void* (*ResolverFn)(void); for (i = 0; i < img->niplt; ++i) { u64 resolver_vaddr = img->iplt_pairs[2u * i + 0]; u64 slot_vaddr = img->iplt_pairs[2u * i + 1]; uintptr_t resolver_rt = vaddr_to_runtime(img, segs, resolver_vaddr); uintptr_t slot_rt = vaddr_to_runtime(img, segs, slot_vaddr); - void *impl; + void* impl; if (!resolver_rt || !slot_rt) compiler_panic(c, no_loc(), "cfree_jit: iplt vaddr does not map to runtime"); impl = ((ResolverFn)resolver_rt)(); - *(void **)(uintptr_t)slot_rt = impl; + *(void**)(uintptr_t)slot_rt = impl; } } - jit = (CfreeJit *)heap->alloc(heap, sizeof(*jit), _Alignof(CfreeJit)); + jit = (CfreeJit*)heap->alloc(heap, sizeof(*jit), _Alignof(CfreeJit)); if (!jit) { mem->release(mem->user, &master); - if (segs) - heap->free(heap, segs, sizeof(*segs) * img->nsegments); + if (segs) heap->free(heap, segs, sizeof(*segs) * img->nsegments); compiler_panic(c, no_loc(), "cfree_jit_from_image: oom on jit handle"); } jit->c = c; @@ -633,15 +612,14 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { /* Run .init_array constructors in forward order. */ { typedef void (*VoidFn)(void); - void *p_start = cfree_jit_lookup(jit, "__init_array_start"); - void *p_end = cfree_jit_lookup(jit, "__init_array_end"); + void* p_start = cfree_jit_lookup(jit, "__init_array_start"); + void* p_end = cfree_jit_lookup(jit, "__init_array_end"); if (p_start && p_end) { - VoidFn *fn = (VoidFn *)p_start; - VoidFn *end = (VoidFn *)p_end; + VoidFn* fn = (VoidFn*)p_start; + VoidFn* end = (VoidFn*)p_end; metrics_scope_begin(c, "jit.ctors"); for (; fn != end; ++fn) - if (*fn) - (*fn)(); + if (*fn) (*fn)(); metrics_scope_end(c, "jit.ctors"); } } @@ -649,18 +627,16 @@ CfreeJit *cfree_jit_from_image(LinkImage *img) { return jit; } -const CfreeExecMem *cfree_jit_image_execmem(CfreeJit *jit) { - if (!jit || !jit->jit_host) - return NULL; +const CfreeExecMem* cfree_jit_image_execmem(CfreeJit* jit) { + if (!jit || !jit->jit_host) return NULL; return jit->jit_host->execmem; } -void cfree_jit_free(CfreeJit *jit) { - Heap *heap; - const CfreeExecMem *mem; - if (!jit) - return; - heap = (Heap *)jit->c->ctx->heap; +void cfree_jit_free(CfreeJit* jit) { + Heap* heap; + const CfreeExecMem* mem; + if (!jit) return; + heap = (Heap*)jit->c->ctx->heap; mem = jit->jit_host ? jit->jit_host->execmem : NULL; /* The debug view (if built) is closed first — it owns a private * Compiler whose pools must be released before the image's @@ -697,29 +673,24 @@ void cfree_jit_free(CfreeJit *jit) { heap->free(heap, jit, sizeof(*jit)); } -void *cfree_jit_lookup(CfreeJit *jit, const char *name) { +void* cfree_jit_lookup(CfreeJit* jit, const char* name) { Sym sym; LinkSymId id; - const LinkSymbol *s; - if (!jit || !name) - return NULL; + const LinkSymbol* s; + if (!jit || !name) return NULL; /* C-symbol mangling lives in obj_format_c_mangle so JIT lookups by * source-level name find the symbol regardless of target format. */ sym = obj_format_c_mangle(jit->c, name); id = symhash_get(&jit->image->globals, sym); - if (id == LINK_SYM_NONE) - return NULL; + if (id == LINK_SYM_NONE) return NULL; s = LinkSyms_at(&jit->image->syms, id - 1); - if (!s) - return NULL; - if (!s->defined) - return NULL; - if (s->kind == SK_ABS) - return (void *)(uintptr_t)s->vaddr; - return (void *)vaddr_to_runtime(jit->image, jit->segs, s->vaddr); + if (!s) return NULL; + if (!s->defined) return NULL; + if (s->kind == SK_ABS) return (void*)(uintptr_t)s->vaddr; + return (void*)vaddr_to_runtime(jit->image, jit->segs, s->vaddr); } -uint64_t cfree_jit_generation(CfreeJit *jit) { +uint64_t cfree_jit_generation(CfreeJit* jit) { return jit ? jit->generation : 0; } @@ -739,24 +710,24 @@ typedef struct JitAppendSec { static int jit_bind_strength(u8 bind) { switch (bind) { - case SB_GLOBAL: - return 3; - case SB_WEAK: - return 2; - case SB_LOCAL: - return 1; - default: - return 0; + case SB_GLOBAL: + return 3; + case SB_WEAK: + return 2; + case SB_LOCAL: + return 1; + default: + return 0; } } -static int jit_obj_sym_is_def(const ObjSym *s) { +static int jit_obj_sym_is_def(const ObjSym* s) { return s && s->kind != SK_UNDEF && (s->kind == SK_ABS || s->kind == SK_COMMON || s->kind == SK_FILE || s->section_id != OBJ_SEC_NONE); } -static int jit_obj_sym_is_spurious_undef(const ObjSym *s) { +static int jit_obj_sym_is_spurious_undef(const ObjSym* s) { return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && s->kind != SK_COMMON && !s->referenced && (s->bind == SB_GLOBAL || s->bind == SB_WEAK); @@ -764,44 +735,42 @@ static int jit_obj_sym_is_spurious_undef(const ObjSym *s) { static u8 jit_reloc_width_local(RelocKind k) { switch (k) { - case R_ABS64: - case R_REL64: - case R_PC64: - case R_X64_TPOFF64: - return 8; - case R_AARCH64_ABS16: - case R_AARCH64_PREL16: - case R_RV_RVC_BRANCH: - case R_RV_RVC_JUMP: - return 2; - case R_RV_ADD8: - case R_RV_SUB8: - case R_RV_SUB6: - case R_RV_SET6: - case R_RV_SET8: - return 1; - default: - return 4; + case R_ABS64: + case R_REL64: + case R_PC64: + case R_X64_TPOFF64: + return 8; + case R_AARCH64_ABS16: + case R_AARCH64_PREL16: + case R_RV_RVC_BRANCH: + case R_RV_RVC_JUMP: + return 2; + case R_RV_ADD8: + case R_RV_SUB8: + case R_RV_SUB6: + case R_RV_SET6: + case R_RV_SET8: + return 1; + default: + return 4; } } -static InputMap jit_input_map_alloc(CfreeJit *jit, ObjBuilder *ob) { +static InputMap jit_input_map_alloc(CfreeJit* jit, ObjBuilder* ob) { InputMap m; - ObjSymIter *it; + ObjSymIter* it; ObjSymEntry e; u32 nsyms = 0; - Heap *h = jit->image->heap; + Heap* h = jit->image->heap; memset(&m, 0, sizeof(m)); it = obj_symiter_new(ob); - while (obj_symiter_next(it, &e)) - ++nsyms; + while (obj_symiter_next(it, &e)) ++nsyms; obj_symiter_free(it); m.nsym = nsyms + 1u; - m.sym = - (LinkSymId *)h->alloc(h, sizeof(*m.sym) * m.nsym, _Alignof(LinkSymId)); + m.sym = (LinkSymId*)h->alloc(h, sizeof(*m.sym) * m.nsym, _Alignof(LinkSymId)); m.nsection = obj_section_count(ob); - m.section = (LinkSectionId *)h->alloc(h, sizeof(*m.section) * m.nsection, - _Alignof(LinkSectionId)); + m.section = (LinkSectionId*)h->alloc(h, sizeof(*m.section) * m.nsection, + _Alignof(LinkSectionId)); if (!m.sym || !m.section) compiler_panic(jit->c, no_loc(), "cfree_jit_append_obj: oom on input map"); memset(m.sym, 0, sizeof(*m.sym) * m.nsym); @@ -809,7 +778,7 @@ static InputMap jit_input_map_alloc(CfreeJit *jit, ObjBuilder *ob) { return m; } -static void jit_invalidate_view(CfreeJit *jit) { +static void jit_invalidate_view(CfreeJit* jit) { if (jit->view) { jit_view_objfile_free(jit->view); jit->view = NULL; @@ -817,12 +786,12 @@ static void jit_invalidate_view(CfreeJit *jit) { jit->view_built = 0u; } -static void jit_apply_one_reloc(CfreeJit *jit, const LinkRelocApply *r) { - LinkImage *img = jit->image; - const LinkSymbol *tgt = LinkSyms_at(&img->syms, r->target - 1); +static void jit_apply_one_reloc(CfreeJit* jit, const LinkRelocApply* r) { + LinkImage* img = jit->image; + const LinkSymbol* tgt = LinkSyms_at(&img->syms, r->target - 1); u64 S; u64 P; - u8 *P_bytes; + u8* P_bytes; if (reloc_is_tlsle(r->kind)) { S = (tgt->vaddr - img->tls_vaddr) + AARCH64_TCB_SIZE; } else if (tgt->kind == SK_ABS) { @@ -831,7 +800,7 @@ static void jit_apply_one_reloc(CfreeJit *jit, const LinkRelocApply *r) { S = (u64)vaddr_to_runtime(img, jit->segs, tgt->vaddr); } P = (u64)vaddr_to_runtime(img, jit->segs, r->write_vaddr); - P_bytes = (u8 *)vaddr_to_write(img, jit->segs, r->write_vaddr); + P_bytes = (u8*)vaddr_to_write(img, jit->segs, r->write_vaddr); if (!P_bytes) compiler_panic(jit->c, no_loc(), "cfree_jit_append_obj: relocation site is unmapped"); @@ -843,8 +812,7 @@ static void jit_apply_one_reloc(CfreeJit *jit, const LinkRelocApply *r) { wr_u32_le(P_bytes, 0xd2800000u | rd); return; } - if (r->kind == R_AARCH64_ADD_ABS_LO12_NC) - return; + if (r->kind == R_AARCH64_ADD_ABS_LO12_NC) return; } if (r->kind == R_AARCH64_TLVP_LOAD_PAGEOFF12) { u64 v = ((u64)S + (u64)r->addend) & 0xfffu; @@ -864,10 +832,10 @@ static void jit_apply_one_reloc(CfreeJit *jit, const LinkRelocApply *r) { link_reloc_apply(jit->c, r->kind, P_bytes, S, r->addend, P); } -static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { - LinkImage *img = jit->image; - Heap *h = img->heap; - const CfreeExecMem *mem = require_execmem_h(jit->jit_host, jit->c); +static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { + LinkImage* img = jit->image; + Heap* h = img->heap; + const CfreeExecMem* mem = require_execmem_h(jit->jit_host, jit->c); u64 page = jit_page_size_h(jit->jit_host, jit->c); u32 old_nsections = img->nsections; u32 old_nsegments = img->nsegments; @@ -877,18 +845,17 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { u32 old_nrelocs = LinkRelocs_count(&img->relocs); u64 old_cursor[SEG_NBUCKETS]; InputMap m; - JitAppendSec *secs = NULL; + JitAppendSec* secs = NULL; u32 nsecs = 0, sec_cap = 0; u32 obj_sec_count; u64 cursor[SEG_NBUCKETS]; LinkInputId new_input_id; u32 new_input_idx; - ObjSymIter *it; + ObjSymIter* it; ObjSymEntry e; u32 i; - for (i = 0; i < SEG_NBUCKETS; ++i) - old_cursor[i] = jit->append_cursor[i]; + for (i = 0; i < SEG_NBUCKETS; ++i) old_cursor[i] = jit->append_cursor[i]; if (!jit || !ob || !jit->linker || obj_compiler(ob) != jit->c) compiler_panic(jit ? jit->c : NULL, no_loc(), @@ -898,19 +865,18 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { * mutating image-visible state. */ it = obj_symiter_new(ob); while (obj_symiter_next(it, &e)) { - const ObjSym *s = e.sym; - if (jit_obj_sym_is_spurious_undef(s)) - continue; + const ObjSym* s = e.sym; + if (jit_obj_sym_is_spurious_undef(s)) continue; if (jit_obj_sym_is_def(s) && s->name != 0 && (s->bind == SB_GLOBAL || s->bind == SB_WEAK)) { LinkSymId existing = symhash_get(&img->globals, s->name); if (existing != LINK_SYM_NONE) { - LinkSymbol *prev = LinkSyms_at(&img->syms, existing - 1); + LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); if (prev && prev->defined && jit_bind_strength((u8)s->bind) == jit_bind_strength(SB_GLOBAL) && jit_bind_strength(prev->bind) == jit_bind_strength(SB_GLOBAL)) { size_t namelen; - const char *nm = pool_str(jit->c->global, s->name, &namelen); + const char* nm = pool_str(jit->c->global, s->name, &namelen); obj_format_demangle_c(jit->c, &nm, &namelen); obj_symiter_free(it); compiler_panic(jit->c, no_loc(), @@ -922,15 +888,14 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { LinkSymId hit = symhash_get(&img->globals, s->name); int ok = 0; if (hit != LINK_SYM_NONE) { - LinkSymbol *def = LinkSyms_at(&img->syms, hit - 1); - if (def && def->defined) - ok = 1; + LinkSymbol* def = LinkSyms_at(&img->syms, hit - 1); + if (def && def->defined) ok = 1; } if (!ok) { - ObjSymIter *it2 = obj_symiter_new(ob); + ObjSymIter* it2 = obj_symiter_new(ob); ObjSymEntry e2; while (obj_symiter_next(it2, &e2)) { - const ObjSym *d = e2.sym; + const ObjSym* d = e2.sym; if (d && d->name == s->name && jit_obj_sym_is_def(d) && (d->bind == SB_GLOBAL || d->bind == SB_WEAK)) { ok = 1; @@ -941,16 +906,14 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { } if (!ok && jit->linker->resolver) { size_t namelen; - const char *nm = pool_str(jit->c->global, s->name, &namelen); + const char* nm = pool_str(jit->c->global, s->name, &namelen); (void)namelen; - if (jit->linker->resolver(jit->linker->resolver_user, nm)) - ok = 1; + if (jit->linker->resolver(jit->linker->resolver_user, nm)) ok = 1; } - if (!ok && s->bind == SB_WEAK) - ok = 1; + if (!ok && s->bind == SB_WEAK) ok = 1; if (!ok) { size_t nlen; - const char *nm = pool_str(jit->c->global, s->name, &nlen); + const char* nm = pool_str(jit->c->global, s->name, &nlen); if (nm && nlen == 15u && memcmp(nm, "__tlv_bootstrap", 15u) == 0) ok = 1; if (!ok) { @@ -967,19 +930,16 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { m = jit_input_map_alloc(jit, ob); obj_sec_count = obj_section_count(ob); - for (i = 0; i < SEG_NBUCKETS; ++i) - cursor[i] = jit->append_cursor[i]; + for (i = 0; i < SEG_NBUCKETS; ++i) cursor[i] = jit->append_cursor[i]; for (i = 1; i < obj_sec_count; ++i) { - const Section *s = obj_section_get(ob, (ObjSecId)i); + const Section* s = obj_section_get(ob, (ObjSecId)i); SegBucket b; u64 size; u64 vaddr; - if (!s || !link_section_kept(s)) - continue; + if (!s || !link_section_kept(s)) continue; size = (s->sem == SSEM_NOBITS) ? (u64)s->bss_size : (u64)s->bytes.total; - if (size == 0) - continue; + if (size == 0) continue; b = link_bucket_for(s->flags); vaddr = ALIGN_UP(cursor[b], (u64)(s->align ? s->align : 1u)); if (vaddr + size > jit->append_limit[b]) @@ -987,7 +947,7 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { "cfree_jit_append_obj: append slack exhausted"); if (nsecs == sec_cap) { u32 ncap = sec_cap ? sec_cap * 2u : 8u; - JitAppendSec *ns = (JitAppendSec *)h->realloc( + JitAppendSec* ns = (JitAppendSec*)h->realloc( h, secs, sizeof(*secs) * sec_cap, sizeof(*secs) * ncap, _Alignof(JitAppendSec)); if (!ns) @@ -1011,26 +971,24 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { cursor[b] = vaddr + size; ++nsecs; } - for (i = 0; i < SEG_NBUCKETS; ++i) - jit->append_cursor[i] = cursor[i]; + for (i = 0; i < SEG_NBUCKETS; ++i) jit->append_cursor[i] = cursor[i]; it = obj_symiter_new(ob); while (obj_symiter_next(it, &e)) { - const ObjSym *s = e.sym; + const ObjSym* s = e.sym; int is_def; - if (e.id >= m.nsym || jit_obj_sym_is_spurious_undef(s)) - continue; + if (e.id >= m.nsym || jit_obj_sym_is_spurious_undef(s)) continue; is_def = jit_obj_sym_is_def(s); if (is_def && (s->bind == SB_GLOBAL || s->bind == SB_WEAK) && s->name != 0) { LinkSymId existing = symhash_get(&img->globals, s->name); if (existing != LINK_SYM_NONE) { - LinkSymbol *prev = LinkSyms_at(&img->syms, existing - 1); + LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); if (prev && prev->defined && jit_bind_strength((u8)s->bind) == jit_bind_strength(SB_GLOBAL) && jit_bind_strength(prev->bind) == jit_bind_strength(SB_GLOBAL)) { size_t namelen; - const char *nm = pool_str(jit->c->global, s->name, &namelen); + const char* nm = pool_str(jit->c->global, s->name, &namelen); obj_format_demangle_c(jit->c, &nm, &namelen); obj_symiter_free(it); compiler_panic(jit->c, no_loc(), @@ -1087,16 +1045,15 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { /* Resolve newly appended undefs before any bytes become executable. */ for (i = 0; i < LinkSyms_count(&img->syms); ++i) { - LinkSymbol *s = LinkSyms_at(&img->syms, i); + LinkSymbol* s = LinkSyms_at(&img->syms, i); if (s->input_id != (LinkInputId)(LinkInputs_count(&jit->linker->inputs) + 1u)) continue; - if (s->defined) - continue; + if (s->defined) continue; if (s->name != 0) { LinkSymId hit = symhash_get(&img->globals, s->name); if (hit != LINK_SYM_NONE && hit != s->id) { - LinkSymbol *def = LinkSyms_at(&img->syms, hit - 1); + LinkSymbol* def = LinkSyms_at(&img->syms, hit - 1); if (def->defined) { s->section_id = def->section_id; s->value = def->value; @@ -1110,8 +1067,8 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { } if (jit->linker->resolver && s->name != 0) { size_t namelen; - const char *nm = pool_str(jit->c->global, s->name, &namelen); - void *p = jit->linker->resolver(jit->linker->resolver_user, nm); + const char* nm = pool_str(jit->c->global, s->name, &namelen); + void* p = jit->linker->resolver(jit->linker->resolver_user, nm); (void)namelen; if (p) { s->kind = SK_ABS; @@ -1128,7 +1085,7 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { } if (s->name != 0) { size_t nlen; - const char *nm = pool_str(jit->c->global, s->name, &nlen); + const char* nm = pool_str(jit->c->global, s->name, &nlen); if (nm && nlen == 15u && memcmp(nm, "__tlv_bootstrap", 15u) == 0) { s->kind = SK_ABS; s->vaddr = 0; @@ -1148,7 +1105,7 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { new_input_idx = new_input_id - 1u; { - InputMap *maps = (InputMap *)h->realloc( + InputMap* maps = (InputMap*)h->realloc( h, img->input_maps, sizeof(*img->input_maps) * img->ninput_maps, sizeof(*img->input_maps) * (new_input_idx + 1u), _Alignof(InputMap)); if (!maps) @@ -1164,23 +1121,23 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { } if (nsecs) { - LinkSection *nsections = (LinkSection *)h->realloc( + LinkSection* nsections = (LinkSection*)h->realloc( h, img->sections, sizeof(*img->sections) * old_nsections, sizeof(*img->sections) * (old_nsections + nsecs), _Alignof(LinkSection)); - LinkSegment *nsegments = (LinkSegment *)h->realloc( + LinkSegment* nsegments = (LinkSegment*)h->realloc( h, img->segments, sizeof(*img->segments) * old_nsegments, sizeof(*img->segments) * (old_nsegments + nsecs), _Alignof(LinkSegment)); - u8 **nsegbytes = (u8 **)h->realloc( + u8** nsegbytes = (u8**)h->realloc( h, img->segment_bytes, sizeof(*img->segment_bytes) * old_nsegments, - sizeof(*img->segment_bytes) * (old_nsegments + nsecs), _Alignof(u8 *)); - size_t *nsegcaps = (size_t *)h->realloc( + sizeof(*img->segment_bytes) * (old_nsegments + nsecs), _Alignof(u8*)); + size_t* nsegcaps = (size_t*)h->realloc( h, img->segment_bytes_cap, sizeof(*img->segment_bytes_cap) * old_nsegments, sizeof(*img->segment_bytes_cap) * (old_nsegments + nsecs), _Alignof(size_t)); - CfreeExecMemRegion *njsegs = (CfreeExecMemRegion *)h->realloc( + CfreeExecMemRegion* njsegs = (CfreeExecMemRegion*)h->realloc( h, jit->segs, sizeof(*jit->segs) * old_nsegs, sizeof(*jit->segs) * (old_nsegs + nsecs), _Alignof(CfreeExecMemRegion)); if (!nsections || !nsegments || !nsegbytes || !nsegcaps || !njsegs) @@ -1194,11 +1151,11 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { } for (i = 0; i < nsecs; ++i) { - JitAppendSec *ps = &secs[i]; - LinkSection *ls = &img->sections[old_nsections + i]; - LinkSegment *seg = &img->segments[old_nsegments + i]; - CfreeExecMemRegion *js = &jit->segs[old_nsegs + i]; - const Section *os = obj_section_get(ob, ps->obj_sec); + JitAppendSec* ps = &secs[i]; + LinkSection* ls = &img->sections[old_nsections + i]; + LinkSegment* seg = &img->segments[old_nsegments + i]; + CfreeExecMemRegion* js = &jit->segs[old_nsegs + i]; + const Section* os = obj_section_get(ob, ps->obj_sec); memset(ls, 0, sizeof(*ls)); ls->id = ps->link_sec; ls->input_id = new_input_id; @@ -1216,12 +1173,9 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { memset(seg, 0, sizeof(*seg)); seg->id = ps->link_seg; seg->flags = SF_ALLOC; - if (ps->bucket == SEG_RX) - seg->flags |= SF_EXEC; - if (ps->bucket == SEG_RW) - seg->flags |= SF_WRITE; - if (ps->bucket == SEG_TLS) - seg->flags |= SF_TLS; + if (ps->bucket == SEG_RX) seg->flags |= SF_EXEC; + if (ps->bucket == SEG_RW) seg->flags |= SF_WRITE; + if (ps->bucket == SEG_TLS) seg->flags |= SF_TLS; seg->file_offset = ps->vaddr; seg->vaddr = ps->vaddr; seg->mem_size = ps->size; @@ -1233,14 +1187,14 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { memset(js, 0, sizeof(*js)); js->write = - (u8 *)jit->master.write + (uintptr_t)(ps->vaddr - jit->image_base); + (u8*)jit->master.write + (uintptr_t)(ps->vaddr - jit->image_base); js->runtime = - (u8 *)jit->master.runtime + (uintptr_t)(ps->vaddr - jit->image_base); + (u8*)jit->master.runtime + (uintptr_t)(ps->vaddr - jit->image_base); js->size = (size_t)ps->size; js->token = NULL; if (os && os->sem != SSEM_NOBITS && os->bytes.total) { - buf_flatten(&os->bytes, (u8 *)js->write); + buf_flatten(&os->bytes, (u8*)js->write); } img->nsections++; img->nsegments++; @@ -1250,15 +1204,14 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { { u32 total = obj_reloc_total(ob); for (i = 0; i < total; ++i) { - const Reloc *r = obj_reloc_at(ob, i); + const Reloc* r = obj_reloc_at(ob, i); LinkRelocApply rec; LinkSectionId ls_id; - const LinkSection *ls; + const LinkSection* ls; if (!r || r->section_id == OBJ_SEC_NONE || r->section_id >= m.nsection) continue; ls_id = m.section[r->section_id]; - if (ls_id == LINK_SEC_NONE) - continue; + if (ls_id == LINK_SEC_NONE) continue; if (r->sym == OBJ_SYM_NONE || r->sym >= m.nsym || m.sym[r->sym] == LINK_SYM_NONE) continue; @@ -1279,16 +1232,16 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { } for (i = old_nrelocs; i < LinkRelocs_count(&img->relocs); ++i) { - const LinkRelocApply *r = LinkRelocs_at(&img->relocs, i); + const LinkRelocApply* r = LinkRelocs_at(&img->relocs, i); jit_apply_one_reloc(jit, r); } for (i = old_nsegs; i < jit->nsegs; ++i) { - const LinkSegment *seg = &img->segments[i]; + const LinkSegment* seg = &img->segments[i]; u64 page_lo = seg->vaddr & ~(page - 1u); u64 page_hi = ALIGN_UP(seg->vaddr + seg->mem_size, page); - void *rt = - (u8 *)jit->master.runtime + (uintptr_t)(page_lo - jit->image_base); + void* rt = + (u8*)jit->master.runtime + (uintptr_t)(page_lo - jit->image_base); if (mem->protect(mem->user, rt, (size_t)(page_hi - page_lo), perms_for(seg->flags)) != 0) { compiler_panic(jit->c, no_loc(), @@ -1297,17 +1250,17 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { } if (mem->flush_icache) { for (i = old_nsegs; i < jit->nsegs; ++i) { - const LinkSegment *seg = &img->segments[i]; + const LinkSegment* seg = &img->segments[i]; if (seg->flags & SF_EXEC) mem->flush_icache(mem->user, jit->segs[i].runtime, jit->segs[i].size); } } { - ObjBuilder **nd = (ObjBuilder **)h->realloc( + ObjBuilder** nd = (ObjBuilder**)h->realloc( h, img->dbg_objs, sizeof(*img->dbg_objs) * old_dbg_n, - sizeof(*img->dbg_objs) * (new_input_idx + 1u), _Alignof(ObjBuilder *)); - u8 *no = (u8 *)h->realloc( + sizeof(*img->dbg_objs) * (new_input_idx + 1u), _Alignof(ObjBuilder*)); + u8* no = (u8*)h->realloc( h, img->dbg_objs_owned, sizeof(*img->dbg_objs_owned) * old_dbg_n, sizeof(*img->dbg_objs_owned) * (new_input_idx + 1u), 1u); if (!nd || !no) @@ -1327,17 +1280,24 @@ static void jit_append_obj_inner(CfreeJit *jit, ObjBuilder *ob) { jit_invalidate_view(jit); jit->generation++; - if (secs) - h->free(h, secs, sizeof(*secs) * sec_cap); + if (secs) h->free(h, secs, sizeof(*secs) * sec_cap); (void)old_cursor; (void)old_nmaps; } -CfreeStatus cfree_jit_append_obj(CfreeJit *jit, CfreeObjBuilder *ob) { +CfreeStatus cfree_jit_publish(CfreeJit* jit, const CfreeJitPublishOptions* opts, + CfreeJitPublishResult* result) { PanicSave saved; - Compiler *c; - if (!jit || !ob) - return CFREE_INVALID; + Compiler* c; + CfreeLinkSession* link; + u32 i; + + if (result) memset(result, 0, sizeof(*result)); + if (!jit || !opts || !opts->link) return CFREE_INVALID; + if ((CfreeJitPublishKind)opts->kind != CFREE_JIT_PUBLISH_APPEND_OBJECTS) + return CFREE_UNSUPPORTED; + link = opts->link; + if (link->non_obj_inputs) return CFREE_UNSUPPORTED; c = jit->c; compiler_panic_save(c, &saved); if (setjmp(c->panic)) { @@ -1345,8 +1305,10 @@ CfreeStatus cfree_jit_append_obj(CfreeJit *jit, CfreeObjBuilder *ob) { compiler_panic_restore(c, &saved); return CFREE_ERR; } - jit_append_obj_inner(jit, ob); + for (i = 0; i < link->npublish_objs; ++i) + jit_append_obj_inner(jit, link->publish_objs[i]); compiler_panic_restore(c, &saved); + if (result) result->generation = jit->generation; return CFREE_OK; } @@ -1354,9 +1316,8 @@ CfreeStatus cfree_jit_append_obj(CfreeJit *jit, CfreeObjBuilder *ob) { /* True if `name` (NUL-terminated) is a debug section the DWARF consumer * (src/debug/dwarf_open.c) might read. Everything else is skipped. */ -static int jit_view_is_debug_name(const char *name) { - if (!name) - return 0; +static int jit_view_is_debug_name(const char* name) { + if (!name) return 0; if (name[0] == '.' && name[1] == 'd' && name[2] == 'e' && name[3] == 'b' && name[4] == 'u' && name[5] == 'g' && name[6] == '_') return 1; /* .debug_* */ @@ -1374,25 +1335,21 @@ static int jit_view_is_debug_name(const char *name) { * Cheap walk over the input's section table. Sym values are pool-local, * so name strings must be dereferenced through the input's *own* * compiler pool — not the jit's pool. */ -static int jit_view_input_has_debug(CfreeJit *jit, u32 ii) { - ObjBuilder *ob; - Pool *in_pool; +static int jit_view_input_has_debug(CfreeJit* jit, u32 ii) { + ObjBuilder* ob; + Pool* in_pool; u32 nsec, k; - if (ii >= jit->image->dbg_objs_n) - return 0; + if (ii >= jit->image->dbg_objs_n) return 0; ob = jit->image->dbg_objs[ii]; - if (!ob) - return 0; + if (!ob) return 0; in_pool = obj_compiler(ob)->global; nsec = obj_section_count(ob); for (k = 0; k < nsec; ++k) { - const Section *s = obj_section_get(ob, (ObjSecId)(k + 1)); - const char *nm; - if (!s || !s->name) - continue; + const Section* s = obj_section_get(ob, (ObjSecId)(k + 1)); + const char* nm; + if (!s || !s->name) continue; nm = pool_str(in_pool, s->name, NULL); - if (jit_view_is_debug_name(nm)) - return 1; + if (jit_view_is_debug_name(nm)) return 1; } return 0; } @@ -1402,23 +1359,18 @@ static int jit_view_input_has_debug(CfreeJit *jit, u32 ii) { * image's LinkSyms table. Returns 0 if the symbol is undefined or the * mapping is missing — debug relocations against unresolved symbols * collapse to zero, which is the DWARF "absent" convention. */ -static u64 jit_view_sym_vaddr(CfreeJit *jit, u32 ii, ObjSymId obj_sym) { - const InputMap *m; +static u64 jit_view_sym_vaddr(CfreeJit* jit, u32 ii, ObjSymId obj_sym) { + const InputMap* m; LinkSymId lid; - const LinkSymbol *s; - if (obj_sym == OBJ_SYM_NONE) - return 0; - if (ii >= jit->image->ninput_maps) - return 0; + const LinkSymbol* s; + if (obj_sym == OBJ_SYM_NONE) return 0; + if (ii >= jit->image->ninput_maps) return 0; m = &jit->image->input_maps[ii]; - if (!m->sym || obj_sym >= m->nsym) - return 0; + if (!m->sym || obj_sym >= m->nsym) return 0; lid = m->sym[obj_sym]; - if (lid == LINK_SYM_NONE || lid > LinkSyms_count(&jit->image->syms)) - return 0; + if (lid == LINK_SYM_NONE || lid > LinkSyms_count(&jit->image->syms)) return 0; s = LinkSyms_at(&jit->image->syms, lid - 1); - if (!s || !s->defined) - return 0; + if (!s || !s->defined) return 0; return s->vaddr; /* image-relative — what DWARF was emitted in */ } @@ -1436,36 +1388,33 @@ typedef struct ViewSec { } ViewSec; /* Find-or-create a ViewSec entry by debug-section name. */ -static ViewSec *view_sec_for(CfreeJit *jit, ViewSec *tab, u32 *ntab, - u32 *cap_inout, const char *name, u16 flags, - u32 align, u32 entsize, ObjBuilder *view_ob, - ViewSec **tab_out) { - Heap *h = (Heap *)jit->c->ctx->heap; - Pool *view_pool = obj_compiler(view_ob)->global; +static ViewSec* view_sec_for(CfreeJit* jit, ViewSec* tab, u32* ntab, + u32* cap_inout, const char* name, u16 flags, + u32 align, u32 entsize, ObjBuilder* view_ob, + ViewSec** tab_out) { + Heap* h = (Heap*)jit->c->ctx->heap; + Pool* view_pool = obj_compiler(view_ob)->global; Sym vn = pool_intern_cstr(view_pool, name); u32 i; for (i = 0; i < *ntab; ++i) { if (tab[i].view_name == vn) { - if (tab_out) - *tab_out = tab; + if (tab_out) *tab_out = tab; return &tab[i]; } } if (*ntab == *cap_inout) { u32 ncap = *cap_inout ? *cap_inout * 2u : 4u; - ViewSec *na = (ViewSec *)h->realloc(h, tab, *cap_inout * sizeof(*tab), - ncap * sizeof(*tab), _Alignof(ViewSec)); - if (!na) - return NULL; + ViewSec* na = (ViewSec*)h->realloc(h, tab, *cap_inout * sizeof(*tab), + ncap * sizeof(*tab), _Alignof(ViewSec)); + if (!na) return NULL; tab = na; *cap_inout = ncap; - if (tab_out) - *tab_out = tab; + if (tab_out) *tab_out = tab; } else if (tab_out) { *tab_out = tab; } { - ViewSec *slot = &tab[(*ntab)++]; + ViewSec* slot = &tab[(*ntab)++]; slot->view_name = vn; slot->view_id = obj_section_ex(view_ob, vn, SEC_DEBUG, SSEM_PROGBITS, flags, align ? align : 1u, entsize, 0, 0); @@ -1476,11 +1425,10 @@ static ViewSec *view_sec_for(CfreeJit *jit, ViewSec *tab, u32 *ntab, } /* Find a ViewSec by view-pool name (no creation). Returns NULL on miss. */ -static ViewSec *view_sec_find(ViewSec *tab, u32 ntab, Sym view_name) { +static ViewSec* view_sec_find(ViewSec* tab, u32 ntab, Sym view_name) { u32 i; for (i = 0; i < ntab; ++i) - if (tab[i].view_name == view_name) - return &tab[i]; + if (tab[i].view_name == view_name) return &tab[i]; return NULL; } @@ -1492,57 +1440,52 @@ static ViewSec *view_sec_find(ViewSec *tab, u32 ntab, Sym view_name) { * `tab` is the find-or-create table of view sections, keyed by name; * snapshots taken at the start of this input are read from it via * view_sec_find. */ -static void jit_view_copy_debug_section(CfreeJit *jit, u32 ii, - ObjSecId in_sec_id, ObjBuilder *view_ob, - ViewSec *tab, u32 ntab, - ViewSec *out_vs) { - ObjBuilder *in_ob = jit->image->dbg_objs[ii]; - const Section *in_sec = obj_section_get(in_ob, in_sec_id); - Pool *in_pool; - Pool *view_pool = obj_compiler(view_ob)->global; - Heap *h; +static void jit_view_copy_debug_section(CfreeJit* jit, u32 ii, + ObjSecId in_sec_id, ObjBuilder* view_ob, + ViewSec* tab, u32 ntab, + ViewSec* out_vs) { + ObjBuilder* in_ob = jit->image->dbg_objs[ii]; + const Section* in_sec = obj_section_get(in_ob, in_sec_id); + Pool* in_pool; + Pool* view_pool = obj_compiler(view_ob)->global; + Heap* h; u32 nbytes, k, total_relocs; - u8 *bytes; - if (!in_sec) - return; + u8* bytes; + if (!in_sec) return; nbytes = in_sec->bytes.total; - if (nbytes == 0) - return; + if (nbytes == 0) return; in_pool = obj_compiler(in_ob)->global; - h = (Heap *)jit->c->ctx->heap; + h = (Heap*)jit->c->ctx->heap; (void)in_pool; - bytes = (u8 *)h->alloc(h, nbytes, 1); - if (!bytes) - return; + bytes = (u8*)h->alloc(h, nbytes, 1); + if (!bytes) return; buf_flatten(&in_sec->bytes, bytes); /* Apply this section's relocations in place. obj_reloc_at returns * all relocations across the input; filter by section_id. */ total_relocs = obj_reloc_total(in_ob); for (k = 0; k < total_relocs; ++k) { - const Reloc *r = obj_reloc_at(in_ob, k); + const Reloc* r = obj_reloc_at(in_ob, k); u64 S = 0; int handled = 0; - if (!r || r->section_id != in_sec_id) - continue; - if (r->offset >= nbytes) - continue; /* malformed; skip */ + if (!r || r->section_id != in_sec_id) continue; + if (r->offset >= nbytes) continue; /* malformed; skip */ /* SK_SECTION target → resolve against the per-input snapshot of the * matching view section's prefix size. This is what makes the * concatenated multi-input view's cross-section offsets land in * the right slot. */ if (r->sym != OBJ_SYM_NONE) { - const ObjSym *ts = obj_symbol_get(in_ob, r->sym); + const ObjSym* ts = obj_symbol_get(in_ob, r->sym); if (ts && ts->kind == SK_SECTION && ts->section_id != OBJ_SEC_NONE) { - const Section *tsec = obj_section_get(in_ob, ts->section_id); + const Section* tsec = obj_section_get(in_ob, ts->section_id); if (tsec && tsec->kind == SEC_DEBUG && tsec->name) { size_t tnlen = 0; - const char *tnm = + const char* tnm = pool_str(obj_compiler(in_ob)->global, tsec->name, &tnlen); if (tnm) { Sym v_tn = pool_intern(view_pool, tnm, tnlen); - ViewSec *tgt = view_sec_find(tab, ntab, v_tn); + ViewSec* tgt = view_sec_find(tab, ntab, v_tn); if (tgt) { S = (u64)tgt->snap; handled = 1; @@ -1551,8 +1494,7 @@ static void jit_view_copy_debug_section(CfreeJit *jit, u32 ii, } } } - if (!handled) - S = jit_view_sym_vaddr(jit, ii, r->sym); + if (!handled) S = jit_view_sym_vaddr(jit, ii, r->sym); /* P is unused by ABS kinds; PC-relative debug-section relocs are * not produced by cfree's debug emitter, but if some external .o * carried one against a debug section, P=0 would give a @@ -1572,100 +1514,86 @@ static void jit_view_copy_debug_section(CfreeJit *jit, u32 ii, * sections. SK_SECTION relocations are resolved against the view-side * prefix length snapshotted at the start of each input, so the merged * CU2/CU3/... cross-section offsets land in the right slot. */ -static CfreeObjFile *jit_view_build(CfreeJit *jit) { - CfreeObjFile *view; - ObjBuilder *view_ob; - ViewSec *tab = NULL; +static CfreeObjFile* jit_view_build(CfreeJit* jit) { + CfreeObjFile* view; + ObjBuilder* view_ob; + ViewSec* tab = NULL; u32 ntab = 0, cap = 0; - Heap *h; + Heap* h; u32 ii, k; int any = 0; - if (!jit->image || jit->image->dbg_objs_n == 0) - return NULL; + if (!jit->image || jit->image->dbg_objs_n == 0) return NULL; for (ii = 0; ii < jit->image->dbg_objs_n; ++ii) { if (jit_view_input_has_debug(jit, ii)) { any = 1; break; } } - if (!any) - return NULL; + if (!any) return NULL; view = cfree_objfile_internal_new(jit->c->ctx, jit->c->target, jit->c->target.obj); - if (!view) - return NULL; + if (!view) return NULL; view_ob = cfree_objfile_builder(view); if (!view_ob) { cfree_objfile_internal_free(view); return NULL; } - h = (Heap *)jit->c->ctx->heap; + h = (Heap*)jit->c->ctx->heap; for (ii = 0; ii < jit->image->dbg_objs_n; ++ii) { - ObjBuilder *in_ob; + ObjBuilder* in_ob; u32 nsec; - if (!jit_view_input_has_debug(jit, ii)) - continue; + if (!jit_view_input_has_debug(jit, ii)) continue; in_ob = jit->image->dbg_objs[ii]; /* Phase A: find-or-create every debug section this input contributes * to, and snapshot cur_size as the per-input prefix. */ nsec = obj_section_count(in_ob); for (k = 0; k < nsec; ++k) { - const Section *s = obj_section_get(in_ob, (ObjSecId)(k + 1)); - const char *nm; + const Section* s = obj_section_get(in_ob, (ObjSecId)(k + 1)); + const char* nm; size_t nlen = 0; - ViewSec *vs; - if (!s || !s->name) - continue; + ViewSec* vs; + if (!s || !s->name) continue; nm = pool_str(obj_compiler(in_ob)->global, s->name, &nlen); - if (!nm || !jit_view_is_debug_name(nm)) - continue; + if (!nm || !jit_view_is_debug_name(nm)) continue; vs = view_sec_for(jit, tab, &ntab, &cap, nm, s->flags, s->align ? s->align : 1u, s->entsize, view_ob, &tab); - if (!vs) - continue; + if (!vs) continue; } - for (k = 0; k < ntab; ++k) - tab[k].snap = tab[k].cur_size; + for (k = 0; k < ntab; ++k) tab[k].snap = tab[k].cur_size; /* Phase B: copy each debug section + apply relocs. cur_size grows * as bytes get appended; SK_SECTION resolution always reads `snap` * (the start-of-input snapshot), so intra-input references inside * any debug section still land in this input's slice. */ for (k = 0; k < nsec; ++k) { - const Section *s = obj_section_get(in_ob, (ObjSecId)(k + 1)); - const char *nm; + const Section* s = obj_section_get(in_ob, (ObjSecId)(k + 1)); + const char* nm; size_t nlen = 0; Sym v_nm; - ViewSec *vs; - if (!s || !s->name) - continue; + ViewSec* vs; + if (!s || !s->name) continue; nm = pool_str(obj_compiler(in_ob)->global, s->name, &nlen); - if (!nm || !jit_view_is_debug_name(nm)) - continue; + if (!nm || !jit_view_is_debug_name(nm)) continue; v_nm = pool_intern(obj_compiler(view_ob)->global, nm, nlen); vs = view_sec_find(tab, ntab, v_nm); - if (!vs) - continue; + if (!vs) continue; jit_view_copy_debug_section(jit, ii, (ObjSecId)(k + 1), view_ob, tab, ntab, vs); } } - if (tab) - h->free(h, tab, sizeof(*tab) * cap); + if (tab) h->free(h, tab, sizeof(*tab) * cap); obj_finalize(view_ob); return view; } -const CfreeObjFile *cfree_jit_view(CfreeJit *jit) { - if (!jit) - return NULL; - if (jit->view_built) - return jit->view; +const CfreeObjFile* cfree_jit_view(CfreeJit* jit) { + if (!jit) return NULL; + if (jit->view_built) return jit->view; jit->view = jit_view_build(jit); jit->view_built = 1u; return jit->view; @@ -1682,45 +1610,37 @@ static int jit_sym_kind_visible(u8 k) { /* Resolve a LinkSymbol's interned name to a stable C string, stripping * the target format's C-mangling prefix (Mach-O's leading `_`) so the * user sees the source-level name. */ -static const char *jit_sym_name_cstr(CfreeJit *jit, const LinkSymbol *s) { +static const char* jit_sym_name_cstr(CfreeJit* jit, const LinkSymbol* s) { size_t len = 0; - const char *nm = pool_str(jit->c->global, s->name, &len); - if (!nm) - return NULL; + const char* nm = pool_str(jit->c->global, s->name, &len); + if (!nm) return NULL; obj_format_demangle_c(jit->c, &nm, &len); return nm; } -static uint64_t jit_sym_runtime_addr(CfreeJit *jit, const LinkSymbol *s) { - if (s->kind == SK_ABS) - return s->vaddr; +static uint64_t jit_sym_runtime_addr(CfreeJit* jit, const LinkSymbol* s) { + if (s->kind == SK_ABS) return s->vaddr; return (uint64_t)vaddr_to_runtime(jit->image, jit->segs, s->vaddr); } -CfreeStatus cfree_jit_addr_to_sym(CfreeJit *jit, uint64_t addr, - const char **name_out, uint64_t *off_out) { +CfreeStatus cfree_jit_addr_to_sym(CfreeJit* jit, uint64_t addr, + const char** name_out, uint64_t* off_out) { u32 n; u32 i; - const LinkSymbol *best = NULL; + const LinkSymbol* best = NULL; uint64_t best_base = 0; uint64_t best_off = (uint64_t)-1; - if (name_out) - *name_out = NULL; - if (off_out) - *off_out = 0; - if (!jit) - return CFREE_INVALID; + if (name_out) *name_out = NULL; + if (off_out) *off_out = 0; + if (!jit) return CFREE_INVALID; n = LinkSyms_count(&jit->image->syms); for (i = 0; i < n; ++i) { - LinkSymbol *s = LinkSyms_at(&jit->image->syms, i); + LinkSymbol* s = LinkSyms_at(&jit->image->syms, i); uint64_t base; - if (!s || !s->defined) - continue; - if (!jit_sym_kind_visible(s->kind)) - continue; + if (!s || !s->defined) continue; + if (!jit_sym_kind_visible(s->kind)) continue; base = jit_sym_runtime_addr(jit, s); - if (!base) - continue; + if (!base) continue; if (addr >= base && (s->size == 0 || addr < base + s->size)) { uint64_t off = addr - base; if (off < best_off || @@ -1732,50 +1652,41 @@ CfreeStatus cfree_jit_addr_to_sym(CfreeJit *jit, uint64_t addr, } } if (best) { - if (name_out) - *name_out = jit_sym_name_cstr(jit, best); - if (off_out) - *off_out = addr - best_base; + if (name_out) *name_out = jit_sym_name_cstr(jit, best); + if (off_out) *off_out = addr - best_base; return CFREE_OK; } return CFREE_NOT_FOUND; } struct CfreeJitSymIter { - CfreeJit *jit; + CfreeJit* jit; u32 next; }; -CfreeStatus cfree_jit_sym_iter_new(CfreeJit *jit, CfreeJitSymIter **out) { - Heap *h; - CfreeJitSymIter *it; - if (!out) - return CFREE_INVALID; +CfreeStatus cfree_jit_sym_iter_new(CfreeJit* jit, CfreeJitSymIter** out) { + Heap* h; + CfreeJitSymIter* it; + if (!out) return CFREE_INVALID; *out = NULL; - if (!jit) - return CFREE_INVALID; - h = (Heap *)jit->c->ctx->heap; - it = (CfreeJitSymIter *)h->alloc(h, sizeof(*it), _Alignof(CfreeJitSymIter)); - if (!it) - return CFREE_NOMEM; + if (!jit) return CFREE_INVALID; + h = (Heap*)jit->c->ctx->heap; + it = (CfreeJitSymIter*)h->alloc(h, sizeof(*it), _Alignof(CfreeJitSymIter)); + if (!it) return CFREE_NOMEM; it->jit = jit; it->next = 0; *out = it; return CFREE_OK; } -CfreeIterResult cfree_jit_sym_iter_next(CfreeJitSymIter *it, - CfreeJitSym *out) { +CfreeIterResult cfree_jit_sym_iter_next(CfreeJitSymIter* it, CfreeJitSym* out) { u32 n; - if (!it || !out) - return CFREE_ITER_ERROR; + if (!it || !out) return CFREE_ITER_ERROR; n = LinkSyms_count(&it->jit->image->syms); while (it->next < n) { - LinkSymbol *s = LinkSyms_at(&it->jit->image->syms, it->next++); - if (!s || !s->defined) - continue; - if (!jit_sym_kind_visible(s->kind)) - continue; + LinkSymbol* s = LinkSyms_at(&it->jit->image->syms, it->next++); + if (!s || !s->defined) continue; + if (!jit_sym_kind_visible(s->kind)) continue; out->name = jit_sym_name_cstr(it->jit, s); out->addr = jit_sym_runtime_addr(it->jit, s); out->size = s->size; @@ -1785,11 +1696,10 @@ CfreeIterResult cfree_jit_sym_iter_next(CfreeJitSymIter *it, return CFREE_ITER_END; } -void cfree_jit_sym_iter_free(CfreeJitSymIter *it) { - Heap *h; - if (!it) - return; - h = (Heap *)it->jit->c->ctx->heap; +void cfree_jit_sym_iter_free(CfreeJitSymIter* it) { + Heap* h; + if (!it) return; + h = (Heap*)it->jit->c->ctx->heap; h->free(h, it, sizeof(*it)); } @@ -1800,17 +1710,15 @@ void cfree_jit_sym_iter_free(CfreeJitSymIter *it) { * reject breakpoint and read/write requests pointing outside the code * region) and a way to read the image's target arch. These accessors give * it just that, without exporting the segment table or the LinkImage. */ -int cfree_jit_image_contains(CfreeJit *jit, uint64_t runtime_addr) { +int cfree_jit_image_contains(CfreeJit* jit, uint64_t runtime_addr) { u32 i; uintptr_t a; - if (!jit || !jit->segs) - return 0; + if (!jit || !jit->segs) return 0; a = (uintptr_t)runtime_addr; for (i = 0; i < jit->nsegs; ++i) { uintptr_t lo = (uintptr_t)jit->segs[i].runtime; uintptr_t hi = lo + (uintptr_t)jit->segs[i].size; - if (a >= lo && a < hi) - return 1; + if (a >= lo && a < hi) return 1; } return 0; } @@ -1820,17 +1728,16 @@ int cfree_jit_image_contains(CfreeJit *jit, uint64_t runtime_addr) { * driver can cross the boundary at every DWARF call. Walks the * segment table (at most a handful of entries) so callers can do this * per stop without measurable cost. */ -uint64_t cfree_jit_runtime_to_image(CfreeJit *jit, uint64_t runtime_pc) { +uint64_t cfree_jit_runtime_to_image(CfreeJit* jit, uint64_t runtime_pc) { u32 i; uintptr_t a; - if (!jit || !jit->segs) - return 0; + if (!jit || !jit->segs) return 0; a = (uintptr_t)runtime_pc; for (i = 0; i < jit->nsegs; ++i) { uintptr_t lo = (uintptr_t)jit->segs[i].runtime; uintptr_t hi = lo + (uintptr_t)jit->segs[i].size; if (a >= lo && a < hi) { - const LinkSegment *s = &jit->image->segments[i]; + const LinkSegment* s = &jit->image->segments[i]; return s->vaddr + (uint64_t)(a - lo); } } @@ -1840,42 +1747,39 @@ uint64_t cfree_jit_runtime_to_image(CfreeJit *jit, uint64_t runtime_pc) { uintptr_t hi = (uintptr_t)jit->segs[i].runtime + (uintptr_t)jit->segs[i].size; if (a == hi) { - const LinkSegment *s = &jit->image->segments[i]; + const LinkSegment* s = &jit->image->segments[i]; return s->vaddr + s->mem_size; } } return 0; } -uint64_t cfree_jit_image_to_runtime(CfreeJit *jit, uint64_t image_vaddr) { +uint64_t cfree_jit_image_to_runtime(CfreeJit* jit, uint64_t image_vaddr) { uintptr_t rt; - if (!jit || !jit->segs) - return 0; + if (!jit || !jit->segs) return 0; rt = vaddr_to_runtime(jit->image, jit->segs, image_vaddr); return (uint64_t)rt; } -CfreeArchKind cfree_jit_image_arch(CfreeJit *jit) { +CfreeArchKind cfree_jit_image_arch(CfreeJit* jit) { return jit->c->target.arch; } -Compiler *cfree_jit_compiler(CfreeJit *jit) { return jit->c; } +Compiler* cfree_jit_compiler(CfreeJit* jit) { return jit->c; } -void cfree_jit_run_dtors(CfreeJit *jit) { +void cfree_jit_run_dtors(CfreeJit* jit) { typedef void (*VoidFn)(void); - void *p_start; - void *p_end; - if (!jit) - return; + void* p_start; + void* p_end; + if (!jit) return; p_start = cfree_jit_lookup(jit, "__fini_array_start"); p_end = cfree_jit_lookup(jit, "__fini_array_end"); if (p_start && p_end) { - VoidFn *begin = (VoidFn *)p_start; - VoidFn *fn = (VoidFn *)p_end; + VoidFn* begin = (VoidFn*)p_start; + VoidFn* fn = (VoidFn*)p_end; while (fn != begin) { --fn; - if (*fn) - (*fn)(); + if (*fn) (*fn)(); } } } diff --git a/test/api/cg_switch_test.c b/test/api/cg_switch_test.c @@ -116,7 +116,8 @@ static void build_switch_fn(CfreeCompiler* c, CfreeCgTypeId i32_ty, EXPECT(ob != NULL, "[%s/O%d] obj_new failed", sh->name, opt_level); if (!ob) return; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "[%s/O%d] cg_new failed", sh->name, opt_level); if (!cg) { obj_free((ObjBuilder*)ob); @@ -140,8 +141,7 @@ static void build_switch_fn(CfreeCompiler* c, CfreeCgTypeId i32_ty, decl.sym.bind = CFREE_SB_GLOBAL; decl.sym.visibility = CFREE_CG_VIS_DEFAULT; sym = cfree_cg_decl(cg, decl); - EXPECT(sym != CFREE_CG_SYM_NONE, "[%s/O%d] decl failed", sh->name, - opt_level); + EXPECT(sym != CFREE_CG_SYM_NONE, "[%s/O%d] decl failed", sh->name, opt_level); cfree_cg_func_begin(cg, sym); @@ -166,9 +166,9 @@ static void build_switch_fn(CfreeCompiler* c, CfreeCgTypeId i32_ty, /* Push selector, dispatch. */ cfree_cg_push_local(cg, param); - cfree_cg_load(cg, (CfreeCgMemAccess){.type = sh->selector_type, - .align = cfree_cg_type_align( - c, sh->selector_type)}); + cfree_cg_load(cg, (CfreeCgMemAccess){ + .type = sh->selector_type, + .align = cfree_cg_type_align(c, sh->selector_type)}); memset(&sw, 0, sizeof sw); sw.selector_type = sh->selector_type; sw.default_label = default_lbl; diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c @@ -1,5 +1,7 @@ #include <cfree/cg.h> +#include <cfree/compile.h> #include <cfree/core.h> +#include <cfree/object.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -59,8 +61,8 @@ static int g_fail; } \ } while (0) -static int expect_panic_contains(CfreeCompiler* c, void (*fn)(void*), - void* arg, const char* expected) { +static int expect_panic_contains(CfreeCompiler* c, void (*fn)(void*), void* arg, + const char* expected) { PanicSave saved; int panicked = 0; g_last_diag[0] = '\0'; @@ -97,7 +99,8 @@ static void exercise_cg_handles(CfreeCompiler* c, CfreeCgTypeId i32_ty, EXPECT(ob != NULL, "obj builder allocation failed"); if (!ob) return; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -175,7 +178,8 @@ static void exercise_cg_scalar_local(CfreeCompiler* c, CfreeCgTypeId i32_ty, EXPECT(ob != NULL, "obj builder allocation failed"); if (!ob) return; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -240,7 +244,8 @@ static void exercise_cg_late_local_addr(CfreeCompiler* c, CfreeCgTypeId i32_ty, EXPECT(ob != NULL, "obj builder allocation failed"); if (!ob) return; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -313,7 +318,8 @@ static void exercise_cg_data_entsize(CfreeCompiler* c, CfreeCgTypeId i8_ty) { EXPECT(ob != NULL, "entsize obj builder allocation failed"); if (!ob) return; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "entsize cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -348,12 +354,10 @@ static void exercise_cg_data_entsize(CfreeCompiler* c, CfreeCgTypeId i8_ty) { for (uint32_t i = 0; i < obj_section_count((ObjBuilder*)ob); ++i) { const Section* sec = obj_section_get((ObjBuilder*)ob, i); if (!sec) continue; - if ((sec->flags & (SF_MERGE | SF_STRINGS)) == - (SF_MERGE | SF_STRINGS)) { + if ((sec->flags & (SF_MERGE | SF_STRINGS)) == (SF_MERGE | SF_STRINGS)) { found = 1; EXPECT(sec->entsize == 1, - "merge string section entsize should be 1, got %u", - sec->entsize); + "merge string section entsize should be 1, got %u", sec->entsize); } } EXPECT(found, "expected merge string data section"); @@ -397,7 +401,8 @@ static void exercise_cg_literal_folds(CfreeCompiler* c, CfreeCgTypeId i32_ty) { EXPECT(ob != NULL, "literal fold obj builder allocation failed"); if (!ob) return; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "literal fold cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -409,32 +414,32 @@ static void exercise_cg_literal_folds(CfreeCompiler* c, CfreeCgTypeId i32_ty) { EXPECT(sym != CFREE_CG_SYM_NONE, "literal fold decl failed"); cfree_cg_func_begin(cg, sym); switch (i) { - case 0: - cfree_cg_push_int(cg, 40, i32_ty); - cfree_cg_push_int(cg, 2, i32_ty); - cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - break; - case 1: - cfree_cg_push_int(cg, 5, i32_ty); - cfree_cg_push_int(cg, 3, i32_ty); - cfree_cg_int_binop(cg, CFREE_CG_INT_SHL, 0); - cfree_cg_push_int(cg, 2, i32_ty); - cfree_cg_int_binop(cg, CFREE_CG_INT_OR, 0); - break; - case 2: - cfree_cg_push_int(cg, 40, i32_ty); - cfree_cg_push_int(cg, 2, i32_ty); - cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_push_int(cg, 42, i32_ty); - cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); - break; - case 3: - cfree_cg_push_int(cg, 41, i32_ty); - cfree_cg_int_unop(cg, CFREE_CG_INT_BNOT, 0); - cfree_cg_int_unop(cg, CFREE_CG_INT_BNOT, 0); - cfree_cg_push_int(cg, 1, i32_ty); - cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - break; + case 0: + cfree_cg_push_int(cg, 40, i32_ty); + cfree_cg_push_int(cg, 2, i32_ty); + cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); + break; + case 1: + cfree_cg_push_int(cg, 5, i32_ty); + cfree_cg_push_int(cg, 3, i32_ty); + cfree_cg_int_binop(cg, CFREE_CG_INT_SHL, 0); + cfree_cg_push_int(cg, 2, i32_ty); + cfree_cg_int_binop(cg, CFREE_CG_INT_OR, 0); + break; + case 2: + cfree_cg_push_int(cg, 40, i32_ty); + cfree_cg_push_int(cg, 2, i32_ty); + cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); + cfree_cg_push_int(cg, 42, i32_ty); + cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); + break; + case 3: + cfree_cg_push_int(cg, 41, i32_ty); + cfree_cg_int_unop(cg, CFREE_CG_INT_BNOT, 0); + cfree_cg_int_unop(cg, CFREE_CG_INT_BNOT, 0); + cfree_cg_push_int(cg, 1, i32_ty); + cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); + break; } cfree_cg_ret(cg); cfree_cg_func_end(cg); @@ -467,7 +472,8 @@ static uint32_t cg_emit_delayed_chain(CfreeCompiler* c, CfreeCgTypeId i32_ty, EXPECT(ob != NULL, "delayed chain obj builder allocation failed"); if (!ob) return 0; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "delayed chain cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -535,7 +541,8 @@ static uint32_t cg_emit_unary_chain(CfreeCompiler* c, CfreeCgTypeId i32_ty, EXPECT(ob != NULL, "unary chain obj builder allocation failed"); if (!ob) return 0; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "unary chain cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -600,7 +607,8 @@ static uint32_t cg_emit_local_shadow(CfreeCompiler* c, CfreeCgTypeId i32_ty, EXPECT(ob != NULL, "local shadow obj builder allocation failed"); if (!ob) return 0; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "local shadow cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -665,7 +673,8 @@ static uint32_t cg_emit_delayed_cmp(CfreeCompiler* c, CfreeCgTypeId i32_ty, EXPECT(ob != NULL, "delayed cmp obj builder allocation failed"); if (!ob) return 0; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "delayed cmp cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -736,7 +745,8 @@ static uint32_t cg_emit_delayed_store(CfreeCompiler* c, CfreeCgTypeId i32_ty, EXPECT(ob != NULL, "delayed store obj builder allocation failed"); if (!ob) return 0; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "delayed store cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -791,8 +801,7 @@ static uint32_t cg_emit_delayed_store(CfreeCompiler* c, CfreeCgTypeId i32_ty, return size; } -static uint32_t cg_emit_delayed_pressure(CfreeCompiler* c, - CfreeCgTypeId i32_ty, +static uint32_t cg_emit_delayed_pressure(CfreeCompiler* c, CfreeCgTypeId i32_ty, const char* name) { enum { NPARAMS = 13 }; CfreeCodeOptions opts; @@ -813,7 +822,8 @@ static uint32_t cg_emit_delayed_pressure(CfreeCompiler* c, EXPECT(ob != NULL, "delayed pressure obj builder allocation failed"); if (!ob) return 0; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "delayed pressure cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -821,8 +831,7 @@ static uint32_t cg_emit_delayed_pressure(CfreeCompiler* c, } memset(param_desc, 0, sizeof param_desc); - for (uint32_t i = 0; i < NPARAMS; ++i) - param_desc[i].type = i32_ty; + for (uint32_t i = 0; i < NPARAMS; ++i) param_desc[i].type = i32_ty; memset(&sig, 0, sizeof sig); sig.ret = i32_ty; sig.params = param_desc; @@ -861,8 +870,7 @@ static uint32_t cg_emit_delayed_pressure(CfreeCompiler* c, cfree_cg_push_local(cg, params[NPARAMS - 1]); cfree_cg_load(cg, mem); cfree_cg_drop(cg); - for (uint32_t i = 0; i + 1 < NPARAMS; ++i) - cfree_cg_drop(cg); + for (uint32_t i = 0; i + 1 < NPARAMS; ++i) cfree_cg_drop(cg); cfree_cg_push_int(cg, 0, i32_ty); cfree_cg_ret(cg); cfree_cg_func_end(cg); @@ -902,7 +910,8 @@ static uint32_t cg_emit_local_shadow_boundary(CfreeCompiler* c, EXPECT(ob != NULL, "local shadow boundary obj builder allocation failed"); if (!ob) return 0; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "local shadow boundary cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -1003,7 +1012,8 @@ static uint32_t cg_emit_local_shadow_partial_store(CfreeCompiler* c, EXPECT(ob != NULL, "partial shadow obj builder allocation failed"); if (!ob) return 0; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "partial shadow cg allocation failed"); if (!cg) { obj_free((ObjBuilder*)ob); @@ -1055,8 +1065,7 @@ static uint32_t cg_emit_local_shadow_partial_store(CfreeCompiler* c, return size; } -static void exercise_cg_constfold_phases(CfreeCompiler* c, - CfreeCgTypeId i32_ty, +static void exercise_cg_constfold_phases(CfreeCompiler* c, CfreeCgTypeId i32_ty, CfreeCgTypeId i8_ty) { uint32_t delayed_size = cg_emit_delayed_chain(c, i32_ty, "cg_delayed_chain_o1"); @@ -1140,7 +1149,8 @@ static CfreeCg* cg_begin_bad_store_func(CfreeCompiler* c, const char* name) { EXPECT(ob != NULL, "bad-store obj builder allocation failed"); if (!ob) return NULL; cg = NULL; - (void)cfree_cg_new(c, ob, &opts, &cg); + (void)cfree_cg_new(c, &cg); + if (cg) (void)cfree_cg_begin_obj(cg, ob, &opts); EXPECT(cg != NULL, "bad-store cg allocation failed"); if (!cg) return NULL; @@ -1216,6 +1226,63 @@ static void exercise_cg_memory_mismatch_diags(CfreeCompiler* c, "store size mismatch should diagnose clearly, got '%s'", g_last_diag); } +static void exercise_compile_session_two_deltas(CfreeCompiler* c) { + CfreeCompileSessionOptions sopts; + CfreeCompileSession* s = NULL; + CfreeAsmCompileOptions aopts; + CfreeSourceInput in; + CfreeObjBuilder* ob1 = NULL; + CfreeObjBuilder* ob2 = NULL; + static const uint8_t empty[] = ""; + + memset(&sopts, 0, sizeof(sopts)); + memset(&aopts, 0, sizeof(aopts)); + sopts.lang = CFREE_LANG_ASM; + sopts.compile.language_options = &aopts; + memset(&in, 0, sizeof(in)); + in.bytes.name = "<api-session-asm>"; + in.bytes.data = empty; + in.bytes.len = 0; + in.lang = CFREE_LANG_ASM; + + EXPECT(cfree_compile_session_new(c, &sopts, &s) == CFREE_OK && s, + "compile session new failed"); + if (!s) return; + EXPECT(cfree_compile_session_compile(s, &in, &ob1) == CFREE_OK && ob1, + "compile session first delta failed"); + EXPECT(cfree_compile_session_compile(s, &in, &ob2) == CFREE_OK && ob2, + "compile session second delta failed"); + cfree_obj_builder_free(ob1); + cfree_obj_builder_free(ob2); + cfree_compile_session_free(s); +} + +static void exercise_cg_begin_end_two_objects(CfreeCompiler* c) { + CfreeCg* cg = NULL; + CfreeObjBuilder* ob1 = NULL; + CfreeObjBuilder* ob2 = NULL; + CfreeCodeOptions opts; + + memset(&opts, 0, sizeof(opts)); + ob1 = (CfreeObjBuilder*)obj_new((Compiler*)c); + ob2 = (CfreeObjBuilder*)obj_new((Compiler*)c); + EXPECT(ob1 && ob2, "obj_new failed for cg begin/end session"); + EXPECT(cfree_cg_new(c, &cg) == CFREE_OK && cg, "cg session new failed"); + if (cg && ob1) { + EXPECT(cfree_cg_begin_obj(cg, ob1, &opts) == CFREE_OK, + "cg begin first object failed"); + EXPECT(cfree_cg_end_obj(cg) == CFREE_OK, "cg end first object failed"); + } + if (cg && ob2) { + EXPECT(cfree_cg_begin_obj(cg, ob2, &opts) == CFREE_OK, + "cg begin second object failed"); + EXPECT(cfree_cg_end_obj(cg) == CFREE_OK, "cg end second object failed"); + } + cfree_cg_free(cg); + cfree_obj_builder_free(ob1); + cfree_obj_builder_free(ob2); +} + int main(void) { CfreeTarget target; CfreeContext ctx; @@ -1401,6 +1468,8 @@ int main(void) { exercise_cg_literal_folds(c, i32_ty); exercise_cg_constfold_phases(c, i32_ty, i8_ty); exercise_cg_memory_mismatch_diags(c, i32_ty, i64_ty, rec); + exercise_compile_session_two_deltas(c); + exercise_cg_begin_end_two_objects(c); cfree_compiler_free(c); return g_fail ? 1 : 0; diff --git a/test/asm/harness/asm_runner.c b/test/asm/harness/asm_runner.c @@ -233,6 +233,55 @@ static void target_from_env(CfreeTarget* t) { } } +static CfreeStatus compile_asm_obj(CfreeCompiler* c, + const CfreeAsmCompileOptions* opts, + const CfreeBytes* in, + CfreeObjBuilder** out) { + CfreeCompileSessionOptions sopts; + CfreeCompileSession* session = NULL; + CfreeSourceInput sin; + CfreeStatus st; + memset(&sopts, 0, sizeof(sopts)); + sopts.lang = CFREE_LANG_ASM; + sopts.compile.code = opts->code; + sopts.compile.diagnostics = opts->diagnostics; + sopts.compile.language_options = opts; + memset(&sin, 0, sizeof(sin)); + sin.bytes = *in; + sin.lang = CFREE_LANG_ASM; + st = cfree_compile_session_new(c, &sopts, &session); + if (st == CFREE_OK) st = cfree_compile_session_compile(session, &sin, out); + cfree_compile_session_free(session); + return st; +} + +static CfreeStatus compile_asm_emit(CfreeCompiler* c, + const CfreeAsmCompileOptions* opts, + const CfreeBytes* in, CfreeWriter* w) { + CfreeObjBuilder* ob = NULL; + CfreeStatus st = compile_asm_obj(c, opts, in, &ob); + if (st == CFREE_OK) st = cfree_obj_builder_emit(ob, w); + cfree_obj_builder_free(ob); + return st; +} + +static CfreeStatus link_one_obj_jit(CfreeCompiler* c, CfreeObjBuilder* ob, + const CfreeJitHost* host, const char* entry, + CfreeJit** out) { + CfreeLinkSessionOptions opts; + CfreeLinkSession* link = NULL; + CfreeStatus st; + memset(&opts, 0, sizeof(opts)); + opts.output_kind = CFREE_LINK_OUTPUT_JIT; + opts.entry = entry; + opts.jit_host = host; + st = cfree_link_session_new(c, &opts, &link); + if (st == CFREE_OK) st = cfree_link_session_add_obj(link, ob); + if (st == CFREE_OK) st = cfree_link_session_jit(link, out); + cfree_link_session_free(link); + return st; +} + /* ---- file helpers ---- */ static int read_file(const char* path, uint8_t** out, size_t* out_len) { @@ -304,9 +353,12 @@ static int hex_decode(const uint8_t* in, size_t in_len, uint8_t** out, ++i; continue; } - if (c >= '0' && c <= '9') v = c - '0'; - else if (c >= 'a' && c <= 'f') v = 10 + c - 'a'; - else if (c >= 'A' && c <= 'F') v = 10 + c - 'A'; + if (c >= '0' && c <= '9') + v = c - '0'; + else if (c >= 'a' && c <= 'f') + v = 10 + c - 'a'; + else if (c >= 'A' && c <= 'F') + v = 10 + c - 'A'; else { free(buf); fprintf(stderr, "asm-runner: bad hex byte 0x%02x\n", c); @@ -372,7 +424,7 @@ static int mode_encode(const char* src_path, const char* out_path) { memset(&opts, 0, sizeof opts); (void)cfree_writer_mem(&g_heap, &w); - if (cfree_compile_asm_obj_emit(c, &opts, &in, w) != CFREE_OK) { + if (compile_asm_emit(c, &opts, &in, w) != CFREE_OK) { cfree_writer_close(w); cfree_compiler_free(c); free(src); @@ -596,7 +648,7 @@ static int mode_emit(const char* src_path, const char* out_path) { memset(&opts, 0, sizeof opts); (void)cfree_writer_mem(&g_heap, &w); - if (cfree_compile_asm_obj_emit(c, &opts, &in, w) != CFREE_OK) { + if (compile_asm_emit(c, &opts, &in, w) != CFREE_OK) { cfree_writer_close(w); cfree_compiler_free(c); free(src); @@ -631,9 +683,7 @@ static int mode_jit(const char* src_path) { CfreeBytes in; CfreeAsmCompileOptions opts; CfreeObjBuilder* ob = NULL; - CfreeJitLinkOptions lopts; CfreeJitHost jhost; - CfreeObjBuilder* arr[1]; CfreeJit* jit = NULL; int (*fn)(void); int result; @@ -655,22 +705,16 @@ static int mode_jit(const char* src_path) { in.len = src_len; memset(&opts, 0, sizeof opts); - if (cfree_compile_asm_obj(c, &opts, &in, &ob) != CFREE_OK || !ob) { + if (compile_asm_obj(c, &opts, &in, &ob) != CFREE_OK || !ob) { cfree_compiler_free(c); free(src); return 1; } - memset(&lopts, 0, sizeof lopts); - arr[0] = ob; - lopts.inputs.objs = arr; - lopts.inputs.nobjs = 1; - lopts.inputs.entry = "test_main"; - memset(&jhost, 0, sizeof jhost); jhost.execmem = &g_execmem; - if (cfree_link_jit(c, &lopts, &jhost, &jit) != CFREE_OK || !jit) { + if (link_one_obj_jit(c, ob, &jhost, "test_main", &jit) != CFREE_OK || !jit) { cfree_compiler_free(c); free(src); return 1; @@ -722,10 +766,14 @@ int main(int argc, char** argv) { long ps = sysconf(_SC_PAGESIZE); if (ps > 0) g_execmem.page_size = (size_t)ps; if (argc < 2) return usage(); - if (!strcmp(argv[1], "--encode") && argc == 4) return mode_encode(argv[2], argv[3]); - if (!strcmp(argv[1], "--decode") && argc == 4) return mode_decode(argv[2], argv[3]); - if (!strcmp(argv[1], "--listing") && argc == 4) return mode_listing(argv[2], argv[3]); - if (!strcmp(argv[1], "--emit") && argc == 4) return mode_emit(argv[2], argv[3]); - if (!strcmp(argv[1], "--jit") && argc == 3) return mode_jit(argv[2]); + if (!strcmp(argv[1], "--encode") && argc == 4) + return mode_encode(argv[2], argv[3]); + if (!strcmp(argv[1], "--decode") && argc == 4) + return mode_decode(argv[2], argv[3]); + if (!strcmp(argv[1], "--listing") && argc == 4) + return mode_listing(argv[2], argv[3]); + if (!strcmp(argv[1], "--emit") && argc == 4) + return mode_emit(argv[2], argv[3]); + if (!strcmp(argv[1], "--jit") && argc == 3) return mode_jit(argv[2]); return usage(); } diff --git a/test/link/harness/jit_runner.c b/test/link/harness/jit_runner.c @@ -432,14 +432,14 @@ int main(int argc, char** argv) { jhost.execmem = &g_execmem; jhost.tls = &g_jit_tls; - CfreeJitLinkOptions opts; + CfreeLinkSessionOptions opts; + CfreeLinkSession* link = NULL; + CfreeLinkScript* script = NULL; memset(&opts, 0, sizeof(opts)); - opts.inputs.obj_bytes = nobj ? objs : NULL; - opts.inputs.nobj_bytes = nobj; - opts.inputs.archives = narc ? archives : NULL; - opts.inputs.narchives = narc; - opts.inputs.entry = "test_main"; + opts.output_kind = CFREE_LINK_OUTPUT_JIT; + opts.entry = "test_main"; opts.gc_sections = gc_sections; + opts.jit_host = &jhost; if (use_resolver) { opts.extern_resolver = extern_resolver; opts.extern_resolver_user = NULL; @@ -453,7 +453,6 @@ int main(int argc, char** argv) { cfree_compiler_free(c); return 2; } - CfreeLinkScript* script = NULL; CfreeStatus prc = cfree_link_script_parse(&ctx, (const char*)sbytes, slen, &script); free(sbytes); @@ -463,16 +462,26 @@ int main(int argc, char** argv) { cfree_compiler_free(c); return 1; } - opts.inputs.linker_script = script; + opts.linker_script = script; } CfreeJit* jit = NULL; - CfreeStatus rc = cfree_link_jit(c, &opts, &jhost, &jit); - for (int i = 0; i < nbufs; i++) free(bufs[i]); + CfreeStatus rc = cfree_link_session_new(c, &opts, &link); + for (uint32_t i = 0; rc == CFREE_OK && i < nobj; ++i) + rc = cfree_link_session_add_obj_bytes(link, &objs[i]); + for (uint32_t i = 0; rc == CFREE_OK && i < narc; ++i) + rc = cfree_link_session_add_archive_bytes(link, &archives[i]); + if (rc == CFREE_OK) rc = cfree_link_session_jit(link, &jit); if (rc != CFREE_OK || !jit) { + cfree_link_session_free(link); + if (script) cfree_link_script_free(&ctx, script); + for (int i = 0; i < nbufs; i++) free(bufs[i]); cfree_compiler_free(c); return 1; } + cfree_link_session_free(link); + if (script) cfree_link_script_free(&ctx, script); + for (int i = 0; i < nbufs; i++) free(bufs[i]); /* Sanity: a never-defined sentinel must not be found (covers case 29). */ if (cfree_jit_lookup(jit, "__cfree_test_sentinel__")) { diff --git a/test/link/harness/link_exe_runner.c b/test/link/harness/link_exe_runner.c @@ -192,15 +192,12 @@ int main(int argc, char** argv) { return 2; } - CfreeExeLinkOptions opts; + CfreeLinkSessionOptions opts; + CfreeLinkSession* link = NULL; + CfreeLinkScript* script = NULL; memset(&opts, 0, sizeof(opts)); - opts.inputs.obj_bytes = nobj ? objs : NULL; - opts.inputs.nobj_bytes = nobj; - opts.inputs.archives = narc ? archives : NULL; - opts.inputs.narchives = narc; - opts.inputs.dso_bytes = ndso ? dsos : NULL; - opts.inputs.ndso_bytes = ndso; - opts.inputs.entry = entry_name; + opts.output_kind = CFREE_LINK_OUTPUT_EXE; + opts.entry = entry_name; opts.gc_sections = gc_sections; if (script_path) { @@ -211,7 +208,6 @@ int main(int argc, char** argv) { cfree_compiler_free(c); return 2; } - CfreeLinkScript* script = NULL; CfreeStatus prc = cfree_link_script_parse(&ctx, (const char*)sbytes, slen, &script); free(sbytes); @@ -221,7 +217,7 @@ int main(int argc, char** argv) { cfree_compiler_free(c); return 1; } - opts.inputs.linker_script = script; + opts.linker_script = script; } CfreeWriter* w = NULL; @@ -230,19 +226,30 @@ int main(int argc, char** argv) { return 2; } - CfreeStatus rc = cfree_link_exe(c, &opts, w); - - for (int i = 0; i < nbufs; i++) free(bufs[i]); + CfreeStatus rc = cfree_link_session_new(c, &opts, &link); + for (uint32_t i = 0; rc == CFREE_OK && i < nobj; ++i) + rc = cfree_link_session_add_obj_bytes(link, &objs[i]); + for (uint32_t i = 0; rc == CFREE_OK && i < narc; ++i) + rc = cfree_link_session_add_archive_bytes(link, &archives[i]); + for (uint32_t i = 0; rc == CFREE_OK && i < ndso; ++i) + rc = cfree_link_session_add_dso_bytes(link, &dsos[i]); + if (rc == CFREE_OK) rc = cfree_link_session_emit(link, w); if (rc != CFREE_OK) { + cfree_link_session_free(link); + if (script) cfree_link_script_free(&ctx, script); + for (int i = 0; i < nbufs; i++) free(bufs[i]); cfree_writer_close(w); cfree_compiler_free(c); return 1; } + for (int i = 0; i < nbufs; i++) free(bufs[i]); size_t out_len; const uint8_t* out_bytes = cfree_writer_mem_bytes(w, &out_len); int wrc = write_exe(out_path, out_bytes, out_len); + cfree_link_session_free(link); + if (script) cfree_link_script_free(&ctx, script); cfree_writer_close(w); cfree_compiler_free(c); if (wrc) { diff --git a/test/parse/harness/parse_runner.c b/test/parse/harness/parse_runner.c @@ -2,9 +2,9 @@ * * parse-runner --emit FILE.c OUT.o # full pipeline → ELF .o * parse-runner --emit-c FILE.c OUT.c # full pipeline → C source via - * --emit=c CGTarget (Phase 1 C backend; - * see doc/CBACKEND.md) - * parse-runner --jit FILE.c # full pipeline → JIT, call test_main + * --emit=c CGTarget (Phase 1 C + * backend; see doc/CBACKEND.md) parse-runner --jit FILE.c # full + * pipeline → JIT, call test_main * * Exclusively uses the public cfree.h surface: this is the same path real * driver consumers take. Built once; the shell runner walks @@ -270,8 +270,7 @@ static CfreeStatus test_read_all(void* user, const char* path, static void test_release(void* user, CfreeFileData* d) { (void)user; - if (!d) - return; + if (!d) return; free(d->token); d->data = NULL; d->size = 0; @@ -304,9 +303,8 @@ static void add_test_system_includes(CfreeCCompileOptions* opts) { opts->preprocess.nsystem_include_dirs = 1; } -static int add_runtime_archive(CfreeJitLinkOptions* opts, +static int add_runtime_archive(CfreeLinkArchiveInput* rt_archive, uint8_t** rt_data_out) { - static CfreeLinkArchiveInput rt_archive; uint8_t* data = NULL; size_t len = 0; const char* arch = cfree_test_arch_name(); @@ -316,18 +314,47 @@ static int add_runtime_archive(CfreeJitLinkOptions* opts, else if (!strcmp(arch, "x64") || !strcmp(arch, "x86_64") || !strcmp(arch, "amd64")) path = "build/rt/x86_64-linux/libcfree_rt.a"; - if (read_file(path, &data, &len) != 0) - return 0; - memset(&rt_archive, 0, sizeof rt_archive); - rt_archive.bytes.name = path; - rt_archive.bytes.data = data; - rt_archive.bytes.len = len; - opts->inputs.archives = &rt_archive; - opts->inputs.narchives = 1; + if (read_file(path, &data, &len) != 0) return 0; + memset(rt_archive, 0, sizeof *rt_archive); + rt_archive->bytes.name = path; + rt_archive->bytes.data = data; + rt_archive->bytes.len = len; *rt_data_out = data; return 1; } +static CfreeStatus compile_c_obj(CfreeCompiler* c, + const CfreeCCompileOptions* opts, + const CfreeBytes* in, CfreeObjBuilder** out) { + CfreeCompileSessionOptions sopts; + CfreeCompileSession* session = NULL; + CfreeSourceInput sin; + CfreeStatus st; + memset(&sopts, 0, sizeof(sopts)); + sopts.lang = CFREE_LANG_C; + sopts.compile.code = opts->code; + sopts.compile.diagnostics = opts->diagnostics; + sopts.compile.language_options = opts; + memset(&sin, 0, sizeof(sin)); + sin.bytes = *in; + sin.lang = CFREE_LANG_C; + st = cfree_compile_session_new(c, &sopts, &session); + if (st == CFREE_OK) st = cfree_compile_session_compile(session, &sin, out); + cfree_compile_session_free(session); + return st; +} + +static CfreeStatus compile_c_emit(CfreeCompiler* c, + const CfreeCCompileOptions* opts, + const CfreeBytes* in, CfreeWriter* w) { + CfreeObjBuilder* ob = NULL; + CfreeStatus st = compile_c_obj(c, opts, in, &ob); + if (st == CFREE_OK && !opts->code.emit_c_source) + st = cfree_obj_builder_emit(ob, w); + cfree_obj_builder_free(ob); + return st; +} + /* ---- modes ---- */ static int mode_emit_impl(const char* src_path, const char* out_path, @@ -373,7 +400,7 @@ static int mode_emit_impl(const char* src_path, const char* out_path, opts.code.emit_c_source = true; opts.code.c_source_writer = w; } - if (cfree_compile_c_obj_emit(c, &opts, &in, w) != CFREE_OK) { + if (compile_c_emit(c, &opts, &in, w) != CFREE_OK) { cfree_writer_close(w); cfree_compiler_free(c); free(src); @@ -420,13 +447,12 @@ static int mode_jit(const char* src_path) { CfreeContext ctx; CfreeCompiler* c = NULL; CfreeBytes in; - CfreeBytes obj_in; CfreeCCompileOptions opts; - CfreeJitLinkOptions lopts; + CfreeObjBuilder* ob = NULL; + CfreeLinkArchiveInput rt_archive; + CfreeLinkSessionOptions lopts; + CfreeLinkSession* link = NULL; CfreeJitHost jhost; - CfreeWriter* obj_w = NULL; - size_t obj_len = 0; - const uint8_t* obj_data = NULL; uint8_t* rt_data = NULL; CfreeJit* jit = NULL; int (*fn)(void); @@ -452,35 +478,36 @@ static int mode_jit(const char* src_path) { opts.code.opt_level = opt_level_from_env(); add_test_system_includes(&opts); - (void)cfree_writer_mem(&g_heap, &obj_w); - if (cfree_compile_c_obj_emit(c, &opts, &in, obj_w) != CFREE_OK) { - cfree_writer_close(obj_w); + if (compile_c_obj(c, &opts, &in, &ob) != CFREE_OK || !ob) { cfree_compiler_free(c); free(src); return 1; } - obj_data = cfree_writer_mem_bytes(obj_w, &obj_len); - memset(&obj_in, 0, sizeof obj_in); - obj_in.name = src_path; - obj_in.data = obj_data; - obj_in.len = obj_len; memset(&lopts, 0, sizeof lopts); - lopts.inputs.obj_bytes = &obj_in; - lopts.inputs.nobj_bytes = 1; - lopts.inputs.entry = "test_main"; - add_runtime_archive(&lopts, &rt_data); + lopts.output_kind = CFREE_LINK_OUTPUT_JIT; + lopts.entry = "test_main"; memset(&jhost, 0, sizeof jhost); jhost.execmem = &g_execmem; + lopts.jit_host = &jhost; - if (cfree_link_jit(c, &lopts, &jhost, &jit) != CFREE_OK || !jit) { - cfree_writer_close(obj_w); + if (!add_runtime_archive(&rt_archive, &rt_data)) { + cfree_compiler_free(c); + free(src); + return 1; + } + if (cfree_link_session_new(c, &lopts, &link) != CFREE_OK || + cfree_link_session_add_obj(link, ob) != CFREE_OK || + cfree_link_session_add_archive_bytes(link, &rt_archive) != CFREE_OK || + cfree_link_session_jit(link, &jit) != CFREE_OK || !jit) { + cfree_link_session_free(link); cfree_compiler_free(c); free(rt_data); free(src); return 1; } + cfree_link_session_free(link); fn = (int (*)(void))cfree_jit_lookup(jit, "test_main"); @@ -509,7 +536,6 @@ static int mode_jit(const char* src_path) { } cfree_jit_free(jit); - cfree_writer_close(obj_w); cfree_compiler_free(c); free(rt_data); free(src);