diff options
| author | Cliff Click <cliffc@acm.org> | 2024-12-02 12:38:24 -0800 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2025-01-15 15:07:30 -0800 |
| commit | 61a06caa60b4c446f45dcb699a1546981413786d (patch) | |
| tree | 2eee77a015dfe3bd9aade41f2503c3d5e716fc34 /chapter18/src/main | |
| parent | fac0c965b11a103a1973153d40347557d9bf68d9 (diff) | |
| download | Simple-61a06caa60b4c446f45dcb699a1546981413786d.tar.gz Simple-61a06caa60b4c446f45dcb699a1546981413786d.zip | |
Progress JSView
Larger programs, better layouts.
Missing e.g. types, & program text & the inter peeps phase
Diffstat (limited to 'chapter18/src/main')
11 files changed, 429 insertions, 69 deletions
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Ary.java b/chapter18/src/main/java/com/seaofnodes/simple/Ary.java index 8654d41e..d37c284f 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/Ary.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/Ary.java @@ -57,18 +57,6 @@ public class Ary<E> extends AbstractList<E> implements List<E> { return true; } - ///** Slow, linear-time, element insert. Preserves order. - // * @param i index to insert at, between 0 and _len inclusive. - // * @param e Element to insert - // */ - //public void insert( int i, E e ) { - // if( i < 0 || i>_len ) - // throw new ArrayIndexOutOfBoundsException(""+i+" >= "+_len); - // if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1)); - // System.arraycopy(_es,i,_es,i+1,(_len++)-i); - // _es[i] = e; - //} - /** Fast, constant-time, element removal. Does not preserve order * @param i element to be removed * @return element removed */ diff --git a/chapter18/src/main/java/com/seaofnodes/simple/GraphVisualizer.java b/chapter18/src/main/java/com/seaofnodes/simple/GraphVisualizer.java index ec326a6f..eb8d8e23 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/GraphVisualizer.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/GraphVisualizer.java @@ -27,7 +27,7 @@ public class GraphVisualizer { // Since the graph has cycles, we need to create a flat list of all the // nodes in the graph. - Collection<Node> all = findAll(stop, scope); + Collection<Node> all = findAll(xScopes, stop, scope); StringBuilder sb = new StringBuilder(); sb.append("digraph chapter18 {\n"); sb.append("/*\n"); @@ -263,20 +263,19 @@ public class GraphVisualizer { /** * Finds all nodes in the graph. */ - private Collection<Node> findAll(Node stop, Node scope) { + public static Collection<Node> findAll(Stack<ScopeNode> ss, Node... ns) { final HashMap<Integer, Node> all = new HashMap<>(); - for( Node n : stop._inputs ) + for( Node n : ns ) + walk(all, n); + for( Node n : ss ) walk(all, n); - if( scope != null ) - for( Node n : scope._inputs ) - walk(all, n); return all.values(); } /** * Walk a subgraph and populate distinct nodes in the all list. */ - private void walk(HashMap<Integer,Node> all, Node n) { + private static void walk(HashMap<Integer,Node> all, Node n) { if(n == null ) return; if (all.get(n._nid) != null) return; // Been there, done that all.put(n._nid, n); diff --git a/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java b/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java index da361afa..48776fd5 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java @@ -1,50 +1,331 @@ package com.seaofnodes.simple; +import com.seaofnodes.simple.node.*; + import java.nio.file.Paths; +import java.io.IOException; +import java.util.Stack; +import java.util.Collection; -public class JSViewer { +public class JSViewer implements AutoCloseable { + // Display programs in an endless loop public static void main( String[] args ) throws Exception { - // Launch server - try( SimpleWebSocket server = new SimpleWebSocket(Paths.get("docs/index.html").toUri(),12345) ) { - int N=0; - while( true ) { - String src = server.get(); - if( src==null || src.equals("null") ) - break; + try(var js = new JSViewer()) { + js.run(); + } + } + + static boolean SHOW; + + // WebSocket to the browser for display + static SimpleWebSocket SERVER; + + static int N; // Dot frames + static Parser P; // + static StopNode STOP; // + + JSViewer() throws Exception { + // Launch server; hand shake + SERVER = new SimpleWebSocket(Paths.get("docs/index.html").toUri(),12345) ; + } + + void run( ) throws Exception { + while( true ) { + String src = SERVER.get(); + switch( src ) { + case null: return; + case "null": return; + case "+": break; // Client requests more frames, but we send them all anyways + default: System.out.println(src); - // Client requests another frame - if( src.charAt(0)=='+' ) { - if( N<2 ) { - StringBuilder sb = new StringBuilder(); - sb.append("digraph jsviewer_1 {\n"); - sb.append("\tnode [shape=circle, style=filled];\n"); - sb.append("\tSRC [label=\"").append("next frame").append("\", shape=oval];\n"); - sb.append("}"); - server.put(sb.toString()); - System.out.println("Sent graph "+N); - N++; - } else { - // no more frames, send nothing + try { + N=0; + // Use parser scope, xscope when building views + P = new Parser(src); + STOP = P.STOP; + SHOW = true; + show(); + // Parse program, generating views at every parse point + P.parse(); + // No longer user parse internal state when building views + P = null; + + + + // Catch and ignore Parser errors + } catch(RuntimeException re) { + } finally { + SHOW = false; + SERVER.put("#"); // Final frame + } + break; + } + } + } + + @Override public void close() throws IOException { + SERVER.close(); + SERVER=null; + } + + public static void show() { if( SERVER!=null && SHOW ) _show(); } + private static void _show() { + Collection<Node> all = GraphVisualizer.findAll(P==null ? null : P._xScopes, STOP, P==null ? null : P._scope); + SB sb = new SB(); + sb.p("digraph view_").p(N++).p(" {\n").ii(); + + // To keep the Scopes below the graph and pointing up into the graph we + // need to group the Nodes in a subgraph cluster, and the scopes into a + // different subgraph cluster. THEN we can draw edges between the + // scopes and nodes. If we try to cross subgraph cluster borders while + // still making the subgraphs DOT gets confused. + sb.i().p("rankdir=BT;\n"); // Force Nodes before Scopes + + // CNC - turned off Apr/8/2024, gives more flex in the layout and + // removes some of the more ludicrous layout choices. + // Preserve node input order + //sb.append("ordering=\"in\";\n"); + + // Merge multiple edges hitting the same node. Makes common shared + // nodes much prettier to look at. + sb.i().p("concentrate=\"true\";\n"); + + // Force nested scopes to order + sb.i().p("compound=\"true\";\n"); + + // Just the Nodes first, in a cluster no edges + nodes(sb, all); + + // Now the scopes, in a cluster no edges + if( P!=null ) + for( ScopeNode xscope : P._xScopes ) + if( !xscope.isDead() ) + scope( sb, xscope ); + + // Walk the Node edges + nodeEdges(sb, P!=null && !P._xScopes.empty() ? P._xScopes.peek() : null, all); + + // Walk the active Scope edges + if( P!=null ) + for( ScopeNode xscope : P._xScopes ) + if( !xscope.isDead() ) + scopeEdges( sb, xscope ); + + + sb.p("}\n").di(); + // Tell client another DOT frame + String dot = sb.toString(); + System.out.println(dot); + try { + SERVER.put(dot); + } catch( IOException ioe ) { + try { SERVER.close();} catch( IOException ignored ){} + } + } + + + + private static void nodes(SB sb, Collection<Node> all) { + // Just the Nodes first, in a cluster no edges + sb.i().p("subgraph cluster_Nodes {\n").ii(); // Magic "cluster_" in the subgraph name + for (Node n : all) { + if( n instanceof ProjNode || n instanceof CProjNode || n instanceof ScopeMinNode || n==Parser.XCTRL ) + continue; // Do not emit, rolled into MultiNode or Scope cluster already + sb.i().p(n.uniqueName()).p(" [ "); + String lab = n.glabel(); + if( n instanceof MultiNode ) { + // Make a box with the MultiNode on top, and all the projections on the bottom + sb. p("shape=plaintext label=<\n").ii(); + sb.i().p("<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">\n"); + // Row over single cell for node label + cell(sb.i().p("<TR>"), lab, null, true, false).p("</TR>\n"); + // Row over single cell, for nested table + sb.i().p("<TR><TD>\n").ii(); + sb.i().p("<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">").p("\n"); + sb.i().p("<TR>"); + n._outputs.sort((x,y) -> x instanceof ProjNode xp && y instanceof ProjNode yp ? (xp._idx - yp._idx) : ((x==null ? 99999 : x._nid) - (y==null ? 99999 : y._nid))); + boolean empty_row=true; + for( Node use : n._outputs ) + if( use instanceof MultiUse muse ) { + cell(sb,use.glabel(),"p"+muse.idx(),use instanceof CFGNode,use.isMem()); + empty_row=false; } - } else { + // At least one cell on row + if( empty_row ) + cell(sb,"",null,false,false); + sb. p("</TR>").p("\n"); + sb.i().p("</TABLE>").p("\n").di(); + sb.i().p("</TD></TR>\n"); + sb.i().p("</TABLE>>\n").di(); + sb.i().p("];\n"); - StringBuilder sb = new StringBuilder(); - sb.append("digraph jsviewer_0 {\n"); - sb.append("\tnode [shape=circle, style=filled];\n"); - sb.append("\tSRC [label=\"").append(src).append("\", shape=oval];\n"); - sb.append("}"); - server.put(sb.toString()); - System.out.println("Sent graph "+N); - N++; + } else { + // control nodes have box shape + // other nodes are ellipses, i.e. default shape + if( n instanceof CFGNode ) sb.p("shape=box style=filled fillcolor=yellow "); + else if (n instanceof PhiNode) sb.p("style=filled fillcolor=lightyellow "); + sb.p("label=\"").p(lab).p("\" ];\n"); + } + } + // Force Region & Phis to line up + for (Node n : all) { + if (n instanceof RegionNode region) { + sb.i().p("{ rank=same; "); + sb.p(region.uniqueName()).p(";"); + for (Node phi : region._outputs) + if (phi instanceof PhiNode) sb.p(phi.uniqueName()).p(";"); + sb.p("}\n"); + } + } + sb.di().i().p("}").nl(); // End Node cluster + } + + // Build a nested scope display, walking the _prev edge + private static void scope( SB sb, ScopeNode scope ) { + sb.i().p("node [shape=plaintext];\n"); + int last = scope.nIns(); + int max = scope._lexSize.size(); + for( int i = 0; i < max; i++ ) { + int level = max-i-1; + String scopeName = makeScopeName(scope, level); + sb.i().p("subgraph cluster_").p(scopeName).p(" {\n").ii(); // Magic "cluster_" in the subgraph name + sb.i().p(scopeName).p(" [label=<\n").ii(); + sb.i().p("<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n"); + // Add the scope level + sb.i().p("<TR><TD BGCOLOR=\"cyan\">").p(level).p("</TD>"); + int lexStart=scope._lexSize.at(level); + // Special for memory ScopeMinNode + ScopeMinNode n = scope.nIns()>1 ? scope.mem() : null; + if( level==0 && n!=null && n.nIns()>2 ) { + sb. p("<TD BGCOLOR=\"blue\" BORDER=0 colspan=\"").p(last-lexStart-1).p("\">\n"); + sb.i().p("\t<TABLE><TR>"); + for( int m=2; m<n.nIns(); m++ ) { + sb.p("<TD>").p(m).p("</TD>"); + throw Utils.TODO(); // Need port names for edges } + sb.p("</TR></TABLE>\n"); + sb.i().p("</TD>"); + } + sb. p("</TR>\n"); // End scope level + sb.i().p("<TR>\n"); + for( int j=lexStart; j<last; j++ ) { + var v = scope._vars.at(j); + cell(sb.i(),v._name,makePortName(scopeName, v._name),j==0,j==1).nl(); + } + last = lexStart; + sb.i().p("</TR>\n"); + sb.i().p("</TABLE>>];\n").di(); + } + // Scope clusters nest, so the graphics shows the nested scopes, so + // they are not closed as they are printed; so they just keep nesting. + // We close them all at once here. + for( int i=0; i<max; i++ ) + sb.di().i().p("}\n"); + } - //// Client reset, send new program - //server.put("!"); + // Append a cell, with color + private static SB cell(SB sb, String text, String port, boolean isCFG, boolean isMem) { + sb.p("<TD "); + if( port!=null ) sb.p("PORT=\"").p(port).p("\""); + if( isCFG ) sb.p(" BGCOLOR=\"yellow\""); + if( isMem ) sb.p(" BGCOLOR=\"blue\""); + sb.p(">"); + if( isMem ) sb.p("<FONT color=\"white\">"); + sb.p(text); + if( isMem ) sb.p("</FONT>"); + sb.p("</TD>"); + return sb; + } + + private static String makeScopeName(ScopeNode sn, int level) { return sn.uniqueName() + "_" + level; } + private static String makePortName(String scopeName, String varName) { return scopeName + "_" + varName; } + + // Walk the node edges + private static void nodeEdges(SB sb, ScopeNode scope, Collection<Node> all) { + // All them edge labels + String scopeName = scope!=null ? makeScopeName(scope, 0) : null; + sb.i().p("edge [ fontname=Helvetica, fontsize=8 ];\n"); + for( Node n : all ) { + // Do not display the Constant->Start edge; + if( n instanceof ConstantNode || + n instanceof XCtrlNode || + // ProjNodes handled by Multi; + n instanceof ProjNode || + n instanceof CProjNode || + // ScopeNodes are done separately + n instanceof ScopeNode || + n instanceof ScopeMinNode + ) + continue; + if( n.isDead() ) + throw Utils.TODO(); + // Normal edges + for( int i=0; i<n.nIns(); i++ ) { + Node def = n.in(i); + if( def==null ) continue; + sb.i().p(n.uniqueName()).p(" -> "); + if( n instanceof PhiNode && def instanceof RegionNode ) { + // Draw a dotted use->def edge from Phi to Region. + sb.p(def.uniqueName()); + sb.p(" [style=dotted taillabel=").p(i).p("];\n"); + } else { + // Most edges land here use->def + if( def instanceof CProjNode proj ) { + String mname = proj.ctrl().uniqueName(); + sb.p(mname).p(":p").p(proj._idx); + } else if( def instanceof ProjNode proj ) { + String mname = proj.in(0).uniqueName(); + sb.p(mname).p(":p").p(proj._idx); + } else sb.p(def.uniqueName()); + // Number edges, so we can see how they track + sb.p("[taillabel=").p(i); + // The edge from New to ctrl is just for anchoring the New + if ( n instanceof NewNode ) + sb.p(" color=green"); + // control edges are colored red + else if( def instanceof CFGNode ) + sb.p(" color=red"); + else if( def.isMem() ) + sb.p(" color=blue"); + // Backedges do not add a ranking constraint + if( i==2 && (n instanceof PhiNode || n instanceof LoopNode) ) + sb.p(" constraint=false"); + sb.p("];\n"); + } + } + + // Bonus edge if hooked by parser + if( (n.iskeep() || n.isUnused()) && scopeName != null ) { + sb.i().p(scopeName).p(" -> ").p(n.uniqueName()).p(" [ stype=dotted color=grey]\n"); } - System.out.println("Client requested shutdown"); - server.close(); } + } + // Walk the scope edges + private static void scopeEdges( SB sb, ScopeNode scope ) { + sb.i().p("edge [style=dashed color=cornflowerblue];\n"); + int level=0; + for( var v : scope._vars ) { + if( v._idx==1 ) continue; // Memory done seperately + Node def = scope.in(v._idx); + while( def instanceof ScopeNode lazy ) + def = lazy.in(v._idx); + if( def==null ) continue; + while( level < scope._lexSize.size() && v._idx >= scope._lexSize.at(level) ) + level++; + String scopeName = makeScopeName(scope, level-1); + sb.i() + .p(scopeName).p(":") + .p('"').p(makePortName(scopeName, v._name)).p('"') // wrap port name with quotes because $ctrl is not valid unquoted + .p(" -> "); + if( def instanceof CProjNode proj ) { + sb.p(def.in(0).uniqueName()).p(":p").p(proj._idx); + } else if( def instanceof ProjNode proj ) { + sb.p(def.in(0).uniqueName()).p(":p").p(proj._idx); + } else sb.p(def.uniqueName()); + sb.p(";\n"); + } } + } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java index 94575559..123841e8 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java @@ -82,7 +82,6 @@ public class Parser { add("while"); }}; - /** * We clone ScopeNodes when control flows branch; it is useful to have * a list of all active ScopeNodes for purposes of visualization of the SoN graph @@ -100,6 +99,7 @@ public class Parser { // Mapping from a type name to the constructor for a Type. public final HashMap<String, StructNode> INITS; + public Parser(String source) { this(source, TypeInteger.BOT); } public Parser(String source, TypeInteger arg) { Node.reset(); @@ -117,10 +117,6 @@ public class Parser { INITS = new HashMap<>(); } - public Parser(String source) { - this(source, TypeInteger.BOT); - } - @Override public String toString() { return _lexer.toString(); } @@ -162,6 +158,7 @@ public class Parser { mem.addDef( new ProjNode(START, 1, ScopeNode.MEM0).peephole()); _scope.define(ScopeNode.MEM0, TypeMem.TOP , false, mem .peephole()); _scope.define(ScopeNode.ARG0, TypeInteger.BOT, false, new ProjNode(START, 2, ScopeNode.ARG0).peephole()); + JSViewer.show(); // Parse whole program parseBlock(false); diff --git a/chapter18/src/main/java/com/seaofnodes/simple/SB.java b/chapter18/src/main/java/com/seaofnodes/simple/SB.java new file mode 100644 index 00000000..6f5a29ee --- /dev/null +++ b/chapter18/src/main/java/com/seaofnodes/simple/SB.java @@ -0,0 +1,74 @@ +package com.seaofnodes.simple; + +/** Tight/tiny StringBuilder wrapper. + * Short short names on purpose; so they don't obscure the printing. + * Can't believe this wasn't done long, long ago. */ +public final class SB { + private final StringBuilder _sb; + private int _indent = 0; + public SB( ) { _sb = new StringBuilder( ); } + public SB(String s) { _sb = new StringBuilder(s); } + public SB p( String s ) { _sb.append(s); return this; } + public SB p( float s ) { + if( Float.isNaN(s) ) + _sb.append( "Float.NaN"); + else if( Float.isInfinite(s) ) { + _sb.append(s > 0 ? "Float.POSITIVE_INFINITY" : "Float.NEGATIVE_INFINITY"); + } else _sb.append(s); + return this; + } + public SB p( double s ) { + if( Double.isNaN(s) ) + _sb.append("Double.NaN"); + else if( Double.isInfinite(s) ) { + _sb.append(s > 0 ? "Double.POSITIVE_INFINITY" : "Double.NEGATIVE_INFINITY"); + } else _sb.append(s); + return this; + } + public SB p( char s ) { _sb.append(s); return this; } + public SB p( int s ) { _sb.append(s); return this; } + public SB p( long s ) { _sb.append(s); return this; } + public SB p( boolean s) { _sb.append(s); return this; } + // Not spelled "p" on purpose: too easy to accidentally say "p(1.0)" and + // suddenly call the autoboxed version. + public SB pobj( Object s ) { _sb.append(s.toString()); return this; } + public SB i( int d ) { for( int i=0; i<d+_indent; i++ ) p(" "); return this; } + public SB i( ) { return i(0); } + public SB ip(String s) { return i().p(s); } + public SB s() { _sb.append(' '); return this; } + + // Increase indentation + public SB ii( int i) { _indent += i; return this; } + public SB ii() { return ii(1); } + // Decrease indentation + public SB di( int i) { _indent -= i; return this; } + public SB di() { return di(1); } + + public SB nl( ) { return p(System.lineSeparator()); } + // Last printed a nl + public boolean was_nl() { + int len = _sb.length(); + String nl = System.lineSeparator(); + int nlen = nl.length(); + if( len < nlen ) return false; + for( int i=0; i<nlen; i++ ) + if( _sb.charAt(len-nlen+i)!=nl.charAt(i) ) + return false; + return true; + } + + // Delete last char. Useful when doing string-joins and JSON printing and an + // extra separater char needs to be removed: + // + // sb.p('['); + // for( Foo foo : foos ) + // sb.p(foo).p(','); + // sb.unchar().p(']'); // remove extra trailing comma + // + public SB unchar() { return unchar(1); } + public SB unchar(int x) { _sb.setLength(_sb.length()-x); return this; } + + public SB clear() { _sb.setLength(0); return this; } + public int len() { return _sb.length(); } + @Override public String toString() { return _sb.toString(); } +} diff --git a/chapter18/src/main/java/com/seaofnodes/simple/SimpleWebSocket.java b/chapter18/src/main/java/com/seaofnodes/simple/SimpleWebSocket.java index 86ae7c9b..114bfddd 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/SimpleWebSocket.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/SimpleWebSocket.java @@ -60,7 +60,7 @@ class SimpleWebSocket extends ServerSocket { _len = _in.read(_ins); _x=0; int op = rawget(); if( (op&0x80)!=0x80 ) // FIN bit not set? - throw Utils.TODO("Multi-part from client: "+op); // Multi-part message + throw Utils.TODO("Multi-part from client: "+op); // Multipart message op &= 0x7F; // Strip FIN bit switch( op&15) { case 1: { @@ -89,9 +89,20 @@ class SimpleWebSocket extends ServerSocket { // Classic put to browser client. No encoding. public void put(String msg) throws IOException { - assert msg.length() < 125; - _out.write(129); // FIN - _out.write(msg.length()); + int len = msg.length(); + if( len <= 125 ) { + _out.write(129); // FIN, opcode 1 - whole text message + _out.write(len); + for( int i=0; i<msg.length(); i++ ) + _out.write(msg.charAt(i)); + return; + } + if( len > 65535 ) + throw Utils.TODO("MOAR LENGTH"); + _out.write(129); // FIN, opcode 1 - whole text message + _out.write(126); // Length is 16b + _out.write(len>>>8); + _out.write(len&255); for( int i=0; i<msg.length(); i++ ) _out.write(msg.charAt(i)); } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CProjNode.java index d2f1bbe1..0b9d89d2 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/CProjNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/CProjNode.java @@ -6,7 +6,7 @@ import com.seaofnodes.simple.type.TypeMem; import com.seaofnodes.simple.type.TypeTuple; import java.util.BitSet; -public class CProjNode extends CFGNode { +public class CProjNode extends CFGNode implements MultiUse { // Which slice of the incoming multipart value public final int _idx; @@ -21,6 +21,7 @@ public class CProjNode extends CFGNode { } @Override public String label() { return _label; } + @Override public int idx() { return _idx; } @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/MultiUse.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MultiUse.java new file mode 100644 index 00000000..e4548dfd --- /dev/null +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MultiUse.java @@ -0,0 +1,3 @@ +package com.seaofnodes.simple.node; + +public interface MultiUse { abstract int idx(); } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java index 3827fdac..040e3a0e 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java @@ -1,9 +1,6 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.IRPrinter; -import com.seaofnodes.simple.IterPeeps; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.*; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; import java.util.*; @@ -306,7 +303,7 @@ public abstract class Node implements OutNode { return this; // Peephole optimizations turned off } Node n = peepholeOpt(); - return n==null ? this : deadCodeElim(n.peephole()); // Cannot return null for no-progress + return n==null ? this : deadCodeElim(n._nid >= _nid ? n.peephole() : n); // Cannot return null for no-progress } /** @@ -328,6 +325,13 @@ public abstract class Node implements OutNode { * </ul> */ public final Node peepholeOpt( ) { + JSViewer.show(); + Node n = _peepholeOpt(); + if( n==null ) return null; + JSViewer.show(); + return n; + } + private final Node _peepholeOpt( ) { ITER_CNT++; // Compute initial or improved Type Type old = setType(compute()); diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ProjNode.java index 73c1fa15..525b5df0 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/ProjNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ProjNode.java @@ -6,7 +6,7 @@ import com.seaofnodes.simple.type.TypeTuple; import java.util.BitSet; -public class ProjNode extends Node { +public class ProjNode extends Node implements MultiUse { // Which slice of the incoming multipart value public final int _idx; @@ -21,6 +21,7 @@ public class ProjNode extends Node { } @Override public String label() { return _label; } + @Override public int idx() { return _idx; } @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/StopNode.java index 867225cb..269c2f6c 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/StopNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/StopNode.java @@ -15,6 +15,7 @@ public class StopNode extends CFGNode { public StopNode(String src) { super(); _src = src; + _type = compute(); } @Override |
