summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/node/StartNode.java
blob: 84c8a3a7dbf7455825966c9574ffa7c99a75dc26 (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
package com.seaofnodes.simple.node;

import com.seaofnodes.print.ExprPrinter;

import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.Utils;
import java.util.Arrays;
import java.util.HashSet;

/**
 * The Start node represents the external world calling, be it calling the
 * entry <clinit> or just some linked caller calling.
 * <p>
 * Start initially has 1 input (arg) from outside and the initial control.
 * In ch10 we also add mem aliases as structs get defined; each field in struct
 * adds a distinct alias to Start's tuple.
 * <p>
 * By ch25, Start is the external world (or linker) calling with everything
 * that has escaped.  Start is NOT the entry <clinit> itself, which can assume
 * no memory nor fidxs exist nor escaped.  Start gets escaped things from Stop;
 * together these close the Grand Cycle between the code we know and the code
 * we don't.
 */
public class StartNode extends LoopNode implements MultiNode {

    final Type _arg;

    public StartNode(StartNode start, StopNode stop, Type arg) { super(null,start,stop); _arg = arg;  }
    public StartNode(StartNode start) { super(start); _arg = start==null ? null : start._arg; }
    @Override public Tag serialTag() { return Tag.Start; }
    public Type arg() { return _arg; }

    @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
        return p.p(label());
    }

    @Override public CFGNode cfg0() { return null; }

    // Get the one control following; error to call with more than one e.g. an
    // IfNode or other multi-way branch.  For Start, it's the class init for
    // this compilation unit.
    @Override public CFGNode uctrl() {
        // Find module.<clinit>, it's the start.
        CFGNode C = null;
        for( Node use : _outputs )
            if( use instanceof FunNode fun && fun.isModInit() )
                { assert C==null; C = fun; }
        if( C==null )
            for( FunNode fun : CodeGen.CODE._linker )
                if( fun!=null && !fun.isDead() && fun.isModInit() )
                    { assert C==null; C = fun; }
        return C;
    }

    boolean escapedFIDX(int fidx) {
        // Public class fields are callable by the unknown external world
        // regardless of the current SCCP approximation of Start memory.
        if( CodeGen.CODE.publicFIDX(fidx) ) return true;
        if( !(_type instanceof TypeTuple tt) )
            return !_type.isHigh(); // TOP never escapes, BOTTOM always escapes
        TypeMem tmem = (TypeMem)tt._types[1];
        if( tmem == TypeMem.BOT ) return false;
        if( tmem == TypeMem.TOP ) return false;
        if( XInt.isHigh(tmem._escFs) )
            return false;
        return XInt.bit(tmem._escFs,fidx);
    }

    @Override public TypeTuple compute() {
        StopNode stop = (StopNode)in(1);
        TypeMem tmem = stop._type instanceof TypeTuple tt
            ? tt.mem()
            : stop._type.isHigh() ? TypeMem.START : TypeMem.BOT;
        assert tmem._alias==1 && !tmem._one;
        return TypeTuple.make(Type.CONTROL,tmem,_arg);
    }

    @Override public Node idealize() { return null; }

    // No immediate dominator, and idepth==0
    @Override public int idepth() { return 0; }
    @Override public CFGNode idom(Node dep) { return null; }

    @Override public boolean eq( Node n ) { return true; }
}