summaryrefslogtreecommitdiff
path: root/chapter25
diff options
context:
space:
mode:
Diffstat (limited to 'chapter25')
-rw-r--r--chapter25/Makefile7
-rw-r--r--chapter25/pom.xml3
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java74
3 files changed, 84 insertions, 0 deletions
diff --git a/chapter25/Makefile b/chapter25/Makefile
index 08b7ce56..886354d3 100644
--- a/chapter25/Makefile
+++ b/chapter25/Makefile
@@ -65,6 +65,10 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java $(SRC
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
simple_driver := $(TST)/$(SIMPLE)/Simple.java
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
+# Compile the common adapter into this chapter without copying its sources.
+GRAPH_DIR := $(firstword $(wildcard ../graph graph))
+graph_javas := $(wildcard $(GRAPH_DIR)/src/main/java/com/seaofnodes/graph/*.java)
+main_javas += $(graph_javas)
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
# These tests do not rely on the stdlib
test_alone := com.seaofnodes.simple.BrainFuckTest com.seaofnodes.simple.MergeSortTest com.seaofnodes.simple.TypeTest
@@ -100,6 +104,9 @@ endif
default: $(default_targets)
+.PHONY: build
+build: $(CLZDIR)/main/.mtag
+
#######################################################
# Compile Java as a whole source set. javac tracks Java dependencies
# internally, so compiling only the directly out-of-date .java files can leave
diff --git a/chapter25/pom.xml b/chapter25/pom.xml
index 6a59188f..7a2b2b78 100644
--- a/chapter25/pom.xml
+++ b/chapter25/pom.xml
@@ -11,4 +11,7 @@
<artifactId>chapter23</artifactId>
<packaging>jar</packaging>
<name>Chapter 23</name>
+ <properties>
+ <simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ </properties>
</project>
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
new file mode 100644
index 00000000..592abb5c
--- /dev/null
+++ b/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -0,0 +1,74 @@
+package com.seaofnodes.simple.print;
+
+import com.seaofnodes.graph.GraphAdapter;
+import com.seaofnodes.graph.GraphSnapshot;
+import com.seaofnodes.graph.GraphSnapshot.*;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.type.TypeMem;
+import java.util.ArrayList;
+
+/** Chapter 25's view of the IR, including partially constructed parse-time graphs. */
+public class SimpleGraphAdapter extends GraphAdapter<Node> {
+ @Override protected int id(Node n) { return n._nid; }
+ @Override protected int nIns(Node n) { return n.nIns(); }
+ @Override protected Node in(Node n, int idx) { return n.in(idx); }
+ @Override protected int nOuts(Node n) { return n.nOuts(); }
+ @Override protected Node out(Node n, int idx) { return n.out(idx); }
+
+ private ArrayList<Edge> edges(Node n) {
+ var edges = new ArrayList<Edge>();
+ for( int i = 0; i < n.nIns(); i++ ) {
+ String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ ? scope.var(i)._name : null;
+ edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
+ }
+ return edges;
+ }
+
+ @Override protected GraphSnapshot.Node desc(Node n) {
+ Projection proj = n instanceof Proj p
+ ? new Projection(n.nIns() == 0 ? 0 : ref(n.in(0)), p.idx()) : null;
+ String label = n.label();
+ return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
+ n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
+ }
+
+ private Kind kind(Node n) {
+ if( n instanceof ScopeNode ) return Kind.SCOPE;
+ if( n instanceof StartCUNode || n instanceof StopCUNode ) return Kind.UNIT;
+ if( n instanceof FunNode ) return Kind.FUN;
+ // Start inherits Loop for whole-program analysis, but is not a source loop.
+ if( n instanceof StartNode ) return Kind.CTRL;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof CFGNode ) return Kind.CTRL;
+ return isMem(n) ? Kind.MEM : Kind.DATA;
+ }
+
+ private Role role(Node n, int i) {
+ if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof FunPtrNode ||
+ n instanceof CtrlNode || n instanceof XCtrlNode )
+ return Role.ASSOC;
+ if( n instanceof PhiNode )
+ return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
+ if( n instanceof Proj )
+ return n instanceof CFGNode ? Role.CTRL : isMem(n) ? Role.MEM : Role.DATA;
+ if( n instanceof RegionNode && i == 0 ) return Role.ASSOC;
+ // Preserve known slot roles even when an input is not attached/typed yet.
+ if( i == 0 || n instanceof RegionNode || n instanceof StopNode ) return Role.CTRL;
+ if( n instanceof MemMergeNode ||
+ i == 1 && (n instanceof MemOpNode || n instanceof ReturnNode || n instanceof CallNode) ||
+ n instanceof EscapeNode && i >= 2 ) return Role.MEM;
+ Node def = n.in(i);
+ if( def instanceof CFGNode ) return Role.CTRL;
+ if( def != null && isMem(def) ) return Role.MEM;
+ return Role.DATA;
+ }
+
+ private boolean isMem(Node n) {
+ // These Phi subclasses are memory even before their first type computation.
+ return n instanceof MemPhiNode || n instanceof BulkMemPhiNode || n.isMem() || n._type instanceof TypeMem;
+ }
+}