§9 Profiles & Interop
9.1 The Three-Profile Model
| Profile | Target | Memory | Concurrency | stdlib layer |
|---|---|---|---|---|
full |
Linux / macOS / Windows / mobile NDK | concurrent generational GC (pluggable) | tasks + channels + parallelism | core < alloc < std |
web |
WasmGC (browser / edge / sandbox) | host GC | JSPI / wasm threads | core < alloc < stdweb |
bare |
Cortex-M / RISC-V / bare-metal wasm | none (arena / static pools) | optional cooperative-scheduler library | core |
- Layering is organized by profile (not feature flags); packages may declare the minimum layer they require.
- Compatibility direction (hard rule):
bare ⊆ full ⊆ (any profile)is upward compatible — bare/own code is usable under any profile; code that depends on GC allocation (the alloc attribute) entering bare = E3040 (§6.5 mechanical determination).
9.2 The web Profile
- The backend is WasmGC; GC is the host's; task suspension goes through JSPI / stack switching; when wasm threads is enabled, full Send checking is restored (§7.8).
- The JS bridge is typed (no
anyleaking through); JS exceptions are converted toResultat the boundary; JS callbacks follow the web-profile Send approximation rules; DOM/Canvas/Fetch go throughstdweb. - The stdweb minimal API (pinned in v0.5, available from P1-D): after
use stdweb.dom—dom.set_title(Str) -> Void,dom.title() -> Str. The rest of DOM/Canvas/Fetch is expanded release by release following this pattern (anchoring test:10_web_dom.ct). - Bootstrap-side status (T45 note, v0.9·6): ownership convention 2 of the three has landed —
CBox[T](a package in the std ffi domain): C→Ctron handoff viacbox_own, call-duration borrow viacbox_borrow(convention 3), handoff to C viacbox_into_raw, explicit release viacbox_free(a #[trusted] release surface); the ownership sentinel = a C-side registration table (value copies do not copy the sentinel state; double free / use-after-free panic loudly), and CBox always goes through the compiled channel (the interpreter bridge truncates pointers). On the interpreter side, the extern direct-call bridge closes the float-frame gap (f:/g: frames driven by declared types + Ri:/Rf:/Rg: return aliases + ABI-correct SIMD-class casts + float returns round-tripping losslessly as "%.17g" text; float shapes with more than 4 arguments panic loudly); integer returns widened to full-width long (the int-truncation gap destroyed on the bootstrap side). cimport union/struct/enum keywords qualify pointer parameters (union Vals*strips the keyword and resolves through the typedef name table). Anchors:tests/ffi/(the three cbox directories / ext_finterp dual-channel / cimport union parameters). - Bootstrap-side status (v0.7 note): the dynamic surface —
#[dlsym]runtime thunks (dlsym(RTLD_DEFAULT)) +dlopen/dlclose/dlsymbuilt in; variadic externs (trailing...in the parameter list; non-extern = E4044);#[link_name(x)]symbol renaming and stackable attributes; the export surface#[export](wrapping non-static C symbols, for the embedding surface); extern-returning fns unblocked (boxed at the declaration site, dual paths for the env sentinel);USize→size_t(code "z");#[repr(packed)]/#[repr(align(N))]; automatic consumption of C headers viacompiler/tools/cimport.ct(a decl-level subset: prototypes / #define / scalar structs; 71 bindings measured against the real math.h). Anchors:tests/ffi/(cimport/dyn_link/variadic/export/ext_fn_ret/layout). - Bootstrap-side status (v0.6 note): under
--profile=web, thestdweb.domchecking surface and runtime surface are already usable (domis a built-in namespace; the title is stored in runtime state; the full profile = intercepted with E2020); the emission side produces thectron_dom_set_title/ctron_dom_titleC stubs, with the real JS bridge to be substituted by the WasmGC backend (P1-D).
9.3 The bare Profile
- Cross-compilation is built in:
ctron build --target <triple>, with a self-contained toolchain (bundled lld + a minilibc option). - First bare targets (tier-1):
thumbv7em-none-eabi,riscv32imac-unknown-none; the remaining LLVM-supported targets are tier-2. - For ISR constraints, explicit allocators, and hard-real-time paths, see §6.6.
9.4 Performance Targets (R4 Normalization)
| Path | Metric | Nature |
|---|---|---|
| own / hot-path profiles | within 5% of C in both directions | hard target (P3 exit) |
| GC profile | gap to C ≤ 15% | a target with an exit condition: if unmet, tighten the GC default policies and steer hot paths to own (§15 risk mitigation) |
| bare | zero implicit allocation, no GC pauses, deterministically buildable | hard target |
9.5 Hardware Utilization
Simd[E, N]fixed-length vectors as first-class citizens; auto-vectorization + comptime unrolling.- A unified async I/O layer: io_uring / kqueue / IOCP (built into the runtime, colorless API).
- NUMA-aware allocation and task affinity (runtime options).
-
GPU (
kernelblocks → SPIR-V/PTX): reserved for v2, via codegen plugins (§10.5). -
Bootstrap-side status (T51 note, 2026-10-03): the unified async I/O layer's four backends are in the tree (the
lib/net/c_src/ctron_rt.creactor) — kqueue (darwin) / epoll (linux) / io_uring (linux, runtime-probed: a NODROP feature gate + a boot-time double-NOP self-check; on failure, loudly registered with fallback to epoll; suppressed via the envCTRON_RT_REACTOR=epoll|io_uring; observed viactron_rt_reactor_name())/ POSIX poll (others). Isomorphic mapping = POLL_ADD is natively one-shot ≙ EV_ONESHOT/EPOLLONESHOT, armed swallow-on-delivery / last-wins, zero new contracts; the reactor's enter is single-consumer blocking, eliminating the 100ms fallback tick. TheCTRON_RT_NUMA=off|on|autooption slot +ctron_rt_numa_nodes()topology probing are in place (linux/sys/devices/system/node); aware allocation / task affinity remain aspirations (trigger condition = multi-node target machines). IOCP: no windows net target machine; registered as environment-dependent. The dual-arm same-shape smoke test is hooked intoci.sh(linux = epoll + io_uring double roll call; darwin = kqueue). Simd v0 = semantics / scalar emulation; for the vectorization assessment conclusions and aspiration tiers, seedocs/simd-vectorization-analysis.md(same note as §3.11).
9.6 FFI and #[trusted]
- An
extern "c"function declaration + the#[trusted]marker = the only entry point outside the safe subset; audited at the package level (ctron lint --trusted). Declaration syntax (v0.5):
#[trusted]
extern "c" fn ctron_add(a: I64, b: I64) -> I64 // no function body; defined on the C side
- C ABI type mapping (excerpt):
I8↔int8_tUSize↔size_tF64↔doubleBool↔bool(C99)T[N]↔T[N]T[]↔(ptr,len)(via wrappers); structs are laid out as declared (#[repr(c)]is the default for FFI exports). - The three ownership conventions (bindgen generates wrappers according to them):
C-owned: C allocates, C frees; Ctron only borrows for the duration of the call;Ctron-owned: transferring ownership across the boundary must go through a wrapper type (e.g.CBox[T]), with drop responsibility explicit;borrowed: a temporary borrow whose lifetime is the duration of the call, never escaping the wrapper layer.- Forbidden to hand arena memory to C for long-term holding (freeing it leaves a dangling pointer); when needed, deep-copy it across the boundary.
- Bootstrap-side status (v0.7 note): the dynamic surface —
#[dlsym]runtime thunks (dlsym(RTLD_DEFAULT)) +dlopen/dlclose/dlsymbuilt in; variadic externs (trailing...in the parameter list; non-extern = E4044);#[link_name(x)]symbol renaming and stackable attributes; the export surface#[export](wrapping non-static C symbols, for the embedding surface); extern-returning fns unblocked (boxed at the declaration site, dual paths for the env sentinel);USize→size_t(code "z");#[repr(packed)]/#[repr(align(N))]; automatic consumption of C headers viacompiler/tools/cimport.ct(a decl-level subset: prototypes / #define / scalar structs; 71 bindings measured against the real math.h). Anchors:tests/ffi/(cimport/dyn_link/variadic/export/ext_fn_ret/layout). - Bootstrap-side status (v0.6 note): fixed the external linkage of extern prototypes (the old implementation used
static, relying on linker leniency); C-ABI callbacks — fn-type parameters map across the boundary toct_fn1..3, bare fn names pass through unwrapped, and capturing closures are intercepted with E4042 (no env slot); the#[repr(c)]struct declaration surface (E4041 intercepts misuse / W8051 warns on non-C-ABI fields), with the emission side emitting the C struct in declaration order — same shape = ABI compatible; Str marshalling viastr_from_c(arena deep copy, Ctron-owned); boundary governance W8052 (container types) / W8053 (returning fn). Bool crosses the boundary as int (unified across the three lines; ABI-equivalent to bool). Anchoring tests:tests/ffi/(the landing point of the §9.8 commitments); performance:compiler/test/bench_ffi.sh(scalar calls / struct by value at 1.00× vs pure C). For the defect list and the comparison with mainstream languages, seedocs/ffi-analysis.md.
9.7 Artifacts and Toolchain (Normative Summary)
- A static single binary by default; size targets: bare+core runtime < 100KB (hard target), full complete runtime < 1MB (goal).
- The backend matrix (all pluggable): Cranelift (dev) / LLVM (release) / WasmGC (web) / Wasm MVP (embedded wasm) / the CVM interpreter (comptime,
ctron runscripts, debugging). - One command:
ctron build/test/fmt/doc/lint/bench/run/publish/add/target/check; see §10.2 forctron check --format=json.
9.8 Correspondence with the Test Suite
tests/08_bare.ct (bare explicit arena), tests/08_bare_alloc.neg.ct (bare E3040); FFI multi-file cases are carried by tests/ffi/ from P1 on (landed in v0.6: four behavior cases + seven negative/lint cases, accepted through both channels — tests/ffi/run.sh and the suite.py ffi/ section).