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 or just some linked caller calling. *

* 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. *

* By ch25, Start is the external world (or linker) calling with everything * that has escaped. Start is NOT the entry 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 _print1(ExprPrinter 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., 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; } }