diff options
| author | Cliff Click <cliffc@acm.org> | 2026-10-24 09:38:56 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-10-24 09:38:56 -0700 |
| commit | ac525dc59de1ae195c40f8e21b09485d0e5d9330 (patch) | |
| tree | d1af8c53dbcdf64526d0d5b5d49c8fdc53489af1 /docs | |
| parent | 2a7ed6bda01f028cf13f803d89b10908d7ea7937 (diff) | |
| download | Simple-ac525dc59de1ae195c40f8e21b09485d0e5d9330.tar.gz Simple-ac525dc59de1ae195c40f8e21b09485d0e5d9330.zip | |
module split
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/chapter-backports.md | 167 | ||||
| -rw-r--r-- | docs/chapter-split.md | 31 |
2 files changed, 189 insertions, 9 deletions
diff --git a/docs/chapter-backports.md b/docs/chapter-backports.md index d44a66d3..a7d3cfca 100644 --- a/docs/chapter-backports.md +++ b/docs/chapter-backports.md @@ -11,7 +11,8 @@ boundaries; revisit construction/escape after he can run both snapshots. Library construction and optimizer tuning move to appendices. The first named snapshots are `chapter-sccp`, `chapter-interprocedural-sccp`, -`chapter-incomplete-types`, `chapter-construction`, and `chapter-escape`. +`chapter-incomplete-types`, `chapter-construction`, `chapter-escape`, and +`chapter-modules`. Local SCCP keeps unknown callers and the call result summaries from pessimistic analysis; the next chapter discovers calls and widens recursive arguments and returns. Numbered Chapters 24 and 25 remain @@ -22,17 +23,168 @@ symbolic fields, and unbounded Load/Phi nodes. Construction now has hidden initializer/allocator calls, local field values and Phis, exit Stores, and explicit publication. Private memory carries fields between helpers. Escape now discovers exposed aliases/functions through the Start/Stop cycle. Review -the construction/escape border before extracting modules and lazy class -initialization. Chained comparisons still need their move to Chapter 23; -allocator tuning and native library material still need their appendices. +the construction/escape border as needed. Modules/lazy initialization now has a +runnable snapshot; separate compilation is next. Chained comparisons still need +their move to Chapter 23; allocator tuning and native library material still +need their appendices. Root Make includes named snapshots in checks. Linear-history publication keeps the numbered sequence until the complete replacement sequence is ready; switch its ordering and index links when retiring the comparison baselines. +## Four README intentions to review + +Keep these four issues visible while reviewing the named chapters. Decisions +may change the construction/escape boundary or later chapter splits. + +1. **Construction (active):** final fields should be local SSA values during + construction, including repeated assignments and loops, with field Stores + at helper exits. Silent loss of writes is a bug; reject unsupported cases. + Also decide whether to allow helpers after inlining and defer completion + checks until SCCP. Those are separate from local field updates. + The local-value implementation now supports final data fields in construction, + escape, and modules, including constant defaults and loop Phis. Shared + function declarations remain fixed. Validate this frontier before adjusting + the broader constructor rules. +2. **Privacy:** underscore names select the public interface, but sibling access + to private fields is not yet rejected. Confirm and enforce the intended + source access rules. The proposed chapter boundary and library changes are + recorded below; Cliff reviews that proposal before implementation. +3. **Class initialization:** review the corrected rule: A may start, initialize + B, then resume. Passive references may cycle; active dependencies may not. + Parents finish before children start. The README now matches this behavior; + further semantic changes need an explicit decision. +4. **Escape summaries and ELF visibility:** analysis tracks unknown callers, + while the current ELF writer exports retained named functions. Decide which + symbols should be public and how that boundary relates to separate compilation. + +### Privacy proposal for review + +Introduce enforced underscore privacy in **Modules and Lazy Class +Initialization** (`chapter-modules`). This is a visible language change: +earlier snapshots allow underscore field access; from Modules onward, access +must obey the declaring class's boundary. The teaching outline already places +privacy here, alongside class names, ownership, and the public interface. +The earlier escape snapshot does not filter fields by underscore spelling. +Its private construction memory is a different concept. + +Review follow-up: preserve the distinction between export filtering and access +checks. Before the 2026-10-24 cleanup, the first underscore helper in the +numbered snapshots' tests was Chapter 19's `Chapter19Test.testString`, +`_hashCodeString`. Renaming it to +`hashCodeString` produces the identical LocalSched graph there: single-use +inlining removes it regardless of spelling. In Chapter 25's copy of that test, +the same rename retains an extra function Return. Underscore export filtering +currently starts in Chapter 25 (and its Modules extraction), not Chapter 19. +Old test class names inside newer snapshots do not identify when their current +underscore behavior was introduced. Any access-check change must preserve the +existing ability to hide helpers and classes from the public interface. +Chapter 19's example now uses `hashCodeString` and field `hashCode`; all 42 +Chapter19Test tests pass with the existing expected graph unchanged. + +Proposed rules: + +- A field or method beginning with `_` is accessible only from code in its + declaring class, including its constructors and method bodies. Enclosing, + nested, and sibling classes do not gain access to that field. A same-class + method may access another instance's private fields; the receiver need not + be exactly `self`. +- A private class name is available in its declaring scope and within the + class itself. For example, `App` may name its child `_Cache`, but that does + not grant `App` access to `_Cache._data`. Code outside that declaring scope + cannot bypass the restriction with a dotted path. Private ancestors also + keep their descendants out of the public interface. Check both type names + and class-value references, and distinguish naming a private class from + using a public value returned by a factory. +- Reads, writes, updates, and method references follow the same rule. + Preserve the source owner and location when receiver types are unresolved; + inlining must not change who has access. An unused result or a folded Load + must not erase an illegal source access. +- Native declarations obey the same source rules. A public wrapper or alias + may deliberately expose a private native binding; no exception for `sys`. + +Source audit: + +- `sys/io.smp` calls `libc._exit` twice. Keep the native `_exit` declaration + private in `sys/libc.smp`, add `val exit = { i32 status -> _exit(status); };`, + and use `libc.exit` in IO. This preserves the native symbol and behavior. +- Bitset's `_bits` and `_grow`, including `_grow(bit)._bits`, are used within + the declaring struct and remain legal. Array helpers call their own `_grow`. + These are the other underscore names in the bundled module library. +- Several retained String spill fixtures use free functions outside `_String` + to access `_hashCode`. They will need an explicit adaptation in this snapshot + (for example, making that fixture field public), with any changed allocation + expectations measured. Do not silently grant file-wide access to pass them. +- The numbered Chapter 25 library has the same `_exit` accesses, and its + `docs/examples/FileIO.smp` also calls `sys.libc._exit`. + +After approval, implement and test in Modules, update its English/Japanese +READMEs with the explicit language boundary, and run the full module suite +including bundled `sys` and native execution. Cover allowed same-class access, +rejected cross-class access, private class lookup, and forward receiver types. +Port the rule and library adaptations to the numbered Chapter 25 comparison +snapshot, with import tests preserving the original source owner. Carry it +into the forthcoming separate-compilation chapter. Do not backport the new +language restriction into Chapters 10-24 or the named pre-module snapshots. + +## Proven Chapter 25 follow-ups from the module extraction + +Three failures reproduce in the numbered Chapter 25 baseline. The fixes are in +`chapter-modules`, but have not been copied back into that comparison snapshot: + +- A private recursive callback passed to native code retains `base == 2` from + known calls instead of restoring its declared `i64` bound. See + `BoundaryTest.testNativeExposure`. Carry direct Call exposure to StopCU even + on nonreturning paths, and restore Start when a function already has known + callers. `Opto.linkStart` must test unknown callers, not `nIns() < 2`. +- The lazy-table example crashes in `StoreNode.useAlias` when a symbolic class + Store has an EscapeNode user from a later allocation. Like + `BulkMemPhiNode.outputAlias`, use the publication field's alias when the Store + is that Escape's public-memory input. See `BoundaryTest.testLazyTables` and + `chapter-modules/src/test/smp/lazy`. The numbered baseline throws `Untested`. +- Final constructor fields lose writes when their declaration value is constant: + `val x=1; new C={->x=1; x=2;};` still reads back 1. Keep constructor field + declarations broad enough for later values, build loop Phis for final fields, + and preserve the distinction from final local bindings. See + `FinalConstructionTest` in the named snapshots. Recheck serialized declarations + and imported constructors when carrying this to the numbered baseline. + +Disposable reproducer: `build/SplitProbe.java`, compiled against Chapter 25; +arguments `native` and `array` exercise these failures. Port with the baseline's +import tests enabled, since the module snapshot intentionally lacks imports. + +Constructor local SSA, deferred constructor parsing and converted private +summaries also need to survive the final separate-compilation extraction. +These carry the already-reviewed construction design forward; they are not +independent changes for pre-construction chapters. + ## Investigate next Establish an earlier-chapter failure before changing compiler behavior. +### Constructor loop with break/continue: worklist assertion + +This fails in construction and in the unchanged escape compiler before the +final-field fix, even with a mutable field: + +```simple +struct C { + int x=0; + new C={int n -> + for(int i=0;i<n;i++) { + if(i==1) continue; + if(i==3) break; + x+=i+1; + } + }; +}; +return new C(arg).x; +``` + +`IterPeeps.progressOnList` asserts during Iter with seed 123. The expected value +for arg 3 is 4. This is independent of final-field mutability; retain the +reproducer while reviewing constructor coverage. Scratch probe: +`build/readme-review/mutable_break.smp`. + ### SCCP function revival: Chapter 24 `Opto.linkCG` uses `code.link(fidx)`, which clears a linker entry when its @@ -102,12 +254,13 @@ the construction chapter. They are not independent fixes to copy into earlier snapshots. Serialization, global identity remapping, and imported escape summaries belong -with separate compilation. Escape analysis gets its own earlier chapter after -construction; its extraction boundary is still to be established. +with separate compilation. Escape analysis now has its own earlier snapshot after +construction; keep its boundary open to review. ## Work that stays in Chapter 25 -Class-cycle checking and CLInit runtime lowering stay in Chapter 25. The +Class-cycle checking and CLInit runtime lowering also appear in the new +modules snapshot; they do not belong in the pre-module chapters. The baseline [chapter README](../chapter25/README.md#lazy-class-initialization) explains the implementation; future work lives in the [roadmap](../chapter25/ROADMAP.md#class-initialization-and-compiler-follow-ups). diff --git a/docs/chapter-split.md b/docs/chapter-split.md index 2b32c83d..7f257d43 100644 --- a/docs/chapter-split.md +++ b/docs/chapter-split.md @@ -117,8 +117,9 @@ The first runnable extractions are [SCCP Across Functions](../chapter-interprocedural-sccp/README.md), followed by [SSA Before Types Are Known](../chapter-incomplete-types/README.md), [Construction and Private Memory](../chapter-construction/README.md) and -[Escape Analysis and Unknown Callers](../chapter-escape/README.md). -The other two snapshots remain to be extracted. Numbered Chapters 24 and 25 +[Escape Analysis and Unknown Callers](../chapter-escape/README.md), and +[Modules and Lazy Class Initialization](../chapter-modules/README.md). +Separate compilation remains to be extracted. Numbered Chapters 24 and 25 remain comparison baselines during this work. Choose final numbers after trying the implementation boundaries above. @@ -153,3 +154,29 @@ Construction still keeps local field values and rejects early exposure of self. Both runnable snapshots are available for Cliff's promised review/play session. This extraction does not choose broader rules for partially initialized objects. No modules, class singletons, serialized IR or identity remapping are included. + +## Modules snapshot ready for review + +`chapter-modules` compiles all discovered source files together. It adds class +singletons, namespaces and privacy, parent initialization, CLInit memory effects, +cycle diagnostics, runtime lowering, and shared native class storage. Source +discovery reads parents as well as referenced children. The bundled modular sys +is supplied as source; building reusable libraries remains appendix material. + +There is no Serialize phase, object reader, GlobalBits remapping, or imported +IR. LocalIds assigns dense IDs within the invocation. FinishCalls detaches +analysis call edges after loop analysis, before scheduling or instruction +selection. ELF emits all discovered live bodies in the selected entry object. + +The preceding construction representation remains: field values and loop Phis +stay local, with Stores at helper exits. Constructor reads may see an unfinished +object, but may never read an uninitialized field. The module snapshot checks +this separately from completion and publication. Escape analysis still restores +unknown callers when a private callback reaches native code, including on paths +with no Return. + +The README's lazy lookup-table example is executable. Existing tests also cover +source/type cycles, rejected initialization cycles, parent order, native cold/hot +calls, shared storage, and ARM/RISC-V encoding. The construction/escape border +remains open to Cliff's review; this extraction does not settle broader rules for +publishing unfinished objects. |
