package com.sun.tools.javac.code; import static com.sun.tools.javac.code.Kinds.MTH; import com.sun.tools.javac.code.Symbol.RegionNameSymbol; import com.sun.tools.javac.code.Symbol.RegionParameterSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Type.TypeVar; import com.sun.tools.javac.tree.JCTree.DPJNegationExpression; import com.sun.tools.javac.tree.JCTree.JCBinary; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCLiteral; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Pair; /** * A class to represent RPL elements. There is one inner class for each type of * RPL element. * * @author Rob Bocchino */ public abstract class RPLElement { // THE RPLElement API /** * Whether the element is atomic */ public boolean isAtomic() { return false; } /** * Whether the element is fully specified (i.e., contains no * or [?]). */ public boolean isFullySpecified() { return true; } /** * Whether the element is a local region name */ public boolean isLocalName() { return false; } /** * Whether the element is included in another element. Used in determining * inclusion of RPLs. */ public boolean isIncludedIn(RPLElement e) { return this.equals(e) || e == STAR; } /** * Whether the element is disjoint from another element, given constraints. * Used in determining disjointness of RPLs. */ public boolean isDisjointFrom(RPLElement e, RPLs rpls, List<Pair<RPL,RPL>> constraints) { return !this.equals(e); } /** * An RPL that bounds this element from above, used in the disjointness test. */ public RPL upperBound() { return new RPL(this); } /** * The symbol corresponding to this RPL element, if any */ public Symbol getSymbol() { return null; } // SINGLE-INSTANCE CLASSES /** The RPL element Root. */ public static final RPLElement ROOT_ELEMENT = new RPLElement() { @Override public String toString() { return "Root"; } public boolean isDisjointFrom(RPLElement e, RPLs rpls, List<Pair<RPL,RPL>> constraints) { if (e instanceof RPLCaptureParameter) { return rpls.areDisjoint(((RPLCaptureParameter) e).includedIn, RPLs.ROOT, constraints); } return e != ROOT_ELEMENT; } }; /** The RPL element Local. */ public static final RPLElement LOCAL_ELEMENT = new RPLElement() { @Override public String toString() { return "Local"; } public boolean isDisjointFrom(RPLElement e, RPLs rpls, List<Pair<RPL,RPL>> constraints) { if (e == LOCAL_ELEMENT) return false; if (e instanceof RPLCaptureParameter) { return !(((RPLCaptureParameter) e).includedIn.isUnderLocal()); } return e != LOCAL_ELEMENT; } @Override public boolean isLocalName() { return true; } }; /** * The RPL element *. */ public static final RPLElement STAR = new RPLElement() { @Override public String toString() { return "*"; } public boolean isFullySpecified() { return false; } public boolean isDisjointFrom(RPLElement e, RPLs rpls, List<Pair<RPL,RPL>> constraints) { return false; } }; // MULTIPLE-INSTANCE CLASSES /** A name RPL element */ public static class NameRPLElement extends RPLElement { /** * The region name symbol representing the name of this element */ public final RegionNameSymbol sym; @Override public Symbol getSymbol() { return sym; } public NameRPLElement(RegionNameSymbol sym) { this.sym = sym; } @Override public boolean isAtomic() { return sym.isAtomic; } @Override public boolean isLocalName() { return (sym.owner.kind == MTH); } public boolean isDisjointFrom(RPLElement e, RPLs rpls, List<Pair<RPL, RPL>> constraints) { if (e instanceof NameRPLElement) { return this.sym != ((NameRPLElement)e).sym; } return e.isDisjointFrom(this, rpls, constraints); } public String toString() { return sym.toString(); } public boolean equals(Object o) { if (o instanceof NameRPLElement) { return this.sym == ((NameRPLElement) o).sym; } return false; } } /** An RPL parameter element */ public static class RPLParameterElement extends RPLElement { /** * The region parameter symbol of this element */ public RegionParameterSymbol sym; @Override public Symbol getSymbol() { return sym; } @Override public boolean isAtomic() { return sym.isAtomic; } /** RPL in which this parameter is included -- used for capture parameters */ public RPL includedIn; public RPLParameterElement(RegionParameterSymbol sym, RPL includedIn) { this.sym = sym; this.includedIn = includedIn; } public RPLParameterElement(RegionParameterSymbol sym) { this.sym = sym; } public boolean isDisjointFrom(RPLElement e, RPLs rpls, List<Pair<RPL, RPL>> constraints) { return false; } @Override public boolean equals(Object o) { if (o instanceof RegionParameterSymbol) return this.sym == o; if (o instanceof RPLParameterElement) return this.sym == ((RPLParameterElement) o).sym; return false; } @Override public String toString() { return sym.toString(); } } /** An array index RPL element. */ public static class ArrayIndexRPLElement extends RPLElement { public JCExpression indexExp; public ArrayIndexRPLElement(JCExpression indexExp) { this.indexExp = indexExp; } @Override public String toString() { return "[" + ((indexExp == null) ? "?" : indexExp) + "]"; } public boolean equals(Object o) { if (!(o instanceof ArrayIndexRPLElement)) return false; ArrayIndexRPLElement that = (ArrayIndexRPLElement) o; return areAlwaysEqualExprs(this.indexExp, that.indexExp); } public boolean isIncludedIn(RPLElement that) { if (that instanceof ArrayIndexRPLElement) { // this is included in [?] ArrayIndexRPLElement ae = (ArrayIndexRPLElement) that; if (ae.indexExp == null) return true; } return super.isIncludedIn(that); } public boolean isDisjointFrom(RPLElement e, RPLs rpls, List<Pair<RPL,RPL>> constraints) { if (this.isIncludedIn(e) || e.isIncludedIn(this)) return false; if (!(e instanceof ArrayIndexRPLElement)) return true; return areNeverEqualExprs(indexExp, ((ArrayIndexRPLElement) e).indexExp); } public boolean isFullySpecified() { return indexExp != null; } public static boolean areAlwaysEqualExprs(JCExpression first, JCExpression second) { if (first instanceof JCBinary && second instanceof JCBinary) { JCBinary firstBinary = (JCBinary) first; JCBinary secondBinary = (JCBinary) second; if (firstBinary.operator != secondBinary.operator) { return false; } return (areAlwaysEqualExprs(firstBinary.lhs, secondBinary.lhs) && areAlwaysEqualExprs(firstBinary.rhs, secondBinary.rhs)); } if (first instanceof JCLiteral && second instanceof JCLiteral) { return ((JCLiteral) first).getValue().equals(((JCLiteral) second).getValue()); } if (first instanceof JCIdent && second instanceof JCIdent) { Symbol firstSymbol = ((JCIdent) first).sym; Symbol secondSymbol = ((JCIdent) second).sym; if (firstSymbol != secondSymbol) return false; if ((firstSymbol.flags() & Flags.FINAL) != 0) return true; return false; } if (first instanceof JCFieldAccess && second instanceof JCFieldAccess) { JCFieldAccess fa1 = (JCFieldAccess) first; JCFieldAccess fa2 = (JCFieldAccess) second; return areAlwaysEqualExprs(fa1.selected, fa2.selected) && fa1.sym == fa2.sym; } return first == second; } public static boolean areNeverEqualExprs(JCExpression first, JCExpression second) { if (first instanceof JCLiteral && second instanceof JCLiteral) { return !((JCLiteral) first).getValue().equals(((JCLiteral) second).getValue()); } if (first instanceof DPJNegationExpression) { return areNeverEqualExprs(second, first); } else if (!(first instanceof DPJNegationExpression) && second instanceof DPJNegationExpression){ if (first.getSymbol() == second.getSymbol()) return true; } return false; } } /** A class for final local variable RPL elements, also called "z region" RPL * elements. */ public static class VarRPLElement extends RPLElement { /** The symbol for the associated variable */ public Symbol.VarSymbol vsym; @Override public Symbol getSymbol() { return vsym; } /** Construct a variable RPL element, given the underlying variable * symbol. */ public VarRPLElement(Symbol.VarSymbol vsym) { this.vsym = vsym; } @Override public RPL upperBound() { if (vsym.type instanceof TypeVar) { TypeVar tvar = (TypeVar) vsym.type; } return new RPL(vsym.type.getOwner().elts.append(STAR)); } public String toString() { return vsym.toString(); } public boolean equals(Object o) { if (!(o instanceof VarRPLElement)) return false; VarRPLElement vrs = (VarRPLElement) o; if (vsym.name.toString().equals("this")) { return vrs.vsym.name.toString().equals("this"); } return vsym.equals(vrs.vsym); } public boolean isDisjointFrom(RPLElement e, RPLs rpls, List<Pair<RPL, RPL>> constraints) { return false; } } // INTERNAL-USE RPL ELEMENTS // These elements are used by the type checker but do not correspond to // anything in the programmer-visible DPJ syntax. /** * Capture parameter of an RPL. When a type is captured, its partially * specified RPLs turn into these parameters. See the tech report for * more details. */ public static class RPLCaptureParameter extends RPLElement { /** * RPL this parameter is included in */ public RPL includedIn; public RPLCaptureParameter(RPL includedIn) { this.includedIn = includedIn; } @Override public RPL upperBound() { return includedIn; } public String toString() { return "capture of (" + includedIn.toString() + ")"; } } /** A class for undetermined region parameters, used during parameter inference * in resolving call sites. */ public static class UndetRPLParameterElement extends RPLParameterElement { public UndetRPLParameterElement(RegionParameterSymbol sym) { super(sym, new RPL(List.<RPLElement>of(RPLElement.ROOT_ELEMENT, RPLElement.STAR))); } public String toString() { return sym + "? under " + includedIn; } } /** * A region on the stack. Used to make sure that stack accesses don't * interfere across parallel sections. */ public static class StackRPLElement extends RPLElement { /** * Stack variable that this RPL element represents */ public VarSymbol sym; @Override public Symbol getSymbol() { return sym; } public static RPL RPL(Symtab syms, VarSymbol sym) { return new RPL(List.<RPLElement>of(new StackRPLElement(sym))); } public StackRPLElement(VarSymbol sym) { this.sym = sym; } public boolean equals(Object o) { if (!(o instanceof StackRPLElement)) return false; return this.sym == ((StackRPLElement) o).sym; } public String toString() { return "stack region of " + sym; } @Override public boolean isLocalName() { return true; } } }