ReviewOS

home-lang/home

fix(build): native `home build` skips comptime, collides module symbols and caches empty blobs

#798
Closed chris opened this 9 days ago ·
9 days ago

Problem

Beyond type errors (tracked separately), native home build has correctness gaps: the comptime executor is set up but never runs; module-name prefixing for symbols is disabled (a known writer bug), so same-named functions in different modules can collide; and the incremental cache stores empty blobs.

Evidence (origin/main @ d4b219507)

Scope

  • Run the comptime executor (or error on comptime constructs until it does).
  • Fix the writer bug and re-enable per-module symbol prefixes.
  • Store real artifacts in the incremental cache, or disable it.

Acceptance criteria

  • Two modules each defining fn helper() link and call the right one.
  • A comptime expression is evaluated at build time (test).
  • A cache hit reproduces a byte-identical binary.

Related: #780 Part of #814.

9 days ago

Incremental-cache correctness checkpoint pushed to main as 94176de (fix(build): cache complete native executables (#798)).

Changes:

  • removed the empty AST/type/object placeholder path from IncrementalCompiler;
  • cache entries now contain the complete generated executable plus a source-hash sidecar;
  • zero-byte artifacts are rejected on both store and load;
  • cache lookup happens only after parse/type/borrow/optimization gates;
  • cache hits restore the actual executable bytes and POSIX mode 0755;
  • both ARM64 and x86-64 native backends store their finished artifact;
  • registered the previously unwired cache tests in zig build test.

Verification under the 3,840 MB guard:

  • zig build test -Dfilter=cache -j1: 11/11 cache tests passed (plus cached ts_cache target), 200 MB peak;
  • zig build debug -Denable_jsc=false -j1: 5/5 steps passed, 901 MB peak on the final rebuild;
  • real CLI two-build acceptance: first build stored the executable, second build restored it to a different output path, cmp proved byte identity, and mode was exactly 755 (44 MB peak).

#798 remains open for its comptime-execution and per-module symbol-prefix requirements.

9 days ago

Comptime checkpoint pushed to main as 3dbd760 (fix(build): evaluate comptime before native emission (#798)).

What changed:

  • removed the misleading second ComptimeExecutor in buildCommand that was initialized but never run;
  • the type checker’s actual ComptimeIntegration is now the single evaluation pass feeding native codegen;
  • evaluator failures are checker errors (and therefore fatal by default) instead of log-only warnings;
  • ComptimeExpr is type-transparent rather than falling through to Void;
  • ARM64 native codegen now consumes evaluated integer/boolean values from the same store as x86-64;
  • added a native executable regression requiring one stored comptime value and process exit status 42.

Guarded verification:

  • codegen suite: 15/15 passed, 433 MB final peak;
  • type/control-flow suite: 45/45 passed, 300 MB peak;
  • fresh zig build debug -Denable_jsc=false -j1: 5/5 steps, 901 MB peak;
  • real Apple-silicon CLI acceptance: home build compiled return comptime 6 * 7, and the emitted executable exited 42 (44 MB test peak).

Together with 94176de, #798 now has verified comptime execution and real-artifact caching. The issue remains open only for per-module symbol prefixing / same-named helper collision correctness.

9 days ago

Checkpoint: the remaining module-symbol work is implemented locally across four files but is intentionally not committed yet. ARM64 imports now use module-qualified free-function symbols, scoped aliases, owned pending-call names, import prepasses, and a focused duplicate-helper regression. Exact compile-only verification passed with zig test --test-no-exec (290 MB peak under the 3,840 MB guard). Native execution is currently blocked by a host-wide macOS 26 launch failure: freshly generated one-line ARM64 and x86_64 Zig executables both freeze in _dyld_start before main, independent of Home, Zig version, path, inode, xattrs, or ad-hoc re-signing. No runtime-pass claim and no unverified push.

9 days ago

Final module-symbol checkpoint pushed to main as 75c02cb (fix(codegen): isolate imported native symbols (#798)).

What changed:

  • ARM64 and x86-64 imports now emit canonical module-qualified free-function symbols;
  • aliases are scoped per importing module, imports are loaded before function emission, and nested/forward calls use owned deferred fixups;
  • x86-64 type-registration and code-emission visits are separated, preventing the type prepass from suppressing imported bodies;
  • both CLI native backends propagate the source root;
  • the regression creates left.helper() and right.helper() with different bodies, then decodes ARM64 BL and x64 CALL rel32 instructions to prove main targets the corresponding distinct qualified symbols.

Guarded verification under the 3,840 MB ceiling:

  • focused test compiled for WASI at 612 MB peak and genuinely executed in Node/WASI: 1/1 passed;
  • full native codegen test artifact compiled successfully at 402 MB peak;
  • native focused artifact compiled successfully at 465 MB peak;
  • git diff --check passed and the four formatter-clean files passed zig fmt --check; the x64 source retains one pre-existing formatter-only Zig 0.17 builtin rename also present at the parent commit.

The host macOS 26 dyld issue still prevents freshly generated native test executables from reaching main, so no native-runtime claim is made. The WASI run executes the code generators and verifies their final patched machine-code call targets directly.

All #798 acceptance criteria are now covered on main:

  • byte-identical real cache artifacts: 94176de;
  • build-time comptime evaluation: 3dbd760;
  • collision-free module symbols and correct call targets: 75c02cb.

Sign in to comment on this issue.