summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/node/EscapeNode.java
blob: 3e95fffb68bf09f102213583af263ede74cf8c19 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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(); }
}