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; }
}
|