diff options
Diffstat (limited to 'chapter18/src/main/java/com')
9 files changed, 63 insertions, 79 deletions
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java index f7b7d0e9..1105c2b7 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java @@ -617,7 +617,15 @@ public class Parser { } else { if( inferType && !_scope.inCon() ) throw errorSyntax("=expression"); - expr = t instanceof TypeMemPtr tn ? (tn._nil==3 ? NIL : con(Type.TOP)) : (t==Type.BOTTOM ? con(t) : ZERO); + // Initial value for uninitialized struct fields. + expr = t instanceof TypeMemPtr tn + // Nullable pointers get a NIL; not-null get a TOP which + // signals that they *must* be initialized in the constructor. + ? (tn.nullable() ? NIL : con(Type.TOP)) + // Bottom signals type inference: they must be initialized in + // the constructor and that's when we'll discover the type. + // Otherwise, its an Integer and use 0. + : (t==Type.BOTTOM ? con(t) : ZERO); } // Lift expression, based on type @@ -664,7 +672,7 @@ public class Parser { fs[i-lexlen] = Field.make(v._name,v.type(),ALIAS++,v._final); } TypeStruct ts = s._ts = TypeStruct.make(typeName, fs); - TYPES.put(typeName, TypeMemPtr.make((byte)2,ts)); + TYPES.put(typeName, TypeMemPtr.make(ts)); INITS.put(typeName,s.peephole().keep()); // Done with struct/block scope require("}"); @@ -695,15 +703,15 @@ public class Parser { if( t0 == null && KEYWORDS.contains(tname) ) return posT(old1); if( t0 == Type.BOTTOM || t0 == Type.TOP ) return t0; // var/val type inference - Type t1 = t0 == null ? TypeMemPtr.make((byte)2,TypeStruct.makeFRef(tname)) :t0; // Null: assume a forward ref type + Type t1 = t0 == null ? TypeMemPtr.make(TypeStruct.makeFRef(tname)) :t0; // Null: assume a forward ref type // Nest arrays and '?' as needed Type t2 = t1; while( true ) { if( match("?") ) { if( !(t2 instanceof TypeMemPtr tmp) ) throw error("Type "+t0+" cannot be null"); - if( tmp._nil==3 ) throw error("Type "+t2+" already allows null"); - t2 = tmp.makeFrom((byte)3); + if( tmp.nullable() ) throw error("Type "+t2+" already allows null"); + t2 = tmp.makeNullable(); } else if( match("[]") ) { t2 = typeAry(t2); } else @@ -726,7 +734,7 @@ public class Parser { // Make an array type of t private TypeMemPtr typeAry( Type t ) { - if( t instanceof TypeMemPtr tmp && (tmp._nil==1|| tmp._nil==2) ) + if( t instanceof TypeMemPtr tmp && tmp.notNull() ) throw error("Arrays of reference types must always be nullable"); String tname = "["+t.str()+"]"; Type ta = TYPES.get(tname); @@ -734,7 +742,7 @@ public class Parser { // Need make an array type. TypeStruct ts = TypeStruct.makeAry(TypeInteger.BOT,ALIAS++,t,ALIAS++); assert ts.str().equals(tname); - TypeMemPtr tary = TypeMemPtr.make((byte)2,ts); + TypeMemPtr tary = TypeMemPtr.make(ts); TYPES.put(tname,tary); return tary; } @@ -756,7 +764,7 @@ public class Parser { if( ret==null ) return posT(old); ts.set(0,ret); if( !match("}") ) return posT(old); // Not a function - return TypeFunPtr.make(TypeTuple.make(ts.asAry()),match("?")); + return TypeFunPtr.make(match("?"),TypeTuple.make(ts.asAry())); } Type t1 = type(); if( t1==null ) return posT(old); // Not a function @@ -1059,7 +1067,7 @@ public class Parser { // Initial values for every field for( int i = 0; i < len; i++ ) ns[2+len+i] = init.get(i+idx); - Node nnn = new NewNode(TypeMemPtr.make((byte)2,obj), ns).peephole(); + Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole(); for( int i = 0; i < len; i++ ) memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole()); return new ProjNode(nnn,1,obj._name).peephole(); diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MemOpNode.java index 818d6352..62323031 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/MemOpNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MemOpNode.java @@ -49,7 +49,7 @@ public abstract class MemOpNode extends Node { // Already an error, but better error messages come from elsewhere if( ptr == Type.BOTTOM ) return null; // Better be a not-nil TMP - if( ptr instanceof TypeMemPtr tmp && tmp._nil==2 ) + if( ptr instanceof TypeMemPtr tmp && tmp.notNull() ) return null; return "Might be null accessing '" + _name + "'"; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java index 54defe13..cae6300e 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java @@ -17,7 +17,7 @@ public class NewNode extends Node implements MultiNode { public NewNode(TypeMemPtr ptr, Node... nodes) { super(nodes); - assert ptr._nil!=3; + assert !ptr.nullable(); _ptr = ptr; _len = ptr._obj._fields.length; // Control in slot 0 diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java index d71e0fe6..b454de66 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java @@ -22,7 +22,7 @@ public class NotNode extends Node { Type t0 = in(1)._type; if( t0.isHigh() ) return TypeInteger.BOOL.dual(); if( t0 == Type.NIL || t0 == TypeInteger.ZERO ) return TypeInteger.TRUE; - if( t0 instanceof TypeNil tn && tn._nil==2 ) return TypeInteger.FALSE; + if( t0 instanceof TypeNil tn && tn.notNull() ) return TypeInteger.FALSE; if( t0 instanceof TypeInteger i && (i._min > 0 || i._max < 0) ) return TypeInteger.FALSE; return TypeInteger.BOOL; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java b/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java index 5104f080..9f9f688a 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/Type.java @@ -48,7 +48,7 @@ public class Type { public final byte _type; public boolean is_simple() { return _type < TSIMPLE; } - private static final String[] STRS = new String[]{"Bot","Top","Ctrl","~Ctrl","nil","~nil"}; + private static final String[] STRS = new String[]{"Bot","Top","Ctrl","~Ctrl","null","~nil"}; protected Type(byte type) { _type = type; } public static final Type BOTTOM = new Type( TBOT ).intern(); // ALL diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java index 9d4e5795..0c66c20c 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java @@ -6,113 +6,83 @@ import java.util.ArrayList; /** * Represents a Pointer to a function. - * + * <p></p> * Functions have argument types and a return type, making a function * signature. Within a signature there can be many instances of functions, and * each function is labeled with a small integer constant. A TFP can represent * a single signature and a set of functions; the set might contain only 1 * function or the zeroth function (the null ptr). - * + * <p></p> * Functions with different signatures cannot be mixed, and will result in a * bottom function type, which can only be null-checked. */ -public class TypeFunPtr extends Type { +public class TypeFunPtr extends TypeNil { // A TypeFunPtr is Signature and a set of functions. public final TypeTuple _sig; // Cheesy easy implementation for a small set; 1 bit per unique function // within the TypeTuple. Can be upgraded to a BitSet for larger classes of // functions. - private final long _fidxs; // 0 bit for null, and up to 63 unique functions per signature + private final long _fidxs; // 64 unique functions per signature - private TypeFunPtr(TypeTuple sig, long fidxs) { - super(TFUNPTR); + private TypeFunPtr(byte nil, TypeTuple sig, long fidxs) { + super(TFUNPTR,nil); assert sig != null; _sig = sig; _fidxs = fidxs; } - public static TypeFunPtr make( TypeTuple sig, long fidxs ) { return new TypeFunPtr(sig,fidxs).intern(); } - // Make a TFP with all functions - public static TypeFunPtr make( TypeTuple sig, boolean nil ) { return new TypeFunPtr(sig,-2|(nil ? 1 : 0)).intern(); } + static TypeFunPtr make( byte nil, TypeTuple sig, long fidxs ) { return new TypeFunPtr(nil,sig,fidxs).intern(); } + public static TypeFunPtr make( boolean nil, TypeTuple sig ) { return make((byte)(nil ? 3 : 2),sig,-1); } + @Override TypeFunPtr makeFrom( byte nil ) { return nil==_nil ? this : make(nil,_sig,_fidxs); } - public static TypeFunPtr BOT = make(TypeTuple.SIGBOT,-1); - public static TypeFunPtr TOP = BOT.dual(); - public static TypeFunPtr TEST = make(TypeTuple.SIGTEST,2); - public static TypeFunPtr TEST0 = make(TypeTuple.SIGTEST,3); - public static TypeFunPtr NULLPTR = make(TypeTuple.SIGTOP,1); - public static TypeFunPtr VOIDPTR = NULLPTR.dual(); - public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST0); ts.add(NULLPTR); ts.add(BOT); } + public static TypeFunPtr BOT = make((byte)3,TypeTuple.SIGBOT,-1); + public static TypeFunPtr TEST = make((byte)2,TypeTuple.SIGTEST,1); + public static TypeFunPtr TEST0 = make((byte)3,TypeTuple.SIGTEST,3); + public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST0); ts.add(BOT); } @Override Type xmeet(Type t) { TypeFunPtr that = (TypeFunPtr) t; - return TypeFunPtr.make((TypeTuple)_sig.meet(that._sig), _fidxs | that._fidxs); + return TypeFunPtr.make(xmeet0(that),(TypeTuple)_sig.meet(that._sig), _fidxs | that._fidxs); } @Override - public TypeFunPtr dual() { return TypeFunPtr.make(_sig.dual(), ~_fidxs); } + public TypeFunPtr dual() { return TypeFunPtr.make(dual0(), _sig.dual(), ~_fidxs); } + + // RHS is NIL + @Override public Type meet0() { return _nil==3 ? this : make((byte)3,_sig,_fidxs); } @Override public TypeFunPtr glb() { throw Utils.TODO(); } - // Is forward-reference - @Override public boolean isFRef() { return false; } - @Override public boolean isHigh() { return this==TOP; } @Override public boolean isConstant() { return Long.bitCount(_fidxs)==1; } - @Override public boolean isHighOrConst() { return Long.bitCount(_fidxs)<=1; } @Override public int log_size() { return 2; } // (1<<2)==4-byte pointers @Override - int hash() { return Utils.fold(_sig.hashCode() ^ _fidxs); } + int hash() { return Utils.fold(_sig.hashCode() ^ _fidxs ^ super.hash()); } @Override boolean eq(Type t) { TypeFunPtr ptr = (TypeFunPtr)t; // Invariant - return _sig == ptr._sig && _fidxs == ptr._fidxs; + return _sig == ptr._sig && _fidxs == ptr._fidxs && super.eq(ptr); } - @Override public String str() { - if( this== NULLPTR) return "null"; - if( this== VOIDPTR) return "*void"; - return print(new SB()).toString(); - } - - // [void,name,MANY]*[,?] - @Override public SB print(SB sb) { - if( this== NULLPTR) return sb.p("null"); - if( this== VOIDPTR) return sb.p("*void"); - sb.p("{ "); - for( int i=1; i<_sig._types.length; i++ ) - _sig._types[i].print(sb).p(" "); - _sig._types[0].print(sb.p("-> ")); - sb.p(" #"); - long fidxs = _fidxs&-2; // Strip off the null flag bit - String fidx = fidxs==0 ? "" - : Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs) - : fidxs == -2 ? "ALL" - : "b"+Long.toBinaryString(fidxs); // Just some function bits - sb.p(fidx).p("}"); - if( (_fidxs&1)==1 ) sb.p("?"); - return sb; - } - - @Override public SB gprint(SB sb) { - if( this== NULLPTR) return sb.p("null"); - if( this== VOIDPTR) return sb.p("*void"); - sb.p("{ "); + @Override public String str() { return print(new SB()).toString(); } + @Override public SB print(SB sb) { return _print(sb,false); } + @Override public SB gprint(SB sb) { return _print(sb,true ); } + private static SB _print(SB sb, boolean g, Type t) { return g ? t.gprint(sb) : t.print(sb); } + private SB _print(SB sb, boolean g) { + sb.p(x()).p("{ "); for( int i=1; i<_sig._types.length; i++ ) - _sig._types[i].gprint(sb).p(" "); - _sig._types[0].gprint(sb.p("-> ")); - sb.p(" #"); - long fidxs = _fidxs&-2; // Strip off the null flag bit + _print(sb,g,_sig._types[i]).p(" "); + _print(sb.p("-> "),g,_sig._types[0]).p(" #"); + long fidxs = isHigh() ? ~_fidxs : _fidxs; String fidx = fidxs==0 ? "" : Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs) - : fidxs == -2 ? "ALL" + : fidxs == -1 ? "ALL" : "b"+Long.toBinaryString(fidxs); // Just some function bits - sb.p(fidx).p("}"); - if( (_fidxs&1)==1 ) sb.p("?"); - return sb; + return sb.p(fidx).p("}").p(q()); } } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java index d17cfd39..6dda9c39 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java @@ -31,10 +31,12 @@ public class TypeMemPtr extends TypeNil { assert obj!=null; _obj = obj; } - public static TypeMemPtr make(byte nil, TypeStruct obj) { return new TypeMemPtr(nil, obj).intern(); } - public static TypeMemPtr make(TypeStruct obj) { return make((byte)3, obj); } + static TypeMemPtr make(byte nil, TypeStruct obj) { return new TypeMemPtr(nil, obj).intern(); } + public static TypeMemPtr makeNullable(TypeStruct obj) { return make((byte)3, obj); } + public static TypeMemPtr make(TypeStruct obj) { return new TypeMemPtr((byte)2, obj).intern(); } public TypeMemPtr makeFrom(TypeStruct obj) { return obj==_obj ? this : make(_nil, obj); } - @Override public TypeMemPtr makeFrom(byte nil) { return nil==_nil ? this : make(nil,_obj); } + public TypeMemPtr makeNullable() { return makeFrom((byte)3); } + @Override TypeMemPtr makeFrom(byte nil) { return nil==_nil ? this : make(nil,_obj); } @Override public TypeMemPtr makeRO() { return makeFrom(_obj.makeRO()); } @Override public boolean isFinal() { return _obj.isFinal(); } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java index d8003d50..03c67ce9 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeNil.java @@ -12,7 +12,7 @@ public abstract class TypeNil extends Type { // 1 = high-subclass no nil // 2 = low -subclass no nil // 3 = low -subclass also nil - public final byte _nil; + final byte _nil; TypeNil(byte t, byte nil ) { super(t); _nil = nil; } @@ -48,6 +48,10 @@ public abstract class TypeNil extends Type { @Override public boolean isConstant () { return false; } @Override public boolean isHighOrConst() { return isHigh() || isConstant(); } + + public boolean notNull() { return _nil==1 || _nil==2; } + public boolean nullable() { return _nil==3; } + final String q() { return _nil == 1 || _nil == 2 ? "" : "?"; } final String x() { return isHigh() ? "~" : ""; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeStruct.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeStruct.java index 35bbe36c..ee206579 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeStruct.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeStruct.java @@ -49,7 +49,7 @@ public class TypeStruct extends Type { // Array public static TypeStruct makeAry(TypeInteger len, int lenAlias, Type body, int bodyAlias) { - assert body instanceof TypeInteger || (body instanceof TypeNil tn && tn._nil==3); + assert body instanceof TypeInteger || (body instanceof TypeNil tn && tn.nullable()); return make("[" + body.str() + "]", Field.make("#" ,len , lenAlias,true ), Field.make("[]",body,bodyAlias,false)); |
