diff options
21 files changed, 57 insertions, 34 deletions
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter07/src/main/java/com/seaofnodes/simple/node/Node.java index 5759a065..941edaca 100644 --- a/chapter07/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter07/src/main/java/com/seaofnodes/simple/node/Node.java @@ -119,7 +119,7 @@ public abstract class Node { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public void _printLine(StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(_nid,label())); - if( _inputs==null ) { + if( isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter08/src/main/java/com/seaofnodes/simple/node/Node.java index 234930b4..cffb41e4 100644 --- a/chapter08/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter08/src/main/java/com/seaofnodes/simple/node/Node.java @@ -121,7 +121,7 @@ public abstract class Node { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public void _printLine(StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(_nid,label())); - if( _inputs==null ) { + if( isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter09/src/main/java/com/seaofnodes/simple/node/Node.java index a5f26545..151cb6a7 100644 --- a/chapter09/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter09/src/main/java/com/seaofnodes/simple/node/Node.java @@ -124,7 +124,7 @@ public abstract class Node { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public void _printLine(StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(_nid,label())); - if( _inputs==null ) { + if( isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter10/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter10/src/main/java/com/seaofnodes/simple/IRPrinter.java index f08f3208..1ac32b1a 100644 --- a/chapter10/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter10/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -14,7 +14,7 @@ public class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static void _printLine( Node n, StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } @@ -46,7 +46,7 @@ public class IRPrinter { // Nodes as referred to as %id public static void _printLineLlvmFormat( Node n, StringBuilder sb ) { nodeId(sb, n).append(": "); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter11/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter11/src/main/java/com/seaofnodes/simple/IRPrinter.java index 909dd575..3410ab64 100644 --- a/chapter11/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter11/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -14,7 +14,7 @@ public class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static void _printLine( Node n, StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } @@ -46,7 +46,7 @@ public class IRPrinter { // Nodes as referred to as %id public static void _printLineLlvmFormat( Node n, StringBuilder sb ) { nodeId(sb, n).append(": "); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter12/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter12/src/main/java/com/seaofnodes/simple/IRPrinter.java index 909dd575..3410ab64 100644 --- a/chapter12/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter12/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -14,7 +14,7 @@ public class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static void _printLine( Node n, StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } @@ -46,7 +46,7 @@ public class IRPrinter { // Nodes as referred to as %id public static void _printLineLlvmFormat( Node n, StringBuilder sb ) { nodeId(sb, n).append(": "); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter13/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter13/src/main/java/com/seaofnodes/simple/IRPrinter.java index 909dd575..3410ab64 100644 --- a/chapter13/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter13/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -14,7 +14,7 @@ public class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static void _printLine( Node n, StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } @@ -46,7 +46,7 @@ public class IRPrinter { // Nodes as referred to as %id public static void _printLineLlvmFormat( Node n, StringBuilder sb ) { nodeId(sb, n).append(": "); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter14/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter14/src/main/java/com/seaofnodes/simple/IRPrinter.java index 909dd575..3410ab64 100644 --- a/chapter14/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter14/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -14,7 +14,7 @@ public class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static void _printLine( Node n, StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } @@ -46,7 +46,7 @@ public class IRPrinter { // Nodes as referred to as %id public static void _printLineLlvmFormat( Node n, StringBuilder sb ) { nodeId(sb, n).append(": "); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter15/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter15/src/main/java/com/seaofnodes/simple/IRPrinter.java index 2b4e7ec6..bc1e2741 100644 --- a/chapter15/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter15/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -13,7 +13,7 @@ public class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static void _printLine( Node n, StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } @@ -45,7 +45,7 @@ public class IRPrinter { // Nodes as referred to as %id public static void _printLineLlvmFormat( Node n, StringBuilder sb ) { nodeId(sb, n).append(": "); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter16/src/main/java/com/seaofnodes/simple/IRPrinter.java index 2b4e7ec6..bc1e2741 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -13,7 +13,7 @@ public class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static void _printLine( Node n, StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } @@ -45,7 +45,7 @@ public class IRPrinter { // Nodes as referred to as %id public static void _printLineLlvmFormat( Node n, StringBuilder sb ) { nodeId(sb, n).append(": "); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter17/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter17/src/main/java/com/seaofnodes/simple/IRPrinter.java index f8691931..e1e19aae 100644 --- a/chapter17/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter17/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -13,7 +13,7 @@ public class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static void _printLine( Node n, StringBuilder sb ) { sb.append("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } @@ -45,7 +45,7 @@ public class IRPrinter { // Nodes as referred to as %id public static void _printLineLlvmFormat( Node n, StringBuilder sb ) { nodeId(sb, n).append(": "); - if( n._inputs==null ) { + if( n.isDead() ) { sb.append("DEAD\n"); return; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter18/src/main/java/com/seaofnodes/simple/IRPrinter.java index d563e031..bedc7de9 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -13,7 +13,7 @@ public class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static SB printLine( Node n, SB sb ) { sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) + if( n.isDead() ) return sb.p("DEAD\n"); for( Node def : n._inputs ) sb.p(def==null ? "____" : "%4d".formatted(def._nid)) diff --git a/chapter19/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter19/src/main/java/com/seaofnodes/simple/IRPrinter.java index 957a9184..1b5ade4a 100644 --- a/chapter19/src/main/java/com/seaofnodes/simple/IRPrinter.java +++ b/chapter19/src/main/java/com/seaofnodes/simple/IRPrinter.java @@ -13,7 +13,7 @@ public abstract class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static SB printLine( Node n, SB sb ) { sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) + if( n.isDead() ) return sb.p("DEAD\n"); for( Node def : n._inputs ) sb.p(def==null ? "____" : "%4d".formatted(def._nid)) diff --git a/chapter20/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter20/src/main/java/com/seaofnodes/simple/print/IRPrinter.java index a815e536..0e79d54d 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/print/IRPrinter.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -17,7 +17,7 @@ public abstract class IRPrinter { // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt public static SB printLine( Node n, SB sb ) { sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) + if( n.isDead() ) return sb.p("DEAD\n"); for( Node def : n._inputs ) sb.p(def==null ? "____" : "%4d".formatted(def._nid)) diff --git a/chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java index 82090c78..ffa1d742 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -18,7 +18,7 @@ public abstract class IRPrinter { public static SB printLine( Node n, SB sb ) { if( n==null ) return sb; sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) + if( n.isDead() ) return sb.p("DEAD\n"); for( Node def : n._inputs ) sb.p(def==null ? "____" : "%4d".formatted(def._nid)) diff --git a/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java index 82090c78..ffa1d742 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -18,7 +18,7 @@ public abstract class IRPrinter { public static SB printLine( Node n, SB sb ) { if( n==null ) return sb; sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) + if( n.isDead() ) return sb.p("DEAD\n"); for( Node def : n._inputs ) sb.p(def==null ? "____" : "%4d".formatted(def._nid)) diff --git a/chapter23/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter23/src/main/java/com/seaofnodes/simple/print/IRPrinter.java index 336cf500..046ffb4a 100644 --- a/chapter23/src/main/java/com/seaofnodes/simple/print/IRPrinter.java +++ b/chapter23/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -18,7 +18,7 @@ public abstract class IRPrinter { public static SB printLine( Node n, SB sb ) { if( n==null ) return sb; sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) + if( n.isDead() ) return sb.p("DEAD\n"); for( Node def : n._inputs ) sb.p(def==null ? "____" : "%4d".formatted(def._nid)) diff --git a/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java index 336cf500..046ffb4a 100644 --- a/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java +++ b/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -18,7 +18,7 @@ public abstract class IRPrinter { public static SB printLine( Node n, SB sb ) { if( n==null ) return sb; sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) + if( n.isDead() ) return sb.p("DEAD\n"); for( Node def : n._inputs ) sb.p(def==null ? "____" : "%4d".formatted(def._nid)) diff --git a/chapter25/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter25/src/main/java/com/seaofnodes/simple/print/IRPrinter.java index 8b1c1e2f..f278be70 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/print/IRPrinter.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -16,7 +16,7 @@ public abstract class IRPrinter { public static SB printLine( Node n, SB sb ) { if( n==null ) return sb; sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n._inputs==null ) + if( n.isDead() ) return sb.p("DEAD\n"); for( Node def : n._inputs ) sb.p(def==null ? "____" : "%4d".formatted(def._nid)) @@ -51,7 +51,7 @@ public abstract class IRPrinter { ArrayList<CompUnit> cus = new ArrayList<>(code._compunits.values()); cus.sort(Comparator.comparing(cu -> cu._cname==null ? "" : cu._cname)); for( CompUnit cu : cus ) { - if( cu._start==null || cu._start._inputs==null ) continue; + if( cu._start==null || cu._start.isDead() ) continue; sb.nl().p("=== ").p(cu._cname==null ? "" : cu._cname).p(" ===\n"); printLine(cu._start,sb); ArrayList<Node> projs = projections(cu._start); @@ -59,7 +59,7 @@ public abstract class IRPrinter { ArrayList<FunNode> funs = new ArrayList<>(); for( FunNode fun : code._linker ) - if( fun!=null && fun._inputs!=null && fun._compunit==cu ) + if( fun!=null && !fun.isDead() && fun._compunit==cu ) funs.add(fun); funs.sort(Comparator.comparingInt(n -> n._nid)); for( FunNode fun : funs ) printFunction(fun,sb); @@ -104,7 +104,7 @@ public abstract class IRPrinter { IdentityHashMap<Node,Boolean> owned, IdentityHashMap<Node,Boolean> emitted, SB sb) { - if( n._inputs==null ) return; + if( n.isDead() ) return; for( Node def : n._inputs ) { if( def==null || def instanceof CFGNode || def instanceof ConstantNode || def instanceof PhiNode || isMultiChild(def) || @@ -121,7 +121,7 @@ public abstract class IRPrinter { private static void functionPost(Node n, FunNode owner, IdentityHashMap<Node,Boolean> visit, ArrayList<Node> post) { - if( n==null || n._inputs==null || visit.put(n,Boolean.TRUE)!=null ) return; + if( n==null || n.isDead() || visit.put(n,Boolean.TRUE)!=null ) return; if( n instanceof FunNode fun && fun!=owner ) return; // Linked callee if( n instanceof ParmNode && input0(n)!=owner ) return; // Callee parameter @@ -134,7 +134,7 @@ public abstract class IRPrinter { // are ownership/linkage hooks (StopCU, CallEnds, FunPtrs), never CFG // continuation in the function being printed. if( !(n instanceof ReturnNode) ) for( Node use : n._outputs ) { - if( use==null || use._inputs==null ) continue; + if( use==null || use.isDead() ) continue; if( n instanceof CallNode && use instanceof FunNode ) continue; if( use instanceof FunNode fun && fun!=owner ) continue; if( use instanceof ParmNode && @@ -161,7 +161,7 @@ public abstract class IRPrinter { private static ArrayList<Node> projections(Node multi) { ArrayList<Node> ps = new ArrayList<>(); for( Node use : multi._outputs ) - if( use!=null && use._inputs!=null && isMultiChild(use) ) ps.add(use); + if( use!=null && !use.isDead() && isMultiChild(use) ) ps.add(use); ps.sort(Comparator.comparingInt(IRPrinter::sortOrder)); return ps; } @@ -182,7 +182,7 @@ public abstract class IRPrinter { // Raw, bounds-safe graph inspection for the debugger. In particular do // not call an accessor which might assert, sharpen, cache, or lazily kill. private static Node input0(Node n) { - return n==null || n._inputs==null || n._inputs.isEmpty() + return n==null || n._inputs.isEmpty() ? null : n._inputs.at(0); } diff --git a/docs/chapter-backports.md b/docs/chapter-backports.md index 7151dc4d..40717e5c 100644 --- a/docs/chapter-backports.md +++ b/docs/chapter-backports.md @@ -131,6 +131,25 @@ Historical results below are dated evidence, not a substitute for a fresh baseline. Logs live in ignored build directories and may no longer exist. Reusable implementation lessons are in `skills/chapter25-codex-notes.md`. +### Issue #251: dead-node printing corrected locally, 2026-09-19 + +[Issue #251](https://github.com/SeaOfNodes/Simple/issues/251) identifies dead-node +checks against a null `_inputs` array. Constructors and clones allocate the +array; `kill()` empties it without setting it to null. Line printers now use +`isDead()` throughout 7-25, including both columnar and LLVM formats in 10-17. +Chapter 25's whole-program printer uses the same predicate to omit dead +functions and nodes. Its bounds-safe input accessor simply checks the input +count. Printing does not prune the linker. + +`Chapter07Test.testDeadNodePrinting` in every snapshot 7-25 checks retained input +storage, the `DEAD` marker, and live inputless nodes. Chapter 25 also tests +omitting a dead function while preserving its linker entry. The regressions +fail against isolated original printers in 7, 10, 18, and 25. Full `make tests` +passed with assertions enabled in every affected snapshot, including 447 tests +in 25. The initial Chapter 17 test assumed an inputless Start; its setup was +corrected for that chapter's representation and its full target rerun. +Logs: `chapter25/build/issue251-review/{original,fixed,chapter17-fixed}.log`. + ### Issue #247: emulator 64-bit stores corrected locally, 2026-09-19 [Issue #247](https://github.com/SeaOfNodes/Simple/issues/247) identifies `st8` diff --git a/skills/chapter25-codex-notes.md b/skills/chapter25-codex-notes.md index ab16e8ee..0bb324ac 100644 --- a/skills/chapter25-codex-notes.md +++ b/skills/chapter25-codex-notes.md @@ -216,6 +216,10 @@ Consequences: ## Side-effect-free diagnostics: B09 lessons +- `Node._inputs` remains allocated after `kill()`. Use `isDead()` when printing + or filtering dead nodes; an empty input array alone does not imply death. + Bounds-safe edge inspection only needs null-node and input-count checks. + - Type construction and interning are allowed during printing. Do not add alternate linker-key comparisons or other machinery merely to avoid interning; canonical types and fast identity comparisons are normal type-system operations. |
