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:
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);