Mon, 15 Apr 2013 14:18:30 +0100
8010923: Avoid redundant speculative attribution
Summary: Add optimization to avoid speculative attribution for certain argument expressions
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Apr 15 14:17:30 2013 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Apr 15 14:18:30 2013 +0100 1.3 @@ -148,6 +148,7 @@ 1.4 varInfo = new ResultInfo(VAR, Type.noType); 1.5 unknownExprInfo = new ResultInfo(VAL, Type.noType); 1.6 unknownTypeInfo = new ResultInfo(TYP, Type.noType); 1.7 + unknownTypeExprInfo = new ResultInfo(Kinds.TYP | Kinds.VAL, Type.noType); 1.8 recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext); 1.9 } 1.10 1.11 @@ -559,6 +560,7 @@ 1.12 final ResultInfo varInfo; 1.13 final ResultInfo unknownExprInfo; 1.14 final ResultInfo unknownTypeInfo; 1.15 + final ResultInfo unknownTypeExprInfo; 1.16 final ResultInfo recoveryInfo; 1.17 1.18 Type pt() { 1.19 @@ -667,7 +669,7 @@ 1.20 List<Type> attribArgs(List<JCExpression> trees, Env<AttrContext> env) { 1.21 ListBuffer<Type> argtypes = new ListBuffer<Type>(); 1.22 for (JCExpression arg : trees) { 1.23 - Type argtype = allowPoly && TreeInfo.isPoly(arg, env.tree) ? 1.24 + Type argtype = allowPoly && deferredAttr.isDeferred(env, arg) ? 1.25 deferredAttr.new DeferredType(arg, env) : 1.26 chk.checkNonVoid(arg, attribExpr(arg, env, Infer.anyPoly)); 1.27 argtypes.append(argtype); 1.28 @@ -2989,7 +2991,8 @@ 1.29 Env<AttrContext> localEnv = env.dup(tree); 1.30 //should we propagate the target type? 1.31 final ResultInfo castInfo; 1.32 - final boolean isPoly = TreeInfo.isPoly(tree.expr, tree); 1.33 + JCExpression expr = TreeInfo.skipParens(tree.expr); 1.34 + boolean isPoly = expr.hasTag(LAMBDA) || expr.hasTag(REFERENCE); 1.35 if (isPoly) { 1.36 //expression is a poly - we need to propagate target type info 1.37 castInfo = new ResultInfo(VAL, clazztype, new Check.NestedCheckContext(resultInfo.checkContext) {
2.1 --- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Apr 15 14:17:30 2013 +0100 2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Apr 15 14:18:30 2013 +0100 2.3 @@ -800,4 +800,219 @@ 2.4 } 2.5 } 2.6 } 2.7 + 2.8 + /** 2.9 + * Does the argument expression {@code expr} need speculative type-checking? 2.10 + */ 2.11 + boolean isDeferred(Env<AttrContext> env, JCExpression expr) { 2.12 + DeferredChecker dc = new DeferredChecker(env); 2.13 + dc.scan(expr); 2.14 + return dc.result.isPoly(); 2.15 + } 2.16 + 2.17 + /** 2.18 + * The kind of an argument expression. This is used by the analysis that 2.19 + * determines as to whether speculative attribution is necessary. 2.20 + */ 2.21 + enum ArgumentExpressionKind { 2.22 + 2.23 + /** kind that denotes poly argument expression */ 2.24 + POLY, 2.25 + /** kind that denotes a standalone expression */ 2.26 + NO_POLY, 2.27 + /** kind that denotes a primitive/boxed standalone expression */ 2.28 + PRIMITIVE; 2.29 + 2.30 + /** 2.31 + * Does this kind denote a poly argument expression 2.32 + */ 2.33 + public final boolean isPoly() { 2.34 + return this == POLY; 2.35 + } 2.36 + 2.37 + /** 2.38 + * Does this kind denote a primitive standalone expression 2.39 + */ 2.40 + public final boolean isPrimitive() { 2.41 + return this == PRIMITIVE; 2.42 + } 2.43 + 2.44 + /** 2.45 + * Compute the kind of a standalone expression of a given type 2.46 + */ 2.47 + static ArgumentExpressionKind standaloneKind(Type type, Types types) { 2.48 + return types.unboxedTypeOrType(type).isPrimitive() ? 2.49 + ArgumentExpressionKind.PRIMITIVE : 2.50 + ArgumentExpressionKind.NO_POLY; 2.51 + } 2.52 + 2.53 + /** 2.54 + * Compute the kind of a method argument expression given its symbol 2.55 + */ 2.56 + static ArgumentExpressionKind methodKind(Symbol sym, Types types) { 2.57 + Type restype = sym.type.getReturnType(); 2.58 + if (sym.type.hasTag(FORALL) && 2.59 + restype.containsAny(((ForAll)sym.type).tvars)) { 2.60 + return ArgumentExpressionKind.POLY; 2.61 + } else { 2.62 + return ArgumentExpressionKind.standaloneKind(restype, types); 2.63 + } 2.64 + } 2.65 + } 2.66 + 2.67 + /** 2.68 + * Tree scanner used for checking as to whether an argument expression 2.69 + * requires speculative attribution 2.70 + */ 2.71 + final class DeferredChecker extends FilterScanner { 2.72 + 2.73 + Env<AttrContext> env; 2.74 + ArgumentExpressionKind result; 2.75 + 2.76 + public DeferredChecker(Env<AttrContext> env) { 2.77 + super(deferredCheckerTags); 2.78 + this.env = env; 2.79 + } 2.80 + 2.81 + @Override 2.82 + public void visitLambda(JCLambda tree) { 2.83 + //a lambda is always a poly expression 2.84 + result = ArgumentExpressionKind.POLY; 2.85 + } 2.86 + 2.87 + @Override 2.88 + public void visitReference(JCMemberReference tree) { 2.89 + //a method reference is always a poly expression 2.90 + result = ArgumentExpressionKind.POLY; 2.91 + } 2.92 + 2.93 + @Override 2.94 + public void visitTypeCast(JCTypeCast tree) { 2.95 + //a cast is always a standalone expression 2.96 + result = ArgumentExpressionKind.NO_POLY; 2.97 + } 2.98 + 2.99 + @Override 2.100 + public void visitConditional(JCConditional tree) { 2.101 + scan(tree.truepart); 2.102 + if (!result.isPrimitive()) { 2.103 + result = ArgumentExpressionKind.POLY; 2.104 + return; 2.105 + } 2.106 + scan(tree.falsepart); 2.107 + result = reduce(ArgumentExpressionKind.PRIMITIVE); 2.108 + } 2.109 + 2.110 + @Override 2.111 + public void visitNewClass(JCNewClass tree) { 2.112 + result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ? 2.113 + ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY; 2.114 + } 2.115 + 2.116 + @Override 2.117 + public void visitApply(JCMethodInvocation tree) { 2.118 + Name name = TreeInfo.name(tree.meth); 2.119 + 2.120 + //fast path 2.121 + if (tree.typeargs.nonEmpty() || 2.122 + name == name.table.names._this || 2.123 + name == name.table.names._super) { 2.124 + result = ArgumentExpressionKind.NO_POLY; 2.125 + return; 2.126 + } 2.127 + 2.128 + //slow path 2.129 + final JCExpression rec = tree.meth.hasTag(SELECT) ? 2.130 + ((JCFieldAccess)tree.meth).selected : 2.131 + null; 2.132 + 2.133 + if (rec != null && !isSimpleReceiver(rec)) { 2.134 + //give up if receiver is too complex (to cut down analysis time) 2.135 + result = ArgumentExpressionKind.POLY; 2.136 + return; 2.137 + } 2.138 + 2.139 + Type site = rec != null ? 2.140 + attribSpeculative(rec, env, attr.unknownTypeExprInfo).type : 2.141 + env.enclClass.sym.type; 2.142 + 2.143 + ListBuffer<Type> args = ListBuffer.lb(); 2.144 + for (int i = 0; i < tree.args.length(); i ++) { 2.145 + args.append(Type.noType); 2.146 + } 2.147 + 2.148 + Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args.toList(), List.<Type>nil(), MethodResolutionPhase.VARARITY) { 2.149 + @Override 2.150 + Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 2.151 + return rec == null ? 2.152 + rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) : 2.153 + rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false); 2.154 + } 2.155 + @Override 2.156 + Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) { 2.157 + return sym; 2.158 + } 2.159 + }; 2.160 + 2.161 + Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh); 2.162 + 2.163 + if (sym.kind == Kinds.AMBIGUOUS) { 2.164 + Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol(); 2.165 + result = ArgumentExpressionKind.PRIMITIVE; 2.166 + for (List<Symbol> ambigousSyms = err.ambiguousSyms ; 2.167 + ambigousSyms.nonEmpty() && !result.isPoly() ; 2.168 + ambigousSyms = ambigousSyms.tail) { 2.169 + Symbol s = ambigousSyms.head; 2.170 + if (s.kind == Kinds.MTH) { 2.171 + result = reduce(ArgumentExpressionKind.methodKind(s, types)); 2.172 + } 2.173 + } 2.174 + } else { 2.175 + result = (sym.kind == Kinds.MTH) ? 2.176 + ArgumentExpressionKind.methodKind(sym, types) : 2.177 + ArgumentExpressionKind.NO_POLY; 2.178 + } 2.179 + } 2.180 + //where 2.181 + private boolean isSimpleReceiver(JCTree rec) { 2.182 + switch (rec.getTag()) { 2.183 + case IDENT: 2.184 + return true; 2.185 + case SELECT: 2.186 + return isSimpleReceiver(((JCFieldAccess)rec).selected); 2.187 + case TYPEAPPLY: 2.188 + case TYPEARRAY: 2.189 + return true; 2.190 + case ANNOTATED_TYPE: 2.191 + return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType); 2.192 + default: 2.193 + return false; 2.194 + } 2.195 + } 2.196 + private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) { 2.197 + switch (result) { 2.198 + case PRIMITIVE: return kind; 2.199 + case NO_POLY: return kind.isPoly() ? kind : result; 2.200 + case POLY: return result; 2.201 + default: 2.202 + Assert.error(); 2.203 + return null; 2.204 + } 2.205 + } 2.206 + 2.207 + @Override 2.208 + public void visitLiteral(JCLiteral tree) { 2.209 + Type litType = attr.litType(tree.typetag); 2.210 + result = ArgumentExpressionKind.standaloneKind(litType, types); 2.211 + } 2.212 + 2.213 + @Override 2.214 + void skip(JCTree tree) { 2.215 + result = ArgumentExpressionKind.NO_POLY; 2.216 + } 2.217 + } 2.218 + //where 2.219 + private EnumSet<JCTree.Tag> deferredCheckerTags = 2.220 + EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST, 2.221 + CONDEXPR, NEWCLASS, APPLY, LITERAL); 2.222 }
3.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Apr 15 14:17:30 2013 +0100 3.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Apr 15 14:18:30 2013 +0100 3.3 @@ -3604,6 +3604,11 @@ 3.4 } 3.5 3.6 @Override 3.7 + public Symbol baseSymbol() { 3.8 + return delegatedError.baseSymbol(); 3.9 + } 3.10 + 3.11 + @Override 3.12 protected Symbol access(Name name, TypeSymbol location) { 3.13 return delegatedError.access(name, location); 3.14 }
4.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Apr 15 14:17:30 2013 +0100 4.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Apr 15 14:18:30 2013 +0100 4.3 @@ -249,23 +249,6 @@ 4.4 } 4.5 } 4.6 4.7 - /** Return true if a a tree corresponds to a poly expression. */ 4.8 - public static boolean isPoly(JCTree tree, JCTree origin) { 4.9 - switch (tree.getTag()) { 4.10 - case APPLY: 4.11 - case NEWCLASS: 4.12 - case CONDEXPR: 4.13 - return !origin.hasTag(TYPECAST); 4.14 - case LAMBDA: 4.15 - case REFERENCE: 4.16 - return true; 4.17 - case PARENS: 4.18 - return isPoly(((JCParens)tree).expr, origin); 4.19 - default: 4.20 - return false; 4.21 - } 4.22 - } 4.23 - 4.24 /** set 'polyKind' on given tree */ 4.25 public static void setPolyKind(JCTree tree, PolyKind pkind) { 4.26 switch (tree.getTag()) {