package com.cliffc.aa.type; import com.cliffc.aa.util.SB; import com.cliffc.aa.util.VBitSet; import com.cliffc.aa.util.NonBlockingHashMapLong; import java.util.BitSet; import java.util.function.Predicate; // Pointers-to-memory; these can be both the address and the value part of // Loads and Stores. They carry a set of aliased TypeObjs. public final class TypeMemPtr extends Type<TypeMemPtr> { // List of known memory aliases. Zero is nil. public BitsAlias _aliases; public TypeObj _obj; // Meet/join of aliases private TypeMemPtr(BitsAlias aliases, TypeObj obj ) { super (TMEMPTR); init(aliases,obj); } private void init (BitsAlias aliases, TypeObj obj ) { super.init(TMEMPTR); _aliases = aliases; _obj=obj; } @Override int compute_hash() { assert _obj._hash != 0; return TMEMPTR + _aliases._hash + _obj._hash; } @Override public boolean equals( Object o ) { if( this==o ) return true; if( !(o instanceof TypeMemPtr) ) return false; TypeMemPtr tf = (TypeMemPtr)o; return _aliases==tf._aliases && _obj==tf._obj; } @Override public boolean cycle_equals( Type o ) { if( this==o ) return true; if( !(o instanceof TypeMemPtr) ) return false; TypeMemPtr t2 = (TypeMemPtr)o; if( _aliases != t2._aliases ) return false; return _obj == t2._obj || _obj.cycle_equals(t2._obj); } @Override String str( VBitSet dups) { if( dups == null ) dups = new VBitSet(); if( dups.tset(_uid) ) return "$"; // Break recursive printing cycle SB sb = new SB().p('*'); _aliases.toString(sb).p(_obj.str(dups)); if( _aliases.test(0) ) sb.p('?'); return sb.toString(); } @Override SB dstr( SB sb, VBitSet dups ) { sb.p('_').p(_uid); if( dups == null ) dups = new VBitSet(); if( dups.tset(_uid) ) return sb.p('$'); // Break recursive printing cycle sb.p('*'); _obj.dstr(_aliases.toString(sb).p(" -> "),dups); return sb; } private static TypeMemPtr FREE=null; @Override protected TypeMemPtr free( TypeMemPtr ret ) { FREE=this; return ret; } public static TypeMemPtr make(BitsAlias aliases, TypeObj obj ) { // Canonical form: cannot have a pointer with only NIL allowed... instead // we only use NIL directly. assert aliases != BitsAlias.NIL; // Check that a pointer-to-struct does not include more structs than what // is pointed at. Type a2 = obj.base(); // Strip off any 'Names' assert !(a2 instanceof TypeStruct) || aliases.strip_nil()==((TypeStruct)a2)._news // Pointing at same set || aliases.strip_nil()==((TypeStruct)a2)._news.dual(); // Pointing at same set TypeMemPtr t1 = FREE; if( t1 == null ) t1 = new TypeMemPtr(aliases,obj); else { FREE = null; t1.init(aliases,obj); } TypeMemPtr t2 = (TypeMemPtr)t1.hashcons(); return t1==t2 ? t1 : t1.free(t2); } public static TypeMemPtr make( int alias, TypeObj obj ) { BitsAlias aliases = BitsAlias.make0(alias); return make(aliases,narrow_obj(aliases,obj)); } static TypeMemPtr make_nil( int alias, TypeObj obj ) { BitsAlias aliases = BitsAlias.make0(alias); return make(aliases.meet_nil(),narrow_obj(aliases,obj)); } public TypeMemPtr make(TypeObj obj ) { return make(_aliases,obj); } static TypeObj narrow_obj( BitsAlias aliases, TypeObj obj ) { // Check that a pointer-to-struct does not include more structs than what // is pointed at. Type obj2 = obj.base(); // Strip off any 'Names' if( !(obj2 instanceof TypeStruct) ) return obj; // No change TypeStruct ts = (TypeStruct)obj2; BitsAlias a0 = aliases.strip_nil(); if( a0 == ts._news ) return obj; // All good assert aliases.is_contained(ts._news); // narrow pointer, pointing at wide structure. TypeStruct nts = ts.make(a0); // Make a narrower structure return obj.make_base(nts); // Rewrap with any 'Name' wrappers } // Cannot have a NIL here, because a CastNode (JOIN) of a NIL to a "*[4]obj?" // yields a TypeMemPtr.NIL instead of a Type.NIL which confuses all ISA tests // with embedded NILs. //public static final TypeMemPtr NIL = (TypeMemPtr)(new TypeMemPtr(BitsAlias.NIL, TypeObj.XOBJ).hashcons()); public static final TypeMemPtr OOP0 = make(BitsAlias.FULL , TypeObj.OBJ); // Includes nil public static final TypeMemPtr OOP = make(BitsAlias.NZERO , TypeObj.OBJ);// Excludes nil public static final TypeMemPtr STRPTR = make(BitsAlias.STRBITS , TypeStr.STR); public static final TypeMemPtr STR0 = make(BitsAlias.STRBITS0, TypeStr.STR); public static final TypeMemPtr ABCPTR = make(BitsAlias.ABCBITS , TypeStr.ABC); public static final TypeMemPtr ABC0 = make(BitsAlias.ABCBITS0, TypeStr.ABC); static final TypeMemPtr STRUCT = make(BitsAlias.RECBITS , TypeStruct.ALLSTRUCT); public static final TypeMemPtr STRUCT0= make(BitsAlias.RECBITS0, TypeStruct.ALLSTRUCT); private static final TypeMemPtr PNTPTR = make(BitsAlias.RECBITS , TypeName.TEST_STRUCT); private static final TypeMemPtr PNT0 = make(BitsAlias.RECBITS0, TypeName.TEST_STRUCT); static final TypeMemPtr[] TYPES = new TypeMemPtr[]{OOP0,STR0,STRPTR,ABCPTR,STRUCT,ABC0,PNTPTR,PNT0}; @Override protected TypeMemPtr xdual() { if( _aliases==BitsAlias.NIL ) { assert _obj==TypeObj.XOBJ; return this; } return new TypeMemPtr(_aliases.dual(),(TypeObj)_obj.dual()); } @Override TypeMemPtr rdual() { if( _dual != null ) return _dual; TypeMemPtr dual = _dual = new TypeMemPtr(_aliases,(TypeObj)_obj.rdual()); dual._dual = this; dual._hash = dual.compute_hash(); dual._cyclic = true; return dual; } @Override protected Type xmeet( Type t ) { switch( t._type ) { case TMEMPTR:break; case TFLT: case TINT: case TFUNPTR: case TRPC: return cross_nil(t); case TNIL: case TNAME: return t.xmeet(this); // Let other side decide case TOBJ: case TSTR: case TSTRUCT: case TTUPLE: case TFUN: case TMEM: return ALL; default: throw typerr(t); // All else should not happen } // Meet of aliases TypeMemPtr ptr = (TypeMemPtr)t; BitsAlias aliases = _aliases.meet(ptr._aliases); if( aliases == BitsAlias.NIL ) return NIL; return make(aliases, narrow_obj(aliases,(TypeObj)_obj.meet(ptr._obj))); } @Override public boolean above_center() { return _aliases.above_center(); } // Aliases represent *classes* of pointers and are thus never constants. // nil is a constant. @Override public boolean may_be_con() { return may_nil(); } @Override public boolean is_con() { return _aliases==BitsAlias.NIL; } // only nil @Override public boolean must_nil() { return _aliases.test(0) && !above_center(); } @Override public boolean may_nil() { return _aliases.may_nil(); } @Override Type not_nil() { BitsAlias bits = _aliases.not_nil(); return bits==_aliases ? this : make(bits,_obj); } @Override public Type meet_nil() { if( _aliases.test(0) ) // Already has a nil? return _aliases.above_center() ? NIL : this; BitsAlias aliases = _aliases.meet_nil(); return aliases==BitsAlias.NIL ? NIL : make(aliases,_obj); } // Build a depth-limited named type @Override TypeMemPtr make_recur(TypeName tn, int d, VBitSet bs ) { Type t2 = _obj.make_recur(tn,d,bs); return t2==_obj ? this : make(_aliases,(TypeObj)t2); } // Mark if part of a cycle @Override void mark_cycle( Type head, VBitSet visit, BitSet cycle ) { if( visit.tset(_uid) ) return; if( this==head ) { cycle.set(_uid); _cyclic=_dual._cyclic=true; } _obj.mark_cycle(head,visit,cycle); if( cycle.get(_obj._uid) ) { cycle.set(_uid); _cyclic=_dual._cyclic=true; } } @Override boolean contains( Type t, VBitSet bs ) { return _obj == t || _obj.contains(t, bs); } @SuppressWarnings("unchecked") @Override int depth( NonBlockingHashMapLong<Integer> ds ) { return _obj.depth(ds); } @SuppressWarnings("unchecked") @Override void walk( Predicate<Type> p ) { if( p.test(this) ) _obj.walk(p); } @Override TypeStruct repeats_in_cycles(TypeStruct head, VBitSet bs) { return _cyclic ? _obj.repeats_in_cycles(head,bs) : null; } public int getbit() { return _aliases.getbit(); } // Keep the high parts @Override public TypeMemPtr startype() { return TypeMemPtr.make(_aliases.above_center() ? _aliases : _aliases.dual(), _obj.startype()); } }