summaryrefslogtreecommitdiff
path: root/skills
diff options
context:
space:
mode:
Diffstat (limited to 'skills')
-rw-r--r--skills/chapter25-codex-notes.md41
-rw-r--r--skills/incremental-builds.md61
2 files changed, 73 insertions, 29 deletions
diff --git a/skills/chapter25-codex-notes.md b/skills/chapter25-codex-notes.md
index be9768f8..ceed54d1 100644
--- a/skills/chapter25-codex-notes.md
+++ b/skills/chapter25-codex-notes.md
@@ -36,10 +36,16 @@ For shared viewer work, read [the graph viewer notes](graph-viewer-codex-notes.m
Static `_spillScaled` also counts each inlined loop copy separately, without
credit for eliminated calls; inspect the optimized call graph before calling
a higher cross-chapter score an allocator regression.
-- Prefer concrete ArrayList to List, common base classes to unnecessary
- interfaces, and short names (`pred`, `proj`, `def`, `use`). Avoid redundant
+- Use concrete JDK collection types in fields, parameters, and return types:
+ ArrayList, HashMap, HashSet, etc., rather than List, Map, or Set interfaces.
+ Prefer common base classes to unnecessary interfaces, and short names
+ (`pred`, `proj`, `def`, `use`). Avoid redundant
Objects.requireNonNull. Prefer int[]/AryInt to List<Integer>; avoid large boxed
ID collections (use arrays/BitSet or NBHML as appropriate). Node ID 0 means null.
+- When both branches assign the same field or variable, prefer one assignment
+ with a ternary expression over an if/else.
+- Space declaration initializers as `Type name = expression;`. Preserve
+ deliberate column alignment when it makes related declarations easier to read.
- Do not introduce Java streams. Use loops and explicit sorts; ask Cliff before
making any exception.
- Cliff often debugs the same failure in parallel. If asked to work in a side
@@ -51,7 +57,7 @@ For shared viewer work, read [the graph viewer notes](graph-viewer-codex-notes.m
printer/accessor side effect is immediately high priority.
- Keep edited text files LF-only, including on Windows.
- When mixing `||` and `&&` in one expression, always parenthesize the groups
- explicitly rather than relying on operator precedence.
+ explicitly rather than relying on operator precedence: `x || (y && z)`.
- For any node consuming or producing both control and memory, control belongs
in slot 0 and memory in slot 1; other inputs/results follow. This applies to
Start, Return, and future forward ports of Call, CallEnd, and other such nodes.
@@ -65,6 +71,31 @@ For shared viewer work, read [the graph viewer notes](graph-viewer-codex-notes.m
## Mutability and chapter boundaries
+- Chapter 28b emits one object per source CompUnit. Imported functions have
+ Fun/Summary/Return graphs until an object is materialized. SummaryNodes are
+ never inlineable bodies. Only local calls request speculative IR; an unused
+ imported function must not recursively fetch its callees. Function identity
+ survives materialization through GlobalBits and rewired call/return edges.
+- Initialization summaries retain direct call/touch edges and parent edges.
+ A potential cycle requires full IR refinement before diagnosis: a helper
+ outside the SCC can provide the constant that removes an internal edge.
+ Native linking uses the compiler's resolved CompUnit object paths when
+ available. Object-only tests without a CodeGen list all link inputs explicitly;
+ TestC does no dependency search. Eval2 trusts TypeCheck and a coherent set of
+ library objects; it does not revalidate cross-object compatibility.
+ SummaryNode.load uses CodeGen.getElf directly;
+ Eval2 needs no extra byte snapshot or protection from rewritten object files.
+ Tests must isolate output paths to avoid writer/reader races.
+ Eval2 materializes one object's checked IR on demand and schedules it
+ independently; never reoptimize graphs with active evaluation frames. Eval2
+ executes CLInit directly using shared run-once flags. The child's clinit
+ body checks its parent before setting its own flag, so Eval2 and Lower need
+ only the requested class's flag-test/call at each active use.
+- Summary escape information must include retention on nonreturning paths and
+ references passed by new callers. Result types alone do not capture this.
+ Import reanalysis releases prior SCCP memory keeps before starting another
+ solve; freshly deserialized nodes need parser-like construction semantics.
+
- Prefix updates must share ordinary name resolution: a method's bare field
name denotes memory, while constructor fields may still be local SSA values.
Do not update the declaration's scope slot before resolving that distinction.
@@ -153,8 +184,8 @@ For shared viewer work, read [the graph viewer notes](graph-viewer-codex-notes.m
- CLInit lowering (2026-10-17): TypeCheck queues surviving markers; optional
Serialize saves opaque ideal IR, then Lower runs Iter before LoopTree.
Serialization includes disconnected Returns and filters cross-object links
- without mutating the live graph. Parent initialization precedes the child's
- flag test/call; the true flag store remains inside the initializer. Runtime
+ without mutating the live graph. In Chapter 28b the child's initializer owns
+ both its parent-init check and its subsequent true flag store. Runtime
flag reads follow ordinary Load idealization, including removing control.
Handle x86 condition-flag lifetime constraints in the backend, not by pinning
ideal Loads. Generated calls remain unlinked and
diff --git a/skills/incremental-builds.md b/skills/incremental-builds.md
index 201922a0..47c06fd9 100644
--- a/skills/incremental-builds.md
+++ b/skills/incremental-builds.md
@@ -1,42 +1,54 @@
-# Incremental builds: future work
+# Incremental builds
-Recorded after the Separate Compilation README review, 2026-10-24. This is a
-design outline, not a description of implemented incremental builds.
+Implementation notes and remaining build-driver work, reviewed 2026-10-25.
-## Current gap
+## Current reuse check
-`CompUnit` decides whether to reuse an object when the unit is discovered. It
-checks its source timestamp and its dependencies' existing object timestamps.
-It does not settle the whole dependency graph before accepting saved IR.
+Chapter 28b's `CompUnit` decides whether to reuse a local object by walking its
+recorded dependencies before loading saved types or IR. It checks all sources
+owned by each local object, missing inputs, and dependency object timestamps.
+Dependencies use the same local/library resolution for checking and loading.
For example:
1. A depends on B and has inlined some of B.
2. B's source changes, leaving B's object unchanged.
-3. A client discovers A. A's check sees the old B object and accepts A's object.
-4. Later discovery notices that B needs rebuilding, without reconsidering A.
+3. A client discovers A. The check follows A's recorded dependency to B and
+ finds B's newer source, even though B's object has not changed.
+4. A is reparsed, so its saved inlined copy of B is never accepted.
-The compiler can therefore reuse code based on stale bodies or constants.
+Use a fresh visited set for each candidate object. Cycles terminate safely,
+but a provisional success inside a cycle must not be cached for another root.
+Each source compilation unit now owns its own object; units compiled together
+share a build timestamp so cycles do not invalidate themselves due to write order.
An unchanged public signature is insufficient: Simple imports implementation
details for optimization as well as declarations for type checking.
+Object-only libraries are still supplied as a coherent build. Do not reject
+them merely because one dependency has a newer installation timestamp: existing
+tests compile cyclic libraries against stubs and then combine their real
+objects. Validating those combinations requires saved input versions, not a
+guess from file times. A newer library object does invalidate a source-backed
+local dependent that can be rebuilt.
+
+`IncrementalBuildTest` covers unchanged reuse, transitive source edits,
+cycles, missing inputs, library dependencies, and clean/incremental native
+execution parity. It sets file times directly, without sleeps.
+
## Required pieces
-- Discover dependencies, mark changed units, and propagate that decision to
- dependents until it settles. Handle cycles as groups. Do this before loading
- IR that may be stale; newly discovered dependencies must also join the plan.
-- Record actual inputs. An object can own several source units, so track all
- of their sources and the objects resolved through library search paths.
- The current check assumes `buildDir/name.o`; a missing file has timestamp
- zero and does not trigger rebuilding. Missing inputs must invalidate or
- produce a useful error rather than silently accepting an old result.
+- Plan object targets and rebuilds across invocations. Handle cycles as groups
+ and newly discovered dependencies. The compiler's per-object reuse check is
+ not a complete scheduling or linking policy.
+- Record actual input identities: source units and resolved library paths and
+ versions. A search
+ path change can select a different library even with an older timestamp.
- Record compiler and serialization versions, target, ABI, and relevant
options. Content hashes would also detect changes with preserved timestamps.
Specify which changes require rebuilding source and which reject an
incompatible source-free library.
-- Make build targets match output ownership. The old ignored `testModule0`
- expects separate A.o and A/B.o, while the current compiler can bundle several
- units into one object. The target must identify the complete set it owns.
+- Make build targets account for every output of a compilation request, which
+ can discover several source units and produce a separate object for each.
- Provide an "ensure current" build operation. Explicit source compilation
currently always recompiles. An unchanged build should do no compilation or
linking; a changed object or link input should trigger relinking.
@@ -54,10 +66,11 @@ requests straightforward. A clean build and an incremental build must produce
the same observable program behavior.
Cover unchanged builds, direct and transitive source edits, inlined constants
-and bodies, cyclic dependencies, bundled sources, removed inputs, library-path
+and bodies, cyclic dependencies, multiple outputs, removed inputs, library-path
changes, compiler/target changes, and failed builds. Use controlled timestamps
or hashes instead of sleeps. Replace the ignored historical experiment with
tests matching the chosen object ownership model.
-Selective library IR loading is separate future work. It can reduce compile
-cost, but is not required to make conservative incremental rebuilding correct.
+Library IR loading is independent of build and native link dependencies.
+Summary-only imports still require coherent objects at link time, and inlining
+does not erase the build dependency on the object supplying the copied body.