summaryrefslogtreecommitdiff
path: root/chapter18/src/main/java/com/seaofnodes
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-01-06 09:53:05 -0800
committerCliff Click <cliffc@acm.org>2025-01-15 15:07:30 -0800
commit56d346ce2cb7c5ee4ab59e3d403d52d030670eca (patch)
tree4d2a7310e36eb4e70bb3317f78abfac4e76474a1 /chapter18/src/main/java/com/seaofnodes
parent4688bd4a724d2cb6f28d8e8233b8e70f268873d5 (diff)
downloadSimple-56d346ce2cb7c5ee4ab59e3d403d52d030670eca.tar.gz
Simple-56d346ce2cb7c5ee4ab59e3d403d52d030670eca.zip
JSView for functions
Constants use glabel in JSView. TypeFunPtr gprint uses "&rarr;" instead of "->"
Diffstat (limited to 'chapter18/src/main/java/com/seaofnodes')
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java1
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java90
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/Parser.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java4
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/FunNode.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java2
7 files changed, 66 insertions, 44 deletions
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java b/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java
index bd56110c..47616b51 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java
@@ -42,6 +42,7 @@ public class CodeGen {
Node._disablePeephole = disable;
_stop = P.parse();
_start = Parser.START; // Capture global start
+ JSViewer.show();
P = null; // No longer parsing
return this;
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java b/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java
index adbe9f30..7422767a 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java
@@ -24,7 +24,7 @@ public class JSViewer implements AutoCloseable {
static CodeGen CODE; //
JSViewer() throws Exception {
- // Launch server; hand shake
+ // Launch server; handshake
SERVER = new SimpleWebSocket(Paths.get("docs/index.html").toUri(),12345) ;
}
@@ -35,7 +35,7 @@ public class JSViewer implements AutoCloseable {
switch( src ) {
case null: return;
case "null": return;
- case "+": break; // Client requests more frames, but we send them all anyways
+ case "+": break; // Client requests more frames, but we send them all anyway
default:
System.out.println(src);
try {
@@ -69,6 +69,9 @@ public class JSViewer implements AutoCloseable {
public static void show() { if( SERVER!=null && SHOW ) _show(); }
private static void _show() {
boolean midParse = CODE.P!=null;
+ // Skip util we at least get the Parse object made
+ if( !midParse && (CODE._phase==null || CODE._phase == CodeGen.Phase.Parse) )
+ return;
Stack<ScopeNode> xScopes = midParse ? CODE.P._xScopes : null;
Collection<Node> all = GraphVisualizer.findAll(xScopes, CODE._stop, midParse ? CODE.P._scope: null);
@@ -130,11 +133,11 @@ public class JSViewer implements AutoCloseable {
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 MemMergeNode || n==Parser.XCTRL )
+ for( Node n : all ) {
+ if( n instanceof ProjNode || n instanceof CProjNode || n instanceof MemMergeNode )
continue; // Do not emit, rolled into MultiNode or Scope cluster already
sb.i().p(n.uniqueName()).p(" [ ");
- if( n instanceof MultiNode ) {
+ if( n instanceof MultiNode && !(n instanceof StartNode) ) {
// 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");
@@ -184,14 +187,15 @@ public class JSViewer implements AutoCloseable {
private static void scope( SB sb, ScopeNode scope ) {
sb.i().p("node [shape=plaintext];\n");
int last = scope.nIns();
- int max = scope._lexSize.size();
+ int max = scope._lexSize.size()+1; // One more than lexsize
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");
- int lexStart=scope._lexSize.at(level);
+ int lexStart = level==0 ? 0 : scope._lexSize.at(level-1);
+
// Special for memory ScopeMinNode
MemMergeNode n = scope.nIns()>1 ? scope.mem() : null;
if( level==0 && n!=null && n.nIns()>2 ) {
@@ -200,10 +204,12 @@ public class JSViewer implements AutoCloseable {
cell(sb,"#"+m,n.alias(m),"m"+m);
sb.p("</TR>\n"); // End scope level
}
+
// Scope variables, empty if none
if( lexStart<last ) {
sb.i().p("<TR>\n");
for( int j=lexStart; j<last; j++ ) {
+ if( scope.in(j)==null ) continue;
var v = scope._vars.at(j);
cell(sb.i(),v._name,scope.in(j),makePortName(scopeName, v._name)).nl();
}
@@ -223,27 +229,48 @@ public class JSViewer implements AutoCloseable {
// Append a cell, with color
private static SB cell(SB sb, String text, Node n, String port) {
- boolean dark=false;
sb.p("<TD");
- if( n instanceof CFGNode ) sb.p(" BGCOLOR=\"yellow\"");
- if( n instanceof NewNode ) sb.p(" BGCOLOR=\"lightgreen\"");
- if( n instanceof StructNode ) sb.p(" BGCOLOR=\"lightgreen\"");
- if( n.isMem() ) { sb.p(" BGCOLOR=\"blue\""); dark=true; }
- if( n._type instanceof TypeMemPtr ) { sb.p(" BGCOLOR=\"green\""); dark=true; }
- if( n._type instanceof TypeInteger ) sb.p(" BGCOLOR=\"lightblue\"");
+ String color = color(n);
+ sb.p(" BGCOLOR=\"").p(color).p("\"");
if( port!=null ) sb.p(" PORT=\"").p(port).p("\"");
- return colorcell(sb.p(">"),text,n,dark).p("</TD>");
+ return colorcell(sb.p(">"),text,n,dark(color)).p("</TD>");
}
private static SB node(SB sb, String text, Node n) {
- boolean dark=false;
- if( n instanceof CFGNode ) sb.p("style=filled fillcolor=yellow shape=box ");
- if( n instanceof PhiNode ) sb.p("style=filled fillcolor=lightyellow ");
- if( n instanceof StructNode) sb.p("style=filled fillcolor=lightgreen ");
- if( n.isMem() ) { sb.p("style=filled fillcolor=blue "); dark=true; }
- if( n._type instanceof TypeMemPtr ) { sb.p("style=filled fillcolor=green "); dark=true; }
- if( n._type instanceof TypeInteger ) sb.p("style=filled fillcolor=lightblue ");
- return colorcell(sb.p("label=<"),text,n,dark).p(">");
+ String color = color(n);
+ sb.p("style=filled fillcolor=").p(color).p(" ");
+ String shape = switch( n ) {
+ case FunNode fun -> "shape=box peripheries=2";
+ case CFGNode cfg -> "shape=box";
+ default -> "";
+ };
+ sb.p(shape).p(" ");
+ return colorcell(sb.p("label=<"),text,n,dark(color)).p(">");
}
+
+ private static String color(Node n) {
+ return switch( n ) {
+ case CFGNode cfg -> "yellow";
+ case NewNode nnn -> "lightgreen";
+ case StructNode s -> "lightgreen";
+ default -> typeColor(n._type);
+ };
+ }
+ private static String typeColor(Type t) {
+ return t==null ? "white" : switch( t ) {
+ case TypeMem mem -> "blue";
+ case TypeMemPtr tmp -> "green";
+ case TypeFunPtr tfp -> "orange";
+ case TypeRPC rpc -> "antiquewhite";
+ case TypeInteger ti -> "lightblue";
+ case TypeFloat tf -> "aqua";
+ case Type tn -> tn==Type.NIL ? "lightgray" : "red";
+ };
+ }
+ private static final String[] DARKS = new String[]{"blue","green","black"};
+ private static boolean dark(String color) { return Utils.find(DARKS,color) != -1; }
+
+
+
// Called with an open div
private static SB colorcell(SB sb, String text, Node n, boolean dark) {
if( dark ) sb.p("<font color=\"white\">");
@@ -313,19 +340,14 @@ public class JSViewer implements AutoCloseable {
if( (n.iskeep() || n.isUnused()) && scopeName != null ) {
sb.i().p(scopeName).p(" -> ").p(n.uniqueName()).p(" [ style=dashed color=grey];\n");
}
+ // Force functions above return
+ if( n instanceof ReturnNode ret && ret.inProgress() && !ret.fun().isDead() )
+ sb.i().p(ret.ctrl().uniqueName()).p(" -> ").p(ret.fun().uniqueName()).p("[style=invis]\n");
}
}
private static void nodeEdgeColor(SB sb, Type t) {
- String color = switch( t ) {
- case TypeMem mem -> "blue";
- case TypeMemPtr ptr -> "green";
- case TypeInteger ti -> "lightblue";
- // control edges are colored red
- default -> (t==Type.CONTROL || t==Type.XCONTROL) ? "red" : null;
- };
- if( color!=null )
- sb.p(" color=").p(color);
+ sb.p(" color=").p(typeColor(t));
}
// Walk the scope edges
@@ -333,14 +355,14 @@ public class JSViewer implements AutoCloseable {
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
+ if( v._idx==1 ) continue; // Memory done separately
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);
+ String scopeName = makeScopeName(scope, level);
sb.i()
.p(scopeName).p(":")
.p('"').p(makePortName(scopeName, v._name)).p('"') // wrap port name with quotes because $ctrl is not valid unquoted
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
index e518d2a0..dc8f042a 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
@@ -170,7 +170,6 @@ public class Parser {
init.unkeep().kill();
INITS.clear();
STOP.peephole();
- JSViewer.show();
if( show ) showGraph();
return STOP;
}
@@ -194,11 +193,11 @@ public class Parser {
Node rpc = new ParmNode("$rpc",0,TypeRPC.BOT,fun,con(TypeRPC.BOT)).peephole();
// Build a multi-exit return point for all function returns
- RegionNode r = new RegionNode((Node)null,null);
+ RegionNode r = new RegionNode((Node)null,null).init();
assert r.inProgress();
- PhiNode rmem = new PhiNode(ScopeNode.MEM0,TypeMem.BOT,r,null);
- PhiNode rrez = new PhiNode(ScopeNode.ARG0,Type.BOTTOM,r,null);
- ReturnNode ret = new ReturnNode(r, rmem, rrez, rpc, fun);
+ PhiNode rmem = new PhiNode(ScopeNode.MEM0,TypeMem.BOT,r,null).init();
+ PhiNode rrez = new PhiNode(ScopeNode.ARG0,Type.BOTTOM,r,null).init();
+ ReturnNode ret = new ReturnNode(r, rmem, rrez, rpc, fun).init();
fun.setRet(ret);
assert ret.inProgress();
STOP.addDef(ret);
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index e54797a5..e03bfb0e 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -31,8 +31,8 @@ public class ConstantNode extends Node {
return new ConstantNode(type);
}
- @Override
- public String label() { return "#"+_con; }
+ @Override public String label() { return "#"+_con; }
+ @Override public String glabel() { return _con.gprint(new SB().p("#")).toString(); }
@Override
public String uniqueName() { return "Con_" + _nid; }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/FunNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/FunNode.java
index 2d01b4d4..3e426ebe 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/FunNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/FunNode.java
@@ -19,7 +19,7 @@ public class FunNode extends RegionNode {
public FunNode( Parser.Lexer loc, StartNode start, TypeFunPtr sig ) { super(loc,null,start); _sig=sig; }
@Override
- public String label() { return _sig._name; }
+ public String label() { return _sig._name == null ? "$fun" : _sig._name; }
// Find the one CFG user from Fun. It's not always the Return, but always
// the Return *is* a CFG user of Fun.
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 727f7bbf..408c8195 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -160,7 +160,7 @@ public class ScopeNode extends MemMergeNode {
_vars.add(v);
// Creating a forward reference
if( init==Parser.XCTRL )
- init = new FRefNode(v).peephole();
+ init = new FRefNode(v).init();
addDef(init);
return true;
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
index f0dc36a7..9e2cec07 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
@@ -110,7 +110,7 @@ public class TypeFunPtr extends TypeNil {
else {
for( Type t : _sig._types )
_print(sb,g,t).p(" ");
- _print(sb.p("-> "),g,_ret).p(" #");
+ _print(sb.p(g ? "&rarr; " : "-> "),g,_ret).p(" #");
long fidxs = isHigh() ? ~_fidxs : _fidxs;
String fidx = fidxs==0 ? ""
: Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs)