1.1 --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Nov 14 20:27:08 2014 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Nov 14 21:10:58 2014 -0800 1.3 @@ -321,7 +321,9 @@ 1.4 1.5 ListBuffer<JCExpression> syntheticInits = new ListBuffer<>(); 1.6 1.7 - if (!sym.isStatic()) { 1.8 + if (localContext.methodReferenceReceiver != null) { 1.9 + syntheticInits.append(localContext.methodReferenceReceiver); 1.10 + } else if (!sym.isStatic()) { 1.11 syntheticInits.append(makeThis( 1.12 sym.owner.enclClass().asType(), 1.13 localContext.owner.enclClass())); 1.14 @@ -364,17 +366,10 @@ 1.15 1.16 //first determine the method symbol to be used to generate the sam instance 1.17 //this is either the method reference symbol, or the bridged reference symbol 1.18 - Symbol refSym = localContext.needsBridge() 1.19 - ? localContext.bridgeSym 1.20 - : localContext.isSignaturePolymorphic() 1.21 + Symbol refSym = localContext.isSignaturePolymorphic() 1.22 ? localContext.sigPolySym 1.23 : tree.sym; 1.24 1.25 - //build the bridge method, if needed 1.26 - if (localContext.needsBridge()) { 1.27 - bridgeMemberReference(tree, localContext); 1.28 - } 1.29 - 1.30 //the qualifying expression is treated as a special captured arg 1.31 JCExpression init; 1.32 switch(tree.kind) { 1.33 @@ -744,54 +739,51 @@ 1.34 // </editor-fold> 1.35 1.36 /** 1.37 - * Generate an adapter method "bridge" for a method reference which cannot 1.38 - * be used directly. 1.39 + * Converts a method reference which cannot be used directly into a lambda 1.40 */ 1.41 - private class MemberReferenceBridger { 1.42 + private class MemberReferenceToLambda { 1.43 1.44 private final JCMemberReference tree; 1.45 private final ReferenceTranslationContext localContext; 1.46 + private final Symbol owner; 1.47 private final ListBuffer<JCExpression> args = new ListBuffer<>(); 1.48 private final ListBuffer<JCVariableDecl> params = new ListBuffer<>(); 1.49 1.50 - MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) { 1.51 + private JCExpression receiverExpression = null; 1.52 + 1.53 + MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) { 1.54 this.tree = tree; 1.55 this.localContext = localContext; 1.56 + this.owner = owner; 1.57 } 1.58 1.59 - /** 1.60 - * Generate the bridge 1.61 - */ 1.62 - JCMethodDecl bridge() { 1.63 + JCLambda lambda() { 1.64 int prevPos = make.pos; 1.65 try { 1.66 make.at(tree); 1.67 Type samDesc = localContext.bridgedRefSig(); 1.68 List<Type> samPTypes = samDesc.getParameterTypes(); 1.69 1.70 - //an extra argument is prepended to the signature of the bridge in case 1.71 - //the member reference is an instance method reference (in which case 1.72 - //the receiver expression is passed to the bridge itself). 1.73 - Type recType = null; 1.74 + // an extra argument is prepended in the case where the member 1.75 + // reference is an unbound instance method reference (in which 1.76 + // case the receiver expression in passed. 1.77 + VarSymbol rcvr; 1.78 switch (tree.kind) { 1.79 - case IMPLICIT_INNER: 1.80 - recType = tree.sym.owner.type.getEnclosingType(); 1.81 - break; 1.82 case BOUND: 1.83 - recType = tree.getQualifierExpression().type; 1.84 + rcvr = addParameter("rec$", tree.getQualifierExpression().type, false); 1.85 + receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); 1.86 break; 1.87 case UNBOUND: 1.88 - recType = samPTypes.head; 1.89 + rcvr = addParameter("rec$", samPTypes.head, false); 1.90 samPTypes = samPTypes.tail; 1.91 break; 1.92 + default: 1.93 + rcvr = null; 1.94 + break; 1.95 } 1.96 1.97 - //generate the parameter list for the bridged member reference - the 1.98 - //bridge signature will match the signature of the target sam descriptor 1.99 - 1.100 - VarSymbol rcvr = (recType == null) 1.101 - ? null 1.102 - : addParameter("rec$", recType, false); 1.103 + // generate the parameter list for the coverted member reference. 1.104 + // the signature will match the signature of the target sam descriptor 1.105 1.106 List<Type> refPTypes = tree.sym.type.getParameterTypes(); 1.107 int refSize = refPTypes.size(); 1.108 @@ -810,64 +802,50 @@ 1.109 addParameter("xva$" + i, tree.varargsElement, true); 1.110 } 1.111 1.112 - //generate the bridge method declaration 1.113 - JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()), 1.114 - localContext.bridgeSym.name, 1.115 - make.QualIdent(samDesc.getReturnType().tsym), 1.116 - List.<JCTypeParameter>nil(), 1.117 - params.toList(), 1.118 - tree.sym.type.getThrownTypes() == null 1.119 - ? List.<JCExpression>nil() 1.120 - : make.Types(tree.sym.type.getThrownTypes()), 1.121 - null, 1.122 - null); 1.123 - bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym; 1.124 - bridgeDecl.type = localContext.bridgeSym.type = 1.125 - types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList())); 1.126 + //body generation - this can be either a method call or a 1.127 + //new instance creation expression, depending on the member reference kind 1.128 + JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) 1.129 + ? expressionInvoke(rcvr) 1.130 + : expressionNew(); 1.131 1.132 - //bridge method body generation - this can be either a method call or a 1.133 - //new instance creation expression, depending on the member reference kind 1.134 - JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE) 1.135 - ? bridgeExpressionInvoke(makeReceiver(rcvr)) 1.136 - : bridgeExpressionNew(); 1.137 - 1.138 - //the body is either a return expression containing a method call, 1.139 - //or the method call itself, depending on whether the return type of 1.140 - //the bridge is non-void/void. 1.141 - bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl); 1.142 - 1.143 - return bridgeDecl; 1.144 + JCLambda slam = make.Lambda(params.toList(), expr); 1.145 + slam.targets = tree.targets; 1.146 + slam.type = tree.type; 1.147 + slam.pos = tree.pos; 1.148 + return slam; 1.149 } finally { 1.150 make.at(prevPos); 1.151 } 1.152 } 1.153 - //where 1.154 - private JCExpression makeReceiver(VarSymbol rcvr) { 1.155 - if (rcvr == null) return null; 1.156 - JCExpression rcvrExpr = make.Ident(rcvr); 1.157 - Type rcvrType = tree.sym.enclClass().type; 1.158 - if (rcvrType == syms.arrayClass.type) { 1.159 - // Map the receiver type to the actually type, not just "array" 1.160 - rcvrType = tree.getQualifierExpression().type; 1.161 - } 1.162 - if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { 1.163 - rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); 1.164 - } 1.165 - return rcvrExpr; 1.166 + 1.167 + JCExpression getReceiverExpression() { 1.168 + return receiverExpression; 1.169 + } 1.170 + 1.171 + private JCExpression makeReceiver(VarSymbol rcvr) { 1.172 + if (rcvr == null) return null; 1.173 + JCExpression rcvrExpr = make.Ident(rcvr); 1.174 + Type rcvrType = tree.sym.enclClass().type; 1.175 + if (rcvrType == syms.arrayClass.type) { 1.176 + // Map the receiver type to the actually type, not just "array" 1.177 + rcvrType = tree.getQualifierExpression().type; 1.178 } 1.179 + if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { 1.180 + rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); 1.181 + } 1.182 + return rcvrExpr; 1.183 + } 1.184 1.185 /** 1.186 - * determine the receiver of the bridged method call - the receiver can 1.187 - * be either the synthetic receiver parameter or a type qualifier; the 1.188 - * original qualifier expression is never used here, as it might refer 1.189 - * to symbols not available in the static context of the bridge 1.190 + * determine the receiver of the method call - the receiver can 1.191 + * be a type qualifier, the synthetic receiver parameter or 'super'. 1.192 */ 1.193 - private JCExpression bridgeExpressionInvoke(JCExpression rcvr) { 1.194 + private JCExpression expressionInvoke(VarSymbol rcvr) { 1.195 JCExpression qualifier = 1.196 tree.sym.isStatic() ? 1.197 make.Type(tree.sym.owner.type) : 1.198 (rcvr != null) ? 1.199 - rcvr : 1.200 + makeReceiver(rcvr) : 1.201 tree.getQualifierExpression(); 1.202 1.203 //create the qualifier expression 1.204 @@ -886,10 +864,9 @@ 1.205 } 1.206 1.207 /** 1.208 - * the enclosing expression is either 'null' (no enclosing type) or set 1.209 - * to the first bridge synthetic parameter 1.210 + * Lambda body to use for a 'new'. 1.211 */ 1.212 - private JCExpression bridgeExpressionNew() { 1.213 + private JCExpression expressionNew() { 1.214 if (tree.kind == ReferenceKind.ARRAY_CTOR) { 1.215 //create the array creation expression 1.216 JCNewArray newArr = make.NewArray( 1.217 @@ -899,15 +876,10 @@ 1.218 newArr.type = tree.getQualifierExpression().type; 1.219 return newArr; 1.220 } else { 1.221 - JCExpression encl = null; 1.222 - switch (tree.kind) { 1.223 - case UNBOUND: 1.224 - case IMPLICIT_INNER: 1.225 - encl = make.Ident(params.first()); 1.226 - } 1.227 - 1.228 //create the instance creation expression 1.229 - JCNewClass newClass = make.NewClass(encl, 1.230 + //note that method reference syntax does not allow an explicit 1.231 + //enclosing class (so the enclosing class is null) 1.232 + JCNewClass newClass = make.NewClass(null, 1.233 List.<JCExpression>nil(), 1.234 make.Type(tree.getQualifierExpression().type), 1.235 convertArgs(tree.sym, args.toList(), tree.varargsElement), 1.236 @@ -921,7 +893,8 @@ 1.237 } 1.238 1.239 private VarSymbol addParameter(String name, Type p, boolean genArg) { 1.240 - VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym); 1.241 + VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner); 1.242 + vsym.pos = tree.pos; 1.243 params.append(make.VarDef(vsym, null)); 1.244 if (genArg) { 1.245 args.append(make.Ident(vsym)); 1.246 @@ -930,15 +903,6 @@ 1.247 } 1.248 } 1.249 1.250 - /** 1.251 - * Bridges a member reference - this is needed when: 1.252 - * * Var args in the referenced method need to be flattened away 1.253 - * * super is used 1.254 - */ 1.255 - private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) { 1.256 - kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge()); 1.257 - } 1.258 - 1.259 private MethodType typeToMethodType(Type mt) { 1.260 Type type = types.erasure(mt); 1.261 return new MethodType(type.getParameterTypes(), 1.262 @@ -1258,9 +1222,25 @@ 1.263 1.264 @Override 1.265 public void visitLambda(JCLambda tree) { 1.266 + analyzeLambda(tree, "lambda.stat"); 1.267 + } 1.268 + 1.269 + private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) { 1.270 + // Translation of the receiver expression must occur first 1.271 + JCExpression rcvr = translate(methodReferenceReceiver); 1.272 + LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1"); 1.273 + if (rcvr != null) { 1.274 + context.methodReferenceReceiver = rcvr; 1.275 + } 1.276 + } 1.277 + 1.278 + private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) { 1.279 List<Frame> prevStack = frameStack; 1.280 try { 1.281 - LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree); 1.282 + LambdaTranslationContext context = new LambdaTranslationContext(tree); 1.283 + if (dumpLambdaToMethodStats) { 1.284 + log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym); 1.285 + } 1.286 frameStack = frameStack.prepend(new Frame(tree)); 1.287 for (JCVariableDecl param : tree.params) { 1.288 context.addSymbol(param.sym, PARAM); 1.289 @@ -1269,6 +1249,7 @@ 1.290 contextMap.put(tree, context); 1.291 super.visitLambda(tree); 1.292 context.complete(); 1.293 + return context; 1.294 } 1.295 finally { 1.296 frameStack = prevStack; 1.297 @@ -1357,47 +1338,24 @@ 1.298 * information added in the LambdaToMethod pass will have the wrong 1.299 * signature. Hooks between Lower and LambdaToMethod have been added to 1.300 * handle normal "new" in this case. This visitor converts potentially 1.301 - * effected method references into a lambda containing a normal "new" of 1.302 - * the class. 1.303 + * affected method references into a lambda containing a normal 1.304 + * expression. 1.305 * 1.306 * @param tree 1.307 */ 1.308 @Override 1.309 public void visitReference(JCMemberReference tree) { 1.310 - if (tree.getMode() == ReferenceMode.NEW 1.311 - && tree.kind != ReferenceKind.ARRAY_CTOR 1.312 - && tree.sym.owner.isLocal()) { 1.313 - MethodSymbol consSym = (MethodSymbol) tree.sym; 1.314 - List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes(); 1.315 - Type classType = consSym.owner.type; 1.316 - 1.317 - // Build lambda parameters 1.318 - // partially cloned from TreeMaker.Params until 8014021 is fixed 1.319 - Symbol owner = owner(); 1.320 - ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>(); 1.321 - int i = 0; 1.322 - for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) { 1.323 - JCVariableDecl param = make.Param(make.paramName(i++), l.head, owner); 1.324 - param.sym.pos = tree.pos; 1.325 - paramBuff.append(param); 1.326 - } 1.327 - List<JCVariableDecl> params = paramBuff.toList(); 1.328 - 1.329 - // Make new-class call 1.330 - JCNewClass nc = makeNewClass(classType, make.Idents(params)); 1.331 - nc.pos = tree.pos; 1.332 - 1.333 - // Make lambda holding the new-class call 1.334 - JCLambda slam = make.Lambda(params, nc); 1.335 - slam.targets = tree.targets; 1.336 - slam.type = tree.type; 1.337 - slam.pos = tree.pos; 1.338 - 1.339 - // Now it is a lambda, process as such 1.340 - visitLambda(slam); 1.341 + ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree); 1.342 + contextMap.put(tree, rcontext); 1.343 + if (rcontext.needsConversionToLambda()) { 1.344 + // Convert to a lambda, and process as such 1.345 + MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner()); 1.346 + analyzeLambda(conv.lambda(), conv.getReceiverExpression()); 1.347 } else { 1.348 super.visitReference(tree); 1.349 - contextMap.put(tree, makeReferenceContext(tree)); 1.350 + if (dumpLambdaToMethodStats) { 1.351 + log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null); 1.352 + } 1.353 } 1.354 } 1.355 1.356 @@ -1652,14 +1610,6 @@ 1.357 } 1.358 } 1.359 1.360 - private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) { 1.361 - return new LambdaTranslationContext(tree); 1.362 - } 1.363 - 1.364 - private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) { 1.365 - return new ReferenceTranslationContext(tree); 1.366 - } 1.367 - 1.368 private class Frame { 1.369 final JCTree tree; 1.370 List<Symbol> locals; 1.371 @@ -1779,6 +1729,13 @@ 1.372 */ 1.373 final Set<Symbol> freeVarProcessedLocalClasses; 1.374 1.375 + /** 1.376 + * For method references converted to lambdas. The method 1.377 + * reference receiver expression. Must be treated like a captured 1.378 + * variable. 1.379 + */ 1.380 + JCExpression methodReferenceReceiver; 1.381 + 1.382 LambdaTranslationContext(JCLambda tree) { 1.383 super(tree); 1.384 Frame frame = frameStack.head; 1.385 @@ -1798,9 +1755,6 @@ 1.386 // This symbol will be filled-in in complete 1.387 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass()); 1.388 1.389 - if (dumpLambdaToMethodStats) { 1.390 - log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym); 1.391 - } 1.392 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class); 1.393 1.394 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>()); 1.395 @@ -2017,6 +1971,13 @@ 1.396 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) { 1.397 params.append(make.VarDef((VarSymbol) thisSym, null)); 1.398 } 1.399 + if (methodReferenceReceiver != null) { 1.400 + params.append(make.VarDef( 1.401 + make.Modifiers(PARAMETER|FINAL), 1.402 + names.fromString("$rcvr$"), 1.403 + make.Type(methodReferenceReceiver.type), 1.404 + null)); 1.405 + } 1.406 for (Symbol thisSym : getSymbolMap(PARAM).values()) { 1.407 params.append(make.VarDef((VarSymbol) thisSym, null)); 1.408 } 1.409 @@ -2044,40 +2005,27 @@ 1.410 * and the used by the main translation routines in order to adjust method 1.411 * references (i.e. in case a bridge is needed) 1.412 */ 1.413 - private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> { 1.414 + private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> { 1.415 1.416 final boolean isSuper; 1.417 - final Symbol bridgeSym; 1.418 final Symbol sigPolySym; 1.419 1.420 ReferenceTranslationContext(JCMemberReference tree) { 1.421 super(tree); 1.422 this.isSuper = tree.hasKind(ReferenceKind.SUPER); 1.423 - this.bridgeSym = needsBridge() 1.424 - ? makePrivateSyntheticMethod(isSuper ? 0 : STATIC, 1.425 - referenceBridgeName(), null, 1.426 - owner.enclClass()) 1.427 - : null; 1.428 this.sigPolySym = isSignaturePolymorphic() 1.429 ? makePrivateSyntheticMethod(tree.sym.flags(), 1.430 tree.sym.name, 1.431 bridgedRefSig(), 1.432 tree.sym.enclClass()) 1.433 : null; 1.434 - if (dumpLambdaToMethodStats) { 1.435 - String key = bridgeSym == null ? 1.436 - "mref.stat" : "mref.stat.1"; 1.437 - log.note(tree, key, needsAltMetafactory(), bridgeSym); 1.438 - } 1.439 } 1.440 1.441 /** 1.442 * Get the opcode associated with this method reference 1.443 */ 1.444 int referenceKind() { 1.445 - return LambdaToMethod.this.referenceKind(needsBridge() 1.446 - ? bridgeSym 1.447 - : tree.sym); 1.448 + return LambdaToMethod.this.referenceKind(tree.sym); 1.449 } 1.450 1.451 boolean needsVarArgsConversion() { 1.452 @@ -2085,62 +2033,6 @@ 1.453 } 1.454 1.455 /** 1.456 - * Generate a disambiguating string to increase stability (important 1.457 - * if serialized) 1.458 - * 1.459 - * @return String to differentiate synthetic lambda method names 1.460 - */ 1.461 - private String referenceBridgeDisambiguation() { 1.462 - StringBuilder buf = new StringBuilder(); 1.463 - // Append the enclosing method signature to differentiate 1.464 - // overloaded enclosing methods. 1.465 - if (owner.type != null) { 1.466 - buf.append(typeSig(owner.type)); 1.467 - buf.append(":"); 1.468 - } 1.469 - 1.470 - // Append qualifier type 1.471 - buf.append(classSig(tree.sym.owner.type)); 1.472 - 1.473 - // Note static/instance 1.474 - buf.append(tree.sym.isStatic()? " S " : " I "); 1.475 - 1.476 - // Append referenced signature 1.477 - buf.append(typeSig(tree.sym.erasure(types))); 1.478 - 1.479 - return buf.toString(); 1.480 - } 1.481 - 1.482 - /** 1.483 - * Construct a unique stable name for the method reference bridge 1.484 - * 1.485 - * @return Name to use for the synthetic method name 1.486 - */ 1.487 - private Name referenceBridgeName() { 1.488 - StringBuilder buf = new StringBuilder(); 1.489 - // Append lambda ID, this is semantically significant 1.490 - buf.append(names.lambda); 1.491 - // Note that it is a method reference bridge 1.492 - buf.append("MR$"); 1.493 - // Append the enclosing method name 1.494 - buf.append(enclosingMethodName()); 1.495 - buf.append('$'); 1.496 - // Append the referenced method name 1.497 - buf.append(syntheticMethodNameComponent(tree.sym.name)); 1.498 - buf.append('$'); 1.499 - // Append a hash of the disambiguating string : enclosing method 1.500 - // signature, etc. 1.501 - String disam = referenceBridgeDisambiguation(); 1.502 - buf.append(Integer.toHexString(disam.hashCode())); 1.503 - buf.append('$'); 1.504 - // The above appended name components may not be unique, append 1.505 - // a count based on the above name components. 1.506 - buf.append(syntheticMethodNameCounts.getIndex(buf)); 1.507 - String result = buf.toString(); 1.508 - return names.fromString(result); 1.509 - } 1.510 - 1.511 - /** 1.512 * @return Is this an array operation like clone() 1.513 */ 1.514 boolean isArrayOp() { 1.515 @@ -2175,13 +2067,16 @@ 1.516 } 1.517 1.518 /** 1.519 - * Does this reference needs a bridge (i.e. var args need to be 1.520 - * expanded or "super" is used) 1.521 + * Does this reference need to be converted to a lambda 1.522 + * (i.e. var args need to be expanded or "super" is used) 1.523 */ 1.524 - final boolean needsBridge() { 1.525 + final boolean needsConversionToLambda() { 1.526 return isSuper || needsVarArgsConversion() || isArrayOp() || 1.527 isPrivateInOtherClass() || 1.528 - !receiverAccessible(); 1.529 + !receiverAccessible() || 1.530 + (tree.getMode() == ReferenceMode.NEW && 1.531 + tree.kind != ReferenceKind.ARRAY_CTOR && 1.532 + (tree.sym.owner.isLocal() || tree.sym.owner.isInner())); 1.533 } 1.534 1.535 Type generatedRefSig() {