Skip to content

JIT executor: recompile-narrowing + capped-persistent reloader (Phase 3 follow-up) #191

@obj-p

Description

@obj-p

Follow-up to #189 (JIT executor Phase 3, PR #190). Phase 3 core is complete: the JIT executor is wired into the macOS daemon behind a StructuralReloader seam — structural edits render in the agent and preview_snapshot serves the agent PNG; literal edits on an agent-backed session rewrite a baked design-time-values JSON and re-render the same .o with no recompile. Measured structural latency is ≈281ms (compile ≈218ms + link/respawn/render ≈62ms).

The render/respawn half is within budget; the whole-module compile is the entire gap to the design's <200ms target. This issue tracks the remaining work, in priority order.

1. Recompile-narrowing (the dominant lever)

PreviewSession.compileObjectForJIT() currently does a whole-module compileObject (~218ms). Wire it to the stable-module/editable-unit split: single-file @testable compile of the edited file against prebuilt .swiftmodules for the rest of the module. The compile-strategy research (W4–W7 on previews-research) found this mandatory and feasible (~0.14s relink at 1000 files; split at file granularity). This is what gets structural edits under 200ms.

2. Capped-persistent reloader

The ratified executor shape is capped-persistent (one persistent agent + a fresh JITDylib per edit + background respawn every ~100 generations), not respawn-per-edit. Swap the body of Sources/PreviewsJITLink/JITStructuralReloader.swift accordingly; the StructuralReloader protocol does not change. This makes the literal path truly in-place (~10ms — re-seed DesignTimeStore + re-render without relink) and amortizes the ~70ms respawn warmup.

  • The agent must call LLJIT::initialize per generation (registers __swift5_* metadata; segfaults without). Satisfied by construction under respawn; must be added explicitly for a persistent agent.

3. examples/ E2E verify

An examples/ project test: a literal edit hot-reloads via DesignTimeStore (~10ms) and a structural edit reloads via the JIT path (respawn), in the same daemon session, no daemon restart. This is the P3.4 acceptance the seam was built for (the routing lives in the FileWatcher closure and is currently covered only by unit tests of the building blocks).

4. JIT-in-CI infra

CI skips the JIT tests because the targets need third_party/llvm-build (multi-GB prebuilt LLVM + orc-rt). Cache or build-once that artifact so CI can run swift test --filter PreviewsJITLinkTests. Self-contained infra; does not affect the daemon design.

Also conditional

P3.3 — in-place write_mem fast path + the Begin/End/cancelUpdate handshake (design §5/§6) — stays conditional, added only if no-restart with @State preservation later earns its keep.

Pointers

  • Plan/source of truth: docs/jit-executor-phase3-plan.md (the "Immediate next step" resume pointer + the P3.4 seam key-files map).
  • Design: prompts/jit-executor-design.md §8 Phase 3+ (on previews-research).
  • Compile-strategy research arc: research/scripts/analysis/jit-compile-arc.md (W4–W7, on previews-research).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions