summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/node/EscapeNode.java
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-08-10 11:11:18 -0700
committerCliff Click <cliffc@acm.org>2026-10-08 16:52:27 -0700
commitd32f97238c903765dec4e9a9f3cbfa5fd12cded6 (patch)
treea5ac731801ef7066bab6359c4e85c2bdd20082a6 /src/main/java/com/seaofnodes/simple/node/EscapeNode.java
parentb5ebb2032aa04cf4506d533127d373d4cf5a25c6 (diff)
downloadSimple-linear.tar.gz
Simple-linear.zip
Chapter 25: Modules, Separate Compilation, and SSA Constructionlinear
Co-authored-by: Hsiang-Ying Fu <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: fuhsnn <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: Symious <14933944+symious@users.noreply.github.com> Co-authored-by: Jun Kawasaki <jun784@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/main/java/com/seaofnodes/simple/node/EscapeNode.java')
-rw-r--r--src/main/java/com/seaofnodes/simple/node/EscapeNode.java116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/main/java/com/seaofnodes/simple/node/EscapeNode.java b/src/main/java/com/seaofnodes/simple/node/EscapeNode.java
new file mode 100644
index 00000000..3e95fffb
--- /dev/null
+++ b/src/main/java/com/seaofnodes/simple/node/EscapeNode.java
@@ -0,0 +1,116 @@
+package com.seaofnodes.simple.node;
+
+import com.seaofnodes.print.ExprPrinter;
+
+import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.*;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+
+/**
+ * Merge public and private aliases.
+ * 0 - control
+ * 1 - private pointer
+ * 2 - private alias
+ * 3 - public alias
+ */
+public class EscapeNode extends TypeNode {
+
+ public EscapeNode(Field fld, Node self, Node priv, Node pub ) {
+ super(fld,null,self,priv,pub);
+ }
+ public EscapeNode(EscapeNode esc ) {
+ super(esc); // Copy constructor
+ // Except we do not want/need self ptr past Opto.
+ // *NOTE* the weird direct stomp; this is correct because this
+ // constructor does NOT set the backedges, because it is used to
+ // copy-construct an entire graph and ALL edges will get rewritten.
+ _inputs.set(1,null);
+ _con = esc._con;
+ }
+
+ // Pointer to some private (unescaped) memory from a NewNode
+ public Node self() { return in(1); }
+ public Node priv() { return in(2); }
+ public Node pub () { return in(3); }
+ public Field fld() { return (Field)_con; }
+
+ @Override public Tag serialTag() { return Tag.Escape; }
+ @Override public void packed( BAOS baos, HashMap<String,Integer> strs, HashMap<Type,Integer> types, IdentityHashMap<Node, Integer> anodes ) {
+ baos.packed2(types.get(_con));
+ }
+ static Node make( BAOS bais, Type[] types) {
+ return new EscapeNode((Field)types[bais.packed2()], null,null,null);
+ }
+
+ @Override
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Esc#").p(fld()._alias).p(" {");
+ if( self()==null ) p.p("---");
+ else p.n(self()).p(",");
+ p.n(priv()).p("}, ");
+ p.n(pub ());
+ return p;
+ }
+
+ @Override
+ public Type compute() {
+ if( priv()._type.isHigh() ) return TypeMem.TOP;
+ if( pub ()._type.isHigh() ) return TypeMem.TOP;
+ TypeMem mpriv = (TypeMem)priv()._type;
+ TypeMem mpub = (TypeMem)pub ()._type;
+ // Private memory comes from an allocation or other non-aliased source.
+ // Public memory comes from anywhere, might be bulk memory with a very weak mem type.
+ Field fld = fld();
+ assert mpriv._alias==1 || mpriv._alias==fld._alias;
+ assert mpub ._alias==1 || mpub ._alias==fld._alias;
+ Type tpriv = mpriv._t instanceof TypeStruct ts && ts.findAlias(fld._alias)!=-1
+ ? ts.at(ts.findAlias(fld._alias))._t
+ : mpriv._t;
+ assert !(mpub._t instanceof TypeStruct); // Never expect this, but if it starts to happen, need to optimize
+ Type tpub = mpub._t;
+
+ // t is meet of pub & priv. Pub memory can be very weak (e.g. alias 1)
+ // and we're no worse than the declared field type
+ Type t = tpriv.meet(tpub).join(fld._t);
+ int[] fidxes = XInt.meet(mpriv._escFs, mpub._escFs);
+ int[] aliases = XInt.meet(mpriv._escAs, mpub._escAs);
+ return TypeMem.make(fld._alias, t, false, false, fld._final, fidxes, aliases).escapesFrom(t);
+ }
+
+ @Override public Node idealize() {
+ // Sharpen private memory input
+ if( priv() instanceof MemMergeNode mmm ) {
+ setDef(2,mmm.alias(fld()._alias));
+ return this;
+ }
+ // Sharpen public memory input
+ if( pub() instanceof MemMergeNode mmm ) {
+ setDef(3,mmm.alias(fld()._alias));
+ return this;
+ }
+ // New allocation is dead
+ if( self()._type.isHigh() )
+ if( pub()._type.isa(_type) ) return pub();
+ else addDep(pub());
+ return null;
+ }
+
+// Upgrade the internal type
+@Override boolean _upgradeType( HashMap<String,Type> TYPES) {
+ Type t = _con.upgradeType(TYPES);
+ if( t == _con ) return false;
+ unlock(); // Unlock before changing _con
+ _con = t;
+ return true;
+}
+
+ @Override public boolean eq(Node n) {
+ if( fld()._alias!=((EscapeNode)n).fld()._alias )
+ return false;
+ assert _con == ((EscapeNode)n)._con;
+ return true;
+ }
+
+ @Override int hash() { return _con.hashCode(); }
+}