summaryrefslogtreecommitdiff
path: root/docs/chapter-backports.md
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-24 09:38:56 -0700
committerCliff Click <cliffc@acm.org>2026-10-24 09:38:56 -0700
commitac525dc59de1ae195c40f8e21b09485d0e5d9330 (patch)
treed1af8c53dbcdf64526d0d5b5d49c8fdc53489af1 /docs/chapter-backports.md
parent2a7ed6bda01f028cf13f803d89b10908d7ea7937 (diff)
downloadSimple-ac525dc59de1ae195c40f8e21b09485d0e5d9330.tar.gz
Simple-ac525dc59de1ae195c40f8e21b09485d0e5d9330.zip
module split
Diffstat (limited to 'docs/chapter-backports.md')
-rw-r--r--docs/chapter-backports.md167
1 files changed, 160 insertions, 7 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).