8010923: Avoid redundant speculative attribution
Summary: Add optimization to avoid speculative attribution for certain argument expressions
Reviewed-by: jjg
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Apr 15 14:17:30 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Apr 15 14:18:30 2013 +0100
@@ -148,6 +148,7 @@
varInfo = new ResultInfo(VAR, Type.noType);
unknownExprInfo = new ResultInfo(VAL, Type.noType);
unknownTypeInfo = new ResultInfo(TYP, Type.noType);
+ unknownTypeExprInfo = new ResultInfo(Kinds.TYP | Kinds.VAL, Type.noType);
recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
}
@@ -559,6 +560,7 @@
final ResultInfo varInfo;
final ResultInfo unknownExprInfo;
final ResultInfo unknownTypeInfo;
+ final ResultInfo unknownTypeExprInfo;
final ResultInfo recoveryInfo;
Type pt() {
@@ -667,7 +669,7 @@
List<Type> attribArgs(List<JCExpression> trees, Env<AttrContext> env) {
ListBuffer<Type> argtypes = new ListBuffer<Type>();
for (JCExpression arg : trees) {
- Type argtype = allowPoly && TreeInfo.isPoly(arg, env.tree) ?
+ Type argtype = allowPoly && deferredAttr.isDeferred(env, arg) ?
deferredAttr.new DeferredType(arg, env) :
chk.checkNonVoid(arg, attribExpr(arg, env, Infer.anyPoly));
argtypes.append(argtype);
@@ -2989,7 +2991,8 @@
Env<AttrContext> localEnv = env.dup(tree);
//should we propagate the target type?
final ResultInfo castInfo;
- final boolean isPoly = TreeInfo.isPoly(tree.expr, tree);
+ JCExpression expr = TreeInfo.skipParens(tree.expr);
+ boolean isPoly = expr.hasTag(LAMBDA) || expr.hasTag(REFERENCE);
if (isPoly) {
//expression is a poly - we need to propagate target type info
castInfo = new ResultInfo(VAL, clazztype, new Check.NestedCheckContext(resultInfo.checkContext) {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Apr 15 14:17:30 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Apr 15 14:18:30 2013 +0100
@@ -800,4 +800,219 @@
}
}
}
+
+ /**
+ * Does the argument expression {@code expr} need speculative type-checking?
+ */
+ boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
+ DeferredChecker dc = new DeferredChecker(env);
+ dc.scan(expr);
+ return dc.result.isPoly();
+ }
+
+ /**
+ * The kind of an argument expression. This is used by the analysis that
+ * determines as to whether speculative attribution is necessary.
+ */
+ enum ArgumentExpressionKind {
+
+ /** kind that denotes poly argument expression */
+ POLY,
+ /** kind that denotes a standalone expression */
+ NO_POLY,
+ /** kind that denotes a primitive/boxed standalone expression */
+ PRIMITIVE;
+
+ /**
+ * Does this kind denote a poly argument expression
+ */
+ public final boolean isPoly() {
+ return this == POLY;
+ }
+
+ /**
+ * Does this kind denote a primitive standalone expression
+ */
+ public final boolean isPrimitive() {
+ return this == PRIMITIVE;
+ }
+
+ /**
+ * Compute the kind of a standalone expression of a given type
+ */
+ static ArgumentExpressionKind standaloneKind(Type type, Types types) {
+ return types.unboxedTypeOrType(type).isPrimitive() ?
+ ArgumentExpressionKind.PRIMITIVE :
+ ArgumentExpressionKind.NO_POLY;
+ }
+
+ /**
+ * Compute the kind of a method argument expression given its symbol
+ */
+ static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
+ Type restype = sym.type.getReturnType();
+ if (sym.type.hasTag(FORALL) &&
+ restype.containsAny(((ForAll)sym.type).tvars)) {
+ return ArgumentExpressionKind.POLY;
+ } else {
+ return ArgumentExpressionKind.standaloneKind(restype, types);
+ }
+ }
+ }
+
+ /**
+ * Tree scanner used for checking as to whether an argument expression
+ * requires speculative attribution
+ */
+ final class DeferredChecker extends FilterScanner {
+
+ Env<AttrContext> env;
+ ArgumentExpressionKind result;
+
+ public DeferredChecker(Env<AttrContext> env) {
+ super(deferredCheckerTags);
+ this.env = env;
+ }
+
+ @Override
+ public void visitLambda(JCLambda tree) {
+ //a lambda is always a poly expression
+ result = ArgumentExpressionKind.POLY;
+ }
+
+ @Override
+ public void visitReference(JCMemberReference tree) {
+ //a method reference is always a poly expression
+ result = ArgumentExpressionKind.POLY;
+ }
+
+ @Override
+ public void visitTypeCast(JCTypeCast tree) {
+ //a cast is always a standalone expression
+ result = ArgumentExpressionKind.NO_POLY;
+ }
+
+ @Override
+ public void visitConditional(JCConditional tree) {
+ scan(tree.truepart);
+ if (!result.isPrimitive()) {
+ result = ArgumentExpressionKind.POLY;
+ return;
+ }
+ scan(tree.falsepart);
+ result = reduce(ArgumentExpressionKind.PRIMITIVE);
+ }
+
+ @Override
+ public void visitNewClass(JCNewClass tree) {
+ result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
+ ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
+ }
+
+ @Override
+ public void visitApply(JCMethodInvocation tree) {
+ Name name = TreeInfo.name(tree.meth);
+
+ //fast path
+ if (tree.typeargs.nonEmpty() ||
+ name == name.table.names._this ||
+ name == name.table.names._super) {
+ result = ArgumentExpressionKind.NO_POLY;
+ return;
+ }
+
+ //slow path
+ final JCExpression rec = tree.meth.hasTag(SELECT) ?
+ ((JCFieldAccess)tree.meth).selected :
+ null;
+
+ if (rec != null && !isSimpleReceiver(rec)) {
+ //give up if receiver is too complex (to cut down analysis time)
+ result = ArgumentExpressionKind.POLY;
+ return;
+ }
+
+ Type site = rec != null ?
+ attribSpeculative(rec, env, attr.unknownTypeExprInfo).type :
+ env.enclClass.sym.type;
+
+ ListBuffer<Type> args = ListBuffer.lb();
+ for (int i = 0; i < tree.args.length(); i ++) {
+ args.append(Type.noType);
+ }
+
+ Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args.toList(), List.<Type>nil(), MethodResolutionPhase.VARARITY) {
+ @Override
+ Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
+ return rec == null ?
+ rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
+ rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
+ }
+ @Override
+ Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
+ return sym;
+ }
+ };
+
+ Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
+
+ if (sym.kind == Kinds.AMBIGUOUS) {
+ Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
+ result = ArgumentExpressionKind.PRIMITIVE;
+ for (List<Symbol> ambigousSyms = err.ambiguousSyms ;
+ ambigousSyms.nonEmpty() && !result.isPoly() ;
+ ambigousSyms = ambigousSyms.tail) {
+ Symbol s = ambigousSyms.head;
+ if (s.kind == Kinds.MTH) {
+ result = reduce(ArgumentExpressionKind.methodKind(s, types));
+ }
+ }
+ } else {
+ result = (sym.kind == Kinds.MTH) ?
+ ArgumentExpressionKind.methodKind(sym, types) :
+ ArgumentExpressionKind.NO_POLY;
+ }
+ }
+ //where
+ private boolean isSimpleReceiver(JCTree rec) {
+ switch (rec.getTag()) {
+ case IDENT:
+ return true;
+ case SELECT:
+ return isSimpleReceiver(((JCFieldAccess)rec).selected);
+ case TYPEAPPLY:
+ case TYPEARRAY:
+ return true;
+ case ANNOTATED_TYPE:
+ return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
+ default:
+ return false;
+ }
+ }
+ private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
+ switch (result) {
+ case PRIMITIVE: return kind;
+ case NO_POLY: return kind.isPoly() ? kind : result;
+ case POLY: return result;
+ default:
+ Assert.error();
+ return null;
+ }
+ }
+
+ @Override
+ public void visitLiteral(JCLiteral tree) {
+ Type litType = attr.litType(tree.typetag);
+ result = ArgumentExpressionKind.standaloneKind(litType, types);
+ }
+
+ @Override
+ void skip(JCTree tree) {
+ result = ArgumentExpressionKind.NO_POLY;
+ }
+ }
+ //where
+ private EnumSet<JCTree.Tag> deferredCheckerTags =
+ EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
+ CONDEXPR, NEWCLASS, APPLY, LITERAL);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Apr 15 14:17:30 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Apr 15 14:18:30 2013 +0100
@@ -3604,6 +3604,11 @@
}
@Override
+ public Symbol baseSymbol() {
+ return delegatedError.baseSymbol();
+ }
+
+ @Override
protected Symbol access(Name name, TypeSymbol location) {
return delegatedError.access(name, location);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Apr 15 14:17:30 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Apr 15 14:18:30 2013 +0100
@@ -249,23 +249,6 @@
}
}
- /** Return true if a a tree corresponds to a poly expression. */
- public static boolean isPoly(JCTree tree, JCTree origin) {
- switch (tree.getTag()) {
- case APPLY:
- case NEWCLASS:
- case CONDEXPR:
- return !origin.hasTag(TYPECAST);
- case LAMBDA:
- case REFERENCE:
- return true;
- case PARENS:
- return isPoly(((JCParens)tree).expr, origin);
- default:
- return false;
- }
- }
-
/** set 'polyKind' on given tree */
public static void setPolyKind(JCTree tree, PolyKind pkind) {
switch (tree.getTag()) {