LambdaToMethod.java revision 2824:e0b35c562008
1/* 2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25package com.sun.tools.javac.comp; 26 27import com.sun.tools.javac.tree.*; 28import com.sun.tools.javac.tree.JCTree.*; 29import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; 30import com.sun.tools.javac.tree.TreeMaker; 31import com.sun.tools.javac.tree.TreeTranslator; 32import com.sun.tools.javac.code.Attribute; 33import com.sun.tools.javac.code.Scope.WriteableScope; 34import com.sun.tools.javac.code.Symbol; 35import com.sun.tools.javac.code.Symbol.ClassSymbol; 36import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; 37import com.sun.tools.javac.code.Symbol.MethodSymbol; 38import com.sun.tools.javac.code.Symbol.TypeSymbol; 39import com.sun.tools.javac.code.Symbol.VarSymbol; 40import com.sun.tools.javac.code.Symtab; 41import com.sun.tools.javac.code.Type; 42import com.sun.tools.javac.code.Type.MethodType; 43import com.sun.tools.javac.code.Type.TypeVar; 44import com.sun.tools.javac.code.Types; 45import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*; 46import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector; 47import com.sun.tools.javac.jvm.*; 48import com.sun.tools.javac.util.*; 49import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 50import com.sun.source.tree.MemberReferenceTree.ReferenceMode; 51 52import java.util.EnumMap; 53import java.util.HashMap; 54import java.util.HashSet; 55import java.util.LinkedHashMap; 56import java.util.Map; 57import java.util.Set; 58 59import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*; 60import static com.sun.tools.javac.code.Flags.*; 61import static com.sun.tools.javac.code.Kinds.Kind.*; 62import static com.sun.tools.javac.code.TypeTag.*; 63import static com.sun.tools.javac.tree.JCTree.Tag.*; 64import javax.lang.model.type.TypeKind; 65 66/** 67 * This pass desugars lambda expressions into static methods 68 * 69 * <p><b>This is NOT part of any supported API. 70 * If you write code that depends on this, you do so at your own risk. 71 * This code and its internal interfaces are subject to change or 72 * deletion without notice.</b> 73 */ 74public class LambdaToMethod extends TreeTranslator { 75 76 private Attr attr; 77 private JCDiagnostic.Factory diags; 78 private Log log; 79 private Lower lower; 80 private Names names; 81 private Symtab syms; 82 private Resolve rs; 83 private Operators operators; 84 private TreeMaker make; 85 private Types types; 86 private TransTypes transTypes; 87 private Env<AttrContext> attrEnv; 88 89 /** the analyzer scanner */ 90 private LambdaAnalyzerPreprocessor analyzer; 91 92 /** map from lambda trees to translation contexts */ 93 private Map<JCTree, TranslationContext<?>> contextMap; 94 95 /** current translation context (visitor argument) */ 96 private TranslationContext<?> context; 97 98 /** info about the current class being processed */ 99 private KlassInfo kInfo; 100 101 /** dump statistics about lambda code generation */ 102 private boolean dumpLambdaToMethodStats; 103 104 /** force serializable representation, for stress testing **/ 105 private final boolean forceSerializable; 106 107 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */ 108 public static final int FLAG_SERIALIZABLE = 1 << 0; 109 110 /** Flag for alternate metafactories indicating the lambda object has multiple targets */ 111 public static final int FLAG_MARKERS = 1 << 1; 112 113 /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */ 114 public static final int FLAG_BRIDGES = 1 << 2; 115 116 // <editor-fold defaultstate="collapsed" desc="Instantiating"> 117 protected static final Context.Key<LambdaToMethod> unlambdaKey = new Context.Key<>(); 118 119 public static LambdaToMethod instance(Context context) { 120 LambdaToMethod instance = context.get(unlambdaKey); 121 if (instance == null) { 122 instance = new LambdaToMethod(context); 123 } 124 return instance; 125 } 126 private LambdaToMethod(Context context) { 127 context.put(unlambdaKey, this); 128 diags = JCDiagnostic.Factory.instance(context); 129 log = Log.instance(context); 130 lower = Lower.instance(context); 131 names = Names.instance(context); 132 syms = Symtab.instance(context); 133 rs = Resolve.instance(context); 134 operators = Operators.instance(context); 135 make = TreeMaker.instance(context); 136 types = Types.instance(context); 137 transTypes = TransTypes.instance(context); 138 analyzer = new LambdaAnalyzerPreprocessor(); 139 Options options = Options.instance(context); 140 dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats"); 141 attr = Attr.instance(context); 142 forceSerializable = options.isSet("forceSerializable"); 143 } 144 // </editor-fold> 145 146 private class KlassInfo { 147 148 /** 149 * list of methods to append 150 */ 151 private ListBuffer<JCTree> appendedMethodList; 152 153 /** 154 * list of deserialization cases 155 */ 156 private final Map<String, ListBuffer<JCStatement>> deserializeCases; 157 158 /** 159 * deserialize method symbol 160 */ 161 private final MethodSymbol deserMethodSym; 162 163 /** 164 * deserialize method parameter symbol 165 */ 166 private final VarSymbol deserParamSym; 167 168 private final JCClassDecl clazz; 169 170 private KlassInfo(JCClassDecl clazz) { 171 this.clazz = clazz; 172 appendedMethodList = new ListBuffer<>(); 173 deserializeCases = new HashMap<>(); 174 MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType, 175 List.<Type>nil(), syms.methodClass); 176 deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym); 177 deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), 178 syms.serializedLambdaType, deserMethodSym); 179 } 180 181 private void addMethod(JCTree decl) { 182 appendedMethodList = appendedMethodList.prepend(decl); 183 } 184 } 185 186 // <editor-fold defaultstate="collapsed" desc="translate methods"> 187 @Override 188 public <T extends JCTree> T translate(T tree) { 189 TranslationContext<?> newContext = contextMap.get(tree); 190 return translate(tree, newContext != null ? newContext : context); 191 } 192 193 <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) { 194 TranslationContext<?> prevContext = context; 195 try { 196 context = newContext; 197 return super.translate(tree); 198 } 199 finally { 200 context = prevContext; 201 } 202 } 203 204 <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) { 205 ListBuffer<T> buf = new ListBuffer<>(); 206 for (T tree : trees) { 207 buf.append(translate(tree, newContext)); 208 } 209 return buf.toList(); 210 } 211 212 public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { 213 this.make = make; 214 this.attrEnv = env; 215 this.context = null; 216 this.contextMap = new HashMap<>(); 217 return translate(cdef); 218 } 219 // </editor-fold> 220 221 // <editor-fold defaultstate="collapsed" desc="visitor methods"> 222 /** 223 * Visit a class. 224 * Maintain the translatedMethodList across nested classes. 225 * Append the translatedMethodList to the class after it is translated. 226 * @param tree 227 */ 228 @Override 229 public void visitClassDef(JCClassDecl tree) { 230 if (tree.sym.owner.kind == PCK) { 231 //analyze class 232 tree = analyzer.analyzeAndPreprocessClass(tree); 233 } 234 KlassInfo prevKlassInfo = kInfo; 235 try { 236 kInfo = new KlassInfo(tree); 237 super.visitClassDef(tree); 238 if (!kInfo.deserializeCases.isEmpty()) { 239 int prevPos = make.pos; 240 try { 241 make.at(tree); 242 kInfo.addMethod(makeDeserializeMethod(tree.sym)); 243 } finally { 244 make.at(prevPos); 245 } 246 } 247 //add all translated instance methods here 248 List<JCTree> newMethods = kInfo.appendedMethodList.toList(); 249 tree.defs = tree.defs.appendList(newMethods); 250 for (JCTree lambda : newMethods) { 251 tree.sym.members().enter(((JCMethodDecl)lambda).sym); 252 } 253 result = tree; 254 } finally { 255 kInfo = prevKlassInfo; 256 } 257 } 258 259 /** 260 * Translate a lambda into a method to be inserted into the class. 261 * Then replace the lambda site with an invokedynamic call of to lambda 262 * meta-factory, which will use the lambda method. 263 * @param tree 264 */ 265 @Override 266 public void visitLambda(JCLambda tree) { 267 LambdaTranslationContext localContext = (LambdaTranslationContext)context; 268 MethodSymbol sym = localContext.translatedSym; 269 MethodType lambdaType = (MethodType) sym.type; 270 271 { 272 Symbol owner = localContext.owner; 273 ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>(); 274 ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>(); 275 276 for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) { 277 if (tc.position.onLambda == tree) { 278 lambdaTypeAnnos.append(tc); 279 } else { 280 ownerTypeAnnos.append(tc); 281 } 282 } 283 if (lambdaTypeAnnos.nonEmpty()) { 284 owner.setTypeAttributes(ownerTypeAnnos.toList()); 285 sym.setTypeAttributes(lambdaTypeAnnos.toList()); 286 } 287 } 288 289 //create the method declaration hoisting the lambda body 290 JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field), 291 sym.name, 292 make.QualIdent(lambdaType.getReturnType().tsym), 293 List.<JCTypeParameter>nil(), 294 localContext.syntheticParams, 295 lambdaType.getThrownTypes() == null ? 296 List.<JCExpression>nil() : 297 make.Types(lambdaType.getThrownTypes()), 298 null, 299 null); 300 lambdaDecl.sym = sym; 301 lambdaDecl.type = lambdaType; 302 303 //translate lambda body 304 //As the lambda body is translated, all references to lambda locals, 305 //captured variables, enclosing members are adjusted accordingly 306 //to refer to the static method parameters (rather than i.e. acessing to 307 //captured members directly). 308 lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl)); 309 310 //Add the method to the list of methods to be added to this class. 311 kInfo.addMethod(lambdaDecl); 312 313 //now that we have generated a method for the lambda expression, 314 //we can translate the lambda into a method reference pointing to the newly 315 //created method. 316 // 317 //Note that we need to adjust the method handle so that it will match the 318 //signature of the SAM descriptor - this means that the method reference 319 //should be added the following synthetic arguments: 320 // 321 // * the "this" argument if it is an instance method 322 // * enclosing locals captured by the lambda expression 323 324 ListBuffer<JCExpression> syntheticInits = new ListBuffer<>(); 325 326 if (localContext.methodReferenceReceiver != null) { 327 syntheticInits.append(localContext.methodReferenceReceiver); 328 } else if (!sym.isStatic()) { 329 syntheticInits.append(makeThis( 330 sym.owner.enclClass().asType(), 331 localContext.owner.enclClass())); 332 } 333 334 //add captured locals 335 for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) { 336 if (fv != localContext.self) { 337 JCTree captured_local = make.Ident(fv).setType(fv.type); 338 syntheticInits.append((JCExpression) captured_local); 339 } 340 } 341 342 //then, determine the arguments to the indy call 343 List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev); 344 345 //build a sam instance using an indy call to the meta-factory 346 int refKind = referenceKind(sym); 347 348 //convert to an invokedynamic call 349 result = makeMetafactoryIndyCall(context, refKind, sym, indy_args); 350 } 351 352 private JCIdent makeThis(Type type, Symbol owner) { 353 VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC, 354 names._this, 355 type, 356 owner); 357 return make.Ident(_this); 358 } 359 360 /** 361 * Translate a method reference into an invokedynamic call to the 362 * meta-factory. 363 * @param tree 364 */ 365 @Override 366 public void visitReference(JCMemberReference tree) { 367 ReferenceTranslationContext localContext = (ReferenceTranslationContext)context; 368 369 //first determine the method symbol to be used to generate the sam instance 370 //this is either the method reference symbol, or the bridged reference symbol 371 Symbol refSym = localContext.isSignaturePolymorphic() 372 ? localContext.sigPolySym 373 : tree.sym; 374 375 //the qualifying expression is treated as a special captured arg 376 JCExpression init; 377 switch(tree.kind) { 378 379 case IMPLICIT_INNER: /** Inner :: new */ 380 case SUPER: /** super :: instMethod */ 381 init = makeThis( 382 localContext.owner.enclClass().asType(), 383 localContext.owner.enclClass()); 384 break; 385 386 case BOUND: /** Expr :: instMethod */ 387 init = tree.getQualifierExpression(); 388 init = attr.makeNullCheck(init); 389 break; 390 391 case UNBOUND: /** Type :: instMethod */ 392 case STATIC: /** Type :: staticMethod */ 393 case TOPLEVEL: /** Top level :: new */ 394 case ARRAY_CTOR: /** ArrayType :: new */ 395 init = null; 396 break; 397 398 default: 399 throw new InternalError("Should not have an invalid kind"); 400 } 401 402 List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev); 403 404 405 //build a sam instance using an indy call to the meta-factory 406 result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args); 407 } 408 409 /** 410 * Translate identifiers within a lambda to the mapped identifier 411 * @param tree 412 */ 413 @Override 414 public void visitIdent(JCIdent tree) { 415 if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) { 416 super.visitIdent(tree); 417 } else { 418 int prevPos = make.pos; 419 try { 420 make.at(tree); 421 422 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; 423 JCTree ltree = lambdaContext.translate(tree); 424 if (ltree != null) { 425 result = ltree; 426 } else { 427 //access to untranslated symbols (i.e. compile-time constants, 428 //members defined inside the lambda body, etc.) ) 429 super.visitIdent(tree); 430 } 431 } finally { 432 make.at(prevPos); 433 } 434 } 435 } 436 437 @Override 438 public void visitVarDef(JCVariableDecl tree) { 439 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context; 440 if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { 441 tree.init = translate(tree.init); 442 tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym); 443 result = tree; 444 } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) { 445 JCExpression init = translate(tree.init); 446 VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym); 447 int prevPos = make.pos; 448 try { 449 result = make.at(tree).VarDef(xsym, init); 450 } finally { 451 make.at(prevPos); 452 } 453 // Replace the entered symbol for this variable 454 WriteableScope sc = tree.sym.owner.members(); 455 if (sc != null) { 456 sc.remove(tree.sym); 457 sc.enter(xsym); 458 } 459 } else { 460 super.visitVarDef(tree); 461 } 462 } 463 464 // </editor-fold> 465 466 // <editor-fold defaultstate="collapsed" desc="Translation helper methods"> 467 468 private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) { 469 return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ? 470 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) : 471 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally); 472 } 473 474 private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) { 475 Type restype = lambdaMethodDecl.type.getReturnType(); 476 boolean isLambda_void = expr.type.hasTag(VOID); 477 boolean isTarget_void = restype.hasTag(VOID); 478 boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); 479 int prevPos = make.pos; 480 try { 481 if (isTarget_void) { 482 //target is void: 483 // BODY; 484 JCStatement stat = make.at(expr).Exec(expr); 485 return make.Block(0, List.<JCStatement>of(stat)); 486 } else if (isLambda_void && isTarget_Void) { 487 //void to Void conversion: 488 // BODY; return null; 489 ListBuffer<JCStatement> stats = new ListBuffer<>(); 490 stats.append(make.at(expr).Exec(expr)); 491 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); 492 return make.Block(0, stats.toList()); 493 } else { 494 //non-void to non-void conversion: 495 // return (TYPE)BODY; 496 JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype); 497 return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr))); 498 } 499 } finally { 500 make.at(prevPos); 501 } 502 } 503 504 private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) { 505 final Type restype = lambdaMethodDecl.type.getReturnType(); 506 final boolean isTarget_void = restype.hasTag(VOID); 507 boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); 508 509 class LambdaBodyTranslator extends TreeTranslator { 510 511 @Override 512 public void visitClassDef(JCClassDecl tree) { 513 //do NOT recurse on any inner classes 514 result = tree; 515 } 516 517 @Override 518 public void visitLambda(JCLambda tree) { 519 //do NOT recurse on any nested lambdas 520 result = tree; 521 } 522 523 @Override 524 public void visitReturn(JCReturn tree) { 525 boolean isLambda_void = tree.expr == null; 526 if (isTarget_void && !isLambda_void) { 527 //Void to void conversion: 528 // { TYPE $loc = RET-EXPR; return; } 529 VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym); 530 JCVariableDecl varDef = make.VarDef(loc, tree.expr); 531 result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null))); 532 } else if (!isTarget_void || !isLambda_void) { 533 //non-void to non-void conversion: 534 // return (TYPE)RET-EXPR; 535 tree.expr = transTypes.coerce(attrEnv, tree.expr, restype); 536 result = tree; 537 } else { 538 result = tree; 539 } 540 541 } 542 } 543 544 JCBlock trans_block = new LambdaBodyTranslator().translate(block); 545 if (completeNormally && isTarget_Void) { 546 //there's no return statement and the lambda (possibly inferred) 547 //return type is java.lang.Void; emit a synthetic return statement 548 trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); 549 } 550 return trans_block; 551 } 552 553 private JCMethodDecl makeDeserializeMethod(Symbol kSym) { 554 ListBuffer<JCCase> cases = new ListBuffer<>(); 555 ListBuffer<JCBreak> breaks = new ListBuffer<>(); 556 for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) { 557 JCBreak br = make.Break(null); 558 breaks.add(br); 559 List<JCStatement> stmts = entry.getValue().append(br).toList(); 560 cases.add(make.Case(make.Literal(entry.getKey()), stmts)); 561 } 562 JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList()); 563 for (JCBreak br : breaks) { 564 br.target = sw; 565 } 566 JCBlock body = make.Block(0L, List.<JCStatement>of( 567 sw, 568 make.Throw(makeNewClass( 569 syms.illegalArgumentExceptionType, 570 List.<JCExpression>of(make.Literal("Invalid lambda deserialization")))))); 571 JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()), 572 names.deserializeLambda, 573 make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym), 574 List.<JCTypeParameter>nil(), 575 List.of(make.VarDef(kInfo.deserParamSym, null)), 576 List.<JCExpression>nil(), 577 body, 578 null); 579 deser.sym = kInfo.deserMethodSym; 580 deser.type = kInfo.deserMethodSym.type; 581 //System.err.printf("DESER: '%s'\n", deser); 582 return deser; 583 } 584 585 /** Make an attributed class instance creation expression. 586 * @param ctype The class type. 587 * @param args The constructor arguments. 588 * @param cons The constructor symbol 589 */ 590 JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) { 591 JCNewClass tree = make.NewClass(null, 592 null, make.QualIdent(ctype.tsym), args, null); 593 tree.constructor = cons; 594 tree.type = ctype; 595 return tree; 596 } 597 598 /** Make an attributed class instance creation expression. 599 * @param ctype The class type. 600 * @param args The constructor arguments. 601 */ 602 JCNewClass makeNewClass(Type ctype, List<JCExpression> args) { 603 return makeNewClass(ctype, args, 604 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil())); 605 } 606 607 private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, 608 DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) { 609 String functionalInterfaceClass = classSig(targetType); 610 String functionalInterfaceMethodName = samSym.getSimpleName().toString(); 611 String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type)); 612 String implClass = classSig(types.erasure(refSym.owner.type)); 613 String implMethodName = refSym.getQualifiedName().toString(); 614 String implMethodSignature = typeSig(types.erasure(refSym.type)); 615 616 JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind)); 617 ListBuffer<JCExpression> serArgs = new ListBuffer<>(); 618 int i = 0; 619 for (Type t : indyType.getParameterTypes()) { 620 List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList(); 621 List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList(); 622 serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg))); 623 ++i; 624 } 625 JCStatement stmt = make.If( 626 deserTest(deserTest(deserTest(deserTest(deserTest( 627 kindTest, 628 "getFunctionalInterfaceClass", functionalInterfaceClass), 629 "getFunctionalInterfaceMethodName", functionalInterfaceMethodName), 630 "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature), 631 "getImplClass", implClass), 632 "getImplMethodSignature", implMethodSignature), 633 make.Return(makeIndyCall( 634 pos, 635 syms.lambdaMetafactory, 636 names.altMetafactory, 637 staticArgs, indyType, serArgs.toList(), samSym.name)), 638 null); 639 ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName); 640 if (stmts == null) { 641 stmts = new ListBuffer<>(); 642 kInfo.deserializeCases.put(implMethodName, stmts); 643 } 644 /**** 645 System.err.printf("+++++++++++++++++\n"); 646 System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass); 647 System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName); 648 System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature); 649 System.err.printf("*implMethodKind: %d\n", implMethodKind); 650 System.err.printf("*implClass: '%s'\n", implClass); 651 System.err.printf("*implMethodName: '%s'\n", implMethodName); 652 System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature); 653 ****/ 654 stmts.append(stmt); 655 } 656 657 private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) { 658 JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2); 659 testExpr.operator = operators.resolveBinary(testExpr, JCTree.Tag.EQ, argType, argType); 660 testExpr.setType(syms.booleanType); 661 return testExpr; 662 } 663 664 private JCExpression deserTest(JCExpression prev, String func, String lit) { 665 MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass); 666 Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil()); 667 JCMethodInvocation eqtest = make.Apply( 668 List.<JCExpression>nil(), 669 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt), 670 List.<JCExpression>of(make.Literal(lit))); 671 eqtest.setType(syms.booleanType); 672 JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest); 673 compound.operator = operators.resolveBinary(compound, JCTree.Tag.AND, syms.booleanType, syms.booleanType); 674 compound.setType(syms.booleanType); 675 return compound; 676 } 677 678 private JCExpression deserGetter(String func, Type type) { 679 return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil()); 680 } 681 682 private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) { 683 MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass); 684 Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil()); 685 return make.Apply( 686 List.<JCExpression>nil(), 687 make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt), 688 args).setType(type); 689 } 690 691 /** 692 * Create new synthetic method with given flags, name, type, owner 693 */ 694 private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) { 695 return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner); 696 } 697 698 /** 699 * Create new synthetic variable with given flags, name, type, owner 700 */ 701 private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) { 702 return makeSyntheticVar(flags, names.fromString(name), type, owner); 703 } 704 705 /** 706 * Create new synthetic variable with given flags, name, type, owner 707 */ 708 private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) { 709 return new VarSymbol(flags | SYNTHETIC, name, type, owner); 710 } 711 712 /** 713 * Set varargsElement field on a given tree (must be either a new class tree 714 * or a method call tree) 715 */ 716 private void setVarargsIfNeeded(JCTree tree, Type varargsElement) { 717 if (varargsElement != null) { 718 switch (tree.getTag()) { 719 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break; 720 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break; 721 default: throw new AssertionError(); 722 } 723 } 724 } 725 726 /** 727 * Convert method/constructor arguments by inserting appropriate cast 728 * as required by type-erasure - this is needed when bridging a lambda/method 729 * reference, as the bridged signature might require downcast to be compatible 730 * with the generated signature. 731 */ 732 private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) { 733 Assert.check(meth.kind == MTH); 734 List<Type> formals = types.erasure(meth.type).getParameterTypes(); 735 if (varargsElement != null) { 736 Assert.check((meth.flags() & VARARGS) != 0); 737 } 738 return transTypes.translateArgs(args, formals, varargsElement, attrEnv); 739 } 740 741 // </editor-fold> 742 743 /** 744 * Converts a method reference which cannot be used directly into a lambda 745 */ 746 private class MemberReferenceToLambda { 747 748 private final JCMemberReference tree; 749 private final ReferenceTranslationContext localContext; 750 private final Symbol owner; 751 private final ListBuffer<JCExpression> args = new ListBuffer<>(); 752 private final ListBuffer<JCVariableDecl> params = new ListBuffer<>(); 753 754 private JCExpression receiverExpression = null; 755 756 MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) { 757 this.tree = tree; 758 this.localContext = localContext; 759 this.owner = owner; 760 } 761 762 JCLambda lambda() { 763 int prevPos = make.pos; 764 try { 765 make.at(tree); 766 767 //body generation - this can be either a method call or a 768 //new instance creation expression, depending on the member reference kind 769 VarSymbol rcvr = addParametersReturnReceiver(); 770 JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) 771 ? expressionInvoke(rcvr) 772 : expressionNew(); 773 774 JCLambda slam = make.Lambda(params.toList(), expr); 775 slam.targets = tree.targets; 776 slam.type = tree.type; 777 slam.pos = tree.pos; 778 return slam; 779 } finally { 780 make.at(prevPos); 781 } 782 } 783 784 /** 785 * Generate the parameter list for the converted member reference. 786 * 787 * @return The receiver variable symbol, if any 788 */ 789 VarSymbol addParametersReturnReceiver() { 790 Type samDesc = localContext.bridgedRefSig(); 791 List<Type> samPTypes = samDesc.getParameterTypes(); 792 List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes(); 793 794 // Determine the receiver, if any 795 VarSymbol rcvr; 796 switch (tree.kind) { 797 case BOUND: 798 // The receiver is explicit in the method reference 799 rcvr = addParameter("rec$", tree.getQualifierExpression().type, false); 800 receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); 801 break; 802 case UNBOUND: 803 // The receiver is the first parameter, extract it and 804 // adjust the SAM and unerased type lists accordingly 805 rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false); 806 samPTypes = samPTypes.tail; 807 descPTypes = descPTypes.tail; 808 break; 809 default: 810 rcvr = null; 811 break; 812 } 813 List<Type> implPTypes = tree.sym.type.getParameterTypes(); 814 int implSize = implPTypes.size(); 815 int samSize = samPTypes.size(); 816 // Last parameter to copy from referenced method, exclude final var args 817 int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize; 818 819 // Failsafe -- assure match-up 820 boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size(); 821 822 // Use parameter types of the implementation method unless the unerased 823 // SAM parameter type is an intersection type, in that case use the 824 // erased SAM parameter type so that the supertype relationship 825 // the implementation method parameters is not obscured. 826 // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes 827 // are used as pointers to the current parameter type information 828 // and are thus not usable afterwards. 829 for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { 830 // By default use the implementation method parmeter type 831 Type parmType = implPTypes.head; 832 // If the unerased parameter type is a type variable whose 833 // bound is an intersection (eg. <T extends A & B>) then 834 // use the SAM parameter type 835 if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) { 836 TypeVar tv = (TypeVar) descPTypes.head; 837 if (tv.bound.getKind() == TypeKind.INTERSECTION) { 838 parmType = samPTypes.head; 839 } 840 } 841 addParameter("x$" + i, parmType, true); 842 843 // Advance to the next parameter 844 implPTypes = implPTypes.tail; 845 samPTypes = samPTypes.tail; 846 descPTypes = descPTypes.tail; 847 } 848 // Flatten out the var args 849 for (int i = last; i < samSize; ++i) { 850 addParameter("xva$" + i, tree.varargsElement, true); 851 } 852 853 return rcvr; 854 } 855 856 JCExpression getReceiverExpression() { 857 return receiverExpression; 858 } 859 860 private JCExpression makeReceiver(VarSymbol rcvr) { 861 if (rcvr == null) return null; 862 JCExpression rcvrExpr = make.Ident(rcvr); 863 Type rcvrType = tree.sym.enclClass().type; 864 if (rcvrType == syms.arrayClass.type) { 865 // Map the receiver type to the actually type, not just "array" 866 rcvrType = tree.getQualifierExpression().type; 867 } 868 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { 869 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); 870 } 871 return rcvrExpr; 872 } 873 874 /** 875 * determine the receiver of the method call - the receiver can 876 * be a type qualifier, the synthetic receiver parameter or 'super'. 877 */ 878 private JCExpression expressionInvoke(VarSymbol rcvr) { 879 JCExpression qualifier = 880 (rcvr != null) ? 881 makeReceiver(rcvr) : 882 tree.getQualifierExpression(); 883 884 //create the qualifier expression 885 JCFieldAccess select = make.Select(qualifier, tree.sym.name); 886 select.sym = tree.sym; 887 select.type = tree.sym.erasure(types); 888 889 //create the method call expression 890 JCExpression apply = make.Apply(List.<JCExpression>nil(), select, 891 convertArgs(tree.sym, args.toList(), tree.varargsElement)). 892 setType(tree.sym.erasure(types).getReturnType()); 893 894 apply = transTypes.coerce(attrEnv, apply, 895 types.erasure(localContext.tree.referentType.getReturnType())); 896 897 setVarargsIfNeeded(apply, tree.varargsElement); 898 return apply; 899 } 900 901 /** 902 * Lambda body to use for a 'new'. 903 */ 904 private JCExpression expressionNew() { 905 if (tree.kind == ReferenceKind.ARRAY_CTOR) { 906 //create the array creation expression 907 JCNewArray newArr = make.NewArray( 908 make.Type(types.elemtype(tree.getQualifierExpression().type)), 909 List.of(make.Ident(params.first())), 910 null); 911 newArr.type = tree.getQualifierExpression().type; 912 return newArr; 913 } else { 914 //create the instance creation expression 915 //note that method reference syntax does not allow an explicit 916 //enclosing class (so the enclosing class is null) 917 JCNewClass newClass = make.NewClass(null, 918 List.<JCExpression>nil(), 919 make.Type(tree.getQualifierExpression().type), 920 convertArgs(tree.sym, args.toList(), tree.varargsElement), 921 null); 922 newClass.constructor = tree.sym; 923 newClass.constructorType = tree.sym.erasure(types); 924 newClass.type = tree.getQualifierExpression().type; 925 setVarargsIfNeeded(newClass, tree.varargsElement); 926 return newClass; 927 } 928 } 929 930 private VarSymbol addParameter(String name, Type p, boolean genArg) { 931 VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner); 932 vsym.pos = tree.pos; 933 params.append(make.VarDef(vsym, null)); 934 if (genArg) { 935 args.append(make.Ident(vsym)); 936 } 937 return vsym; 938 } 939 } 940 941 private MethodType typeToMethodType(Type mt) { 942 Type type = types.erasure(mt); 943 return new MethodType(type.getParameterTypes(), 944 type.getReturnType(), 945 type.getThrownTypes(), 946 syms.methodClass); 947 } 948 949 /** 950 * Generate an indy method call to the meta factory 951 */ 952 private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context, 953 int refKind, Symbol refSym, List<JCExpression> indy_args) { 954 JCFunctionalExpression tree = context.tree; 955 //determine the static bsm args 956 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym); 957 List<Object> staticArgs = List.<Object>of( 958 typeToMethodType(samSym.type), 959 new Pool.MethodHandle(refKind, refSym, types), 960 typeToMethodType(tree.getDescriptorType(types))); 961 962 //computed indy arg types 963 ListBuffer<Type> indy_args_types = new ListBuffer<>(); 964 for (JCExpression arg : indy_args) { 965 indy_args_types.append(arg.type); 966 } 967 968 //finally, compute the type of the indy call 969 MethodType indyType = new MethodType(indy_args_types.toList(), 970 tree.type, 971 List.<Type>nil(), 972 syms.methodClass); 973 974 Name metafactoryName = context.needsAltMetafactory() ? 975 names.altMetafactory : names.metafactory; 976 977 if (context.needsAltMetafactory()) { 978 ListBuffer<Object> markers = new ListBuffer<>(); 979 for (Type t : tree.targets.tail) { 980 if (t.tsym != syms.serializableType.tsym) { 981 markers.append(t.tsym); 982 } 983 } 984 int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0; 985 boolean hasMarkers = markers.nonEmpty(); 986 boolean hasBridges = context.bridges.nonEmpty(); 987 if (hasMarkers) { 988 flags |= FLAG_MARKERS; 989 } 990 if (hasBridges) { 991 flags |= FLAG_BRIDGES; 992 } 993 staticArgs = staticArgs.append(flags); 994 if (hasMarkers) { 995 staticArgs = staticArgs.append(markers.length()); 996 staticArgs = staticArgs.appendList(markers.toList()); 997 } 998 if (hasBridges) { 999 staticArgs = staticArgs.append(context.bridges.length() - 1); 1000 for (Symbol s : context.bridges) { 1001 Type s_erasure = s.erasure(types); 1002 if (!types.isSameType(s_erasure, samSym.erasure(types))) { 1003 staticArgs = staticArgs.append(s.erasure(types)); 1004 } 1005 } 1006 } 1007 if (context.isSerializable()) { 1008 int prevPos = make.pos; 1009 try { 1010 make.at(kInfo.clazz); 1011 addDeserializationCase(refKind, refSym, tree.type, samSym, 1012 tree, staticArgs, indyType); 1013 } finally { 1014 make.at(prevPos); 1015 } 1016 } 1017 } 1018 1019 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name); 1020 } 1021 1022 /** 1023 * Generate an indy method call with given name, type and static bootstrap 1024 * arguments types 1025 */ 1026 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, 1027 List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs, 1028 Name methName) { 1029 int prevPos = make.pos; 1030 try { 1031 make.at(pos); 1032 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType, 1033 syms.stringType, 1034 syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs)); 1035 1036 Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site, 1037 bsmName, bsm_staticArgs, List.<Type>nil()); 1038 1039 DynamicMethodSymbol dynSym = 1040 new DynamicMethodSymbol(methName, 1041 syms.noSymbol, 1042 bsm.isStatic() ? 1043 ClassFile.REF_invokeStatic : 1044 ClassFile.REF_invokeVirtual, 1045 (MethodSymbol)bsm, 1046 indyType, 1047 staticArgs.toArray()); 1048 1049 JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName); 1050 qualifier.sym = dynSym; 1051 qualifier.type = indyType.getReturnType(); 1052 1053 JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs); 1054 proxyCall.type = indyType.getReturnType(); 1055 return proxyCall; 1056 } finally { 1057 make.at(prevPos); 1058 } 1059 } 1060 //where 1061 private List<Type> bsmStaticArgToTypes(List<Object> args) { 1062 ListBuffer<Type> argtypes = new ListBuffer<>(); 1063 for (Object arg : args) { 1064 argtypes.append(bsmStaticArgToType(arg)); 1065 } 1066 return argtypes.toList(); 1067 } 1068 1069 private Type bsmStaticArgToType(Object arg) { 1070 Assert.checkNonNull(arg); 1071 if (arg instanceof ClassSymbol) { 1072 return syms.classType; 1073 } else if (arg instanceof Integer) { 1074 return syms.intType; 1075 } else if (arg instanceof Long) { 1076 return syms.longType; 1077 } else if (arg instanceof Float) { 1078 return syms.floatType; 1079 } else if (arg instanceof Double) { 1080 return syms.doubleType; 1081 } else if (arg instanceof String) { 1082 return syms.stringType; 1083 } else if (arg instanceof Pool.MethodHandle) { 1084 return syms.methodHandleType; 1085 } else if (arg instanceof MethodType) { 1086 return syms.methodTypeType; 1087 } else { 1088 Assert.error("bad static arg " + arg.getClass()); 1089 return null; 1090 } 1091 } 1092 1093 /** 1094 * Get the opcode associated with this method reference 1095 */ 1096 private int referenceKind(Symbol refSym) { 1097 if (refSym.isConstructor()) { 1098 return ClassFile.REF_newInvokeSpecial; 1099 } else { 1100 if (refSym.isStatic()) { 1101 return ClassFile.REF_invokeStatic; 1102 } else if ((refSym.flags() & PRIVATE) != 0) { 1103 return ClassFile.REF_invokeSpecial; 1104 } else if (refSym.enclClass().isInterface()) { 1105 return ClassFile.REF_invokeInterface; 1106 } else { 1107 return ClassFile.REF_invokeVirtual; 1108 } 1109 } 1110 } 1111 1112 // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer"> 1113 /** 1114 * This visitor collects information about translation of a lambda expression. 1115 * More specifically, it keeps track of the enclosing contexts and captured locals 1116 * accessed by the lambda being translated (as well as other useful info). 1117 * It also translates away problems for LambdaToMethod. 1118 */ 1119 class LambdaAnalyzerPreprocessor extends TreeTranslator { 1120 1121 /** the frame stack - used to reconstruct translation info about enclosing scopes */ 1122 private List<Frame> frameStack; 1123 1124 /** 1125 * keep the count of lambda expression (used to generate unambiguous 1126 * names) 1127 */ 1128 private int lambdaCount = 0; 1129 1130 /** 1131 * keep the count of lambda expression defined in given context (used to 1132 * generate unambiguous names for serializable lambdas) 1133 */ 1134 private class SyntheticMethodNameCounter { 1135 private Map<String, Integer> map = new HashMap<>(); 1136 int getIndex(StringBuilder buf) { 1137 String temp = buf.toString(); 1138 Integer count = map.get(temp); 1139 if (count == null) { 1140 count = 0; 1141 } 1142 ++count; 1143 map.put(temp, count); 1144 return count; 1145 } 1146 } 1147 private SyntheticMethodNameCounter syntheticMethodNameCounts = 1148 new SyntheticMethodNameCounter(); 1149 1150 private Map<Symbol, JCClassDecl> localClassDefs; 1151 1152 /** 1153 * maps for fake clinit symbols to be used as owners of lambda occurring in 1154 * a static var init context 1155 */ 1156 private Map<ClassSymbol, Symbol> clinits = new HashMap<>(); 1157 1158 private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) { 1159 frameStack = List.nil(); 1160 localClassDefs = new HashMap<>(); 1161 return translate(tree); 1162 } 1163 1164 @Override 1165 public void visitBlock(JCBlock tree) { 1166 List<Frame> prevStack = frameStack; 1167 try { 1168 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) { 1169 frameStack = frameStack.prepend(new Frame(tree)); 1170 } 1171 super.visitBlock(tree); 1172 } 1173 finally { 1174 frameStack = prevStack; 1175 } 1176 } 1177 1178 @Override 1179 public void visitClassDef(JCClassDecl tree) { 1180 List<Frame> prevStack = frameStack; 1181 int prevLambdaCount = lambdaCount; 1182 SyntheticMethodNameCounter prevSyntheticMethodNameCounts = 1183 syntheticMethodNameCounts; 1184 Map<ClassSymbol, Symbol> prevClinits = clinits; 1185 DiagnosticSource prevSource = log.currentSource(); 1186 try { 1187 log.useSource(tree.sym.sourcefile); 1188 lambdaCount = 0; 1189 syntheticMethodNameCounts = new SyntheticMethodNameCounter(); 1190 prevClinits = new HashMap<>(); 1191 if (tree.sym.owner.kind == MTH) { 1192 localClassDefs.put(tree.sym, tree); 1193 } 1194 if (directlyEnclosingLambda() != null) { 1195 tree.sym.owner = owner(); 1196 if (tree.sym.hasOuterInstance()) { 1197 //if a class is defined within a lambda, the lambda must capture 1198 //its enclosing instance (if any) 1199 TranslationContext<?> localContext = context(); 1200 while (localContext != null) { 1201 if (localContext.tree.getTag() == LAMBDA) { 1202 ((LambdaTranslationContext)localContext) 1203 .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS); 1204 } 1205 localContext = localContext.prev; 1206 } 1207 } 1208 } 1209 frameStack = frameStack.prepend(new Frame(tree)); 1210 super.visitClassDef(tree); 1211 } 1212 finally { 1213 log.useSource(prevSource.getFile()); 1214 frameStack = prevStack; 1215 lambdaCount = prevLambdaCount; 1216 syntheticMethodNameCounts = prevSyntheticMethodNameCounts; 1217 clinits = prevClinits; 1218 } 1219 } 1220 1221 @Override 1222 public void visitIdent(JCIdent tree) { 1223 if (context() != null && lambdaIdentSymbolFilter(tree.sym)) { 1224 if (tree.sym.kind == VAR && 1225 tree.sym.owner.kind == MTH && 1226 tree.type.constValue() == null) { 1227 TranslationContext<?> localContext = context(); 1228 while (localContext != null) { 1229 if (localContext.tree.getTag() == LAMBDA) { 1230 JCTree block = capturedDecl(localContext.depth, tree.sym); 1231 if (block == null) break; 1232 ((LambdaTranslationContext)localContext) 1233 .addSymbol(tree.sym, CAPTURED_VAR); 1234 } 1235 localContext = localContext.prev; 1236 } 1237 } else if (tree.sym.owner.kind == TYP) { 1238 TranslationContext<?> localContext = context(); 1239 while (localContext != null) { 1240 if (localContext.tree.hasTag(LAMBDA)) { 1241 JCTree block = capturedDecl(localContext.depth, tree.sym); 1242 if (block == null) break; 1243 switch (block.getTag()) { 1244 case CLASSDEF: 1245 JCClassDecl cdecl = (JCClassDecl)block; 1246 ((LambdaTranslationContext)localContext) 1247 .addSymbol(cdecl.sym, CAPTURED_THIS); 1248 break; 1249 default: 1250 Assert.error("bad block kind"); 1251 } 1252 } 1253 localContext = localContext.prev; 1254 } 1255 } 1256 } 1257 super.visitIdent(tree); 1258 } 1259 1260 @Override 1261 public void visitLambda(JCLambda tree) { 1262 analyzeLambda(tree, "lambda.stat"); 1263 } 1264 1265 private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) { 1266 // Translation of the receiver expression must occur first 1267 JCExpression rcvr = translate(methodReferenceReceiver); 1268 LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1"); 1269 if (rcvr != null) { 1270 context.methodReferenceReceiver = rcvr; 1271 } 1272 } 1273 1274 private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) { 1275 List<Frame> prevStack = frameStack; 1276 try { 1277 LambdaTranslationContext context = new LambdaTranslationContext(tree); 1278 if (dumpLambdaToMethodStats) { 1279 log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym); 1280 } 1281 frameStack = frameStack.prepend(new Frame(tree)); 1282 for (JCVariableDecl param : tree.params) { 1283 context.addSymbol(param.sym, PARAM); 1284 frameStack.head.addLocal(param.sym); 1285 } 1286 contextMap.put(tree, context); 1287 super.visitLambda(tree); 1288 context.complete(); 1289 return context; 1290 } 1291 finally { 1292 frameStack = prevStack; 1293 } 1294 } 1295 1296 @Override 1297 public void visitMethodDef(JCMethodDecl tree) { 1298 List<Frame> prevStack = frameStack; 1299 try { 1300 frameStack = frameStack.prepend(new Frame(tree)); 1301 super.visitMethodDef(tree); 1302 } 1303 finally { 1304 frameStack = prevStack; 1305 } 1306 } 1307 1308 @Override 1309 public void visitNewClass(JCNewClass tree) { 1310 TypeSymbol def = tree.type.tsym; 1311 boolean inReferencedClass = currentlyInClass(def); 1312 boolean isLocal = def.isLocal(); 1313 if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) { 1314 TranslationContext<?> localContext = context(); 1315 while (localContext != null) { 1316 if (localContext.tree.getTag() == LAMBDA) { 1317 ((LambdaTranslationContext)localContext) 1318 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS); 1319 } 1320 localContext = localContext.prev; 1321 } 1322 } 1323 if (context() != null && !inReferencedClass && isLocal) { 1324 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context(); 1325 captureLocalClassDefs(def, lambdaContext); 1326 } 1327 super.visitNewClass(tree); 1328 } 1329 //where 1330 void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) { 1331 JCClassDecl localCDef = localClassDefs.get(csym); 1332 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) { 1333 BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() { 1334 @Override 1335 void addFreeVars(ClassSymbol c) { 1336 captureLocalClassDefs(c, lambdaContext); 1337 } 1338 @Override 1339 void visitSymbol(Symbol sym) { 1340 if (sym.kind == VAR && 1341 sym.owner.kind == MTH && 1342 ((VarSymbol)sym).getConstValue() == null) { 1343 TranslationContext<?> localContext = context(); 1344 while (localContext != null) { 1345 if (localContext.tree.getTag() == LAMBDA) { 1346 JCTree block = capturedDecl(localContext.depth, sym); 1347 if (block == null) break; 1348 ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR); 1349 } 1350 localContext = localContext.prev; 1351 } 1352 } 1353 } 1354 }; 1355 fvc.scan(localCDef); 1356 } 1357 } 1358 //where 1359 boolean currentlyInClass(Symbol csym) { 1360 for (Frame frame : frameStack) { 1361 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) { 1362 JCClassDecl cdef = (JCClassDecl) frame.tree; 1363 if (cdef.sym == csym) { 1364 return true; 1365 } 1366 } 1367 } 1368 return false; 1369 } 1370 1371 /** 1372 * Method references to local class constructors, may, if the local 1373 * class references local variables, have implicit constructor 1374 * parameters added in Lower; As a result, the invokedynamic bootstrap 1375 * information added in the LambdaToMethod pass will have the wrong 1376 * signature. Hooks between Lower and LambdaToMethod have been added to 1377 * handle normal "new" in this case. This visitor converts potentially 1378 * affected method references into a lambda containing a normal 1379 * expression. 1380 * 1381 * @param tree 1382 */ 1383 @Override 1384 public void visitReference(JCMemberReference tree) { 1385 ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree); 1386 contextMap.put(tree, rcontext); 1387 if (rcontext.needsConversionToLambda()) { 1388 // Convert to a lambda, and process as such 1389 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner()); 1390 analyzeLambda(conv.lambda(), conv.getReceiverExpression()); 1391 } else { 1392 super.visitReference(tree); 1393 if (dumpLambdaToMethodStats) { 1394 log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null); 1395 } 1396 } 1397 } 1398 1399 @Override 1400 public void visitSelect(JCFieldAccess tree) { 1401 if (context() != null && tree.sym.kind == VAR && 1402 (tree.sym.name == names._this || 1403 tree.sym.name == names._super)) { 1404 // A select of this or super means, if we are in a lambda, 1405 // we much have an instance context 1406 TranslationContext<?> localContext = context(); 1407 while (localContext != null) { 1408 if (localContext.tree.hasTag(LAMBDA)) { 1409 JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym); 1410 if (clazz == null) break; 1411 ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS); 1412 } 1413 localContext = localContext.prev; 1414 } 1415 } 1416 super.visitSelect(tree); 1417 } 1418 1419 @Override 1420 public void visitVarDef(JCVariableDecl tree) { 1421 TranslationContext<?> context = context(); 1422 LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)? 1423 (LambdaTranslationContext)context : 1424 null; 1425 if (ltc != null) { 1426 if (frameStack.head.tree.hasTag(LAMBDA)) { 1427 ltc.addSymbol(tree.sym, LOCAL_VAR); 1428 } 1429 // Check for type variables (including as type arguments). 1430 // If they occur within class nested in a lambda, mark for erasure 1431 Type type = tree.sym.asType(); 1432 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) { 1433 ltc.addSymbol(tree.sym, TYPE_VAR); 1434 } 1435 } 1436 1437 List<Frame> prevStack = frameStack; 1438 try { 1439 if (tree.sym.owner.kind == MTH) { 1440 frameStack.head.addLocal(tree.sym); 1441 } 1442 frameStack = frameStack.prepend(new Frame(tree)); 1443 super.visitVarDef(tree); 1444 } 1445 finally { 1446 frameStack = prevStack; 1447 } 1448 } 1449 1450 /** 1451 * Return a valid owner given the current declaration stack 1452 * (required to skip synthetic lambda symbols) 1453 */ 1454 private Symbol owner() { 1455 return owner(false); 1456 } 1457 1458 @SuppressWarnings("fallthrough") 1459 private Symbol owner(boolean skipLambda) { 1460 List<Frame> frameStack2 = frameStack; 1461 while (frameStack2.nonEmpty()) { 1462 switch (frameStack2.head.tree.getTag()) { 1463 case VARDEF: 1464 if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) { 1465 frameStack2 = frameStack2.tail; 1466 break; 1467 } 1468 JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree; 1469 return initSym(cdecl.sym, 1470 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC); 1471 case BLOCK: 1472 JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree; 1473 return initSym(cdecl2.sym, 1474 ((JCBlock)frameStack2.head.tree).flags & STATIC); 1475 case CLASSDEF: 1476 return ((JCClassDecl)frameStack2.head.tree).sym; 1477 case METHODDEF: 1478 return ((JCMethodDecl)frameStack2.head.tree).sym; 1479 case LAMBDA: 1480 if (!skipLambda) 1481 return ((LambdaTranslationContext)contextMap 1482 .get(frameStack2.head.tree)).translatedSym; 1483 default: 1484 frameStack2 = frameStack2.tail; 1485 } 1486 } 1487 Assert.error(); 1488 return null; 1489 } 1490 1491 private Symbol initSym(ClassSymbol csym, long flags) { 1492 boolean isStatic = (flags & STATIC) != 0; 1493 if (isStatic) { 1494 /* static clinits are generated in Gen, so we need to use a fake 1495 * one. Attr creates a fake clinit method while attributing 1496 * lambda expressions used as initializers of static fields, so 1497 * let's use that one. 1498 */ 1499 MethodSymbol clinit = attr.removeClinit(csym); 1500 if (clinit != null) { 1501 clinits.put(csym, clinit); 1502 return clinit; 1503 } 1504 1505 /* if no clinit is found at Attr, then let's try at clinits. 1506 */ 1507 clinit = (MethodSymbol)clinits.get(csym); 1508 if (clinit == null) { 1509 /* no luck, let's create a new one 1510 */ 1511 clinit = makePrivateSyntheticMethod(STATIC, 1512 names.clinit, 1513 new MethodType(List.<Type>nil(), syms.voidType, 1514 List.<Type>nil(), syms.methodClass), 1515 csym); 1516 clinits.put(csym, clinit); 1517 } 1518 return clinit; 1519 } else { 1520 //get the first constructor and treat it as the instance init sym 1521 for (Symbol s : csym.members_field.getSymbolsByName(names.init)) { 1522 return s; 1523 } 1524 } 1525 Assert.error("init not found"); 1526 return null; 1527 } 1528 1529 private JCTree directlyEnclosingLambda() { 1530 if (frameStack.isEmpty()) { 1531 return null; 1532 } 1533 List<Frame> frameStack2 = frameStack; 1534 while (frameStack2.nonEmpty()) { 1535 switch (frameStack2.head.tree.getTag()) { 1536 case CLASSDEF: 1537 case METHODDEF: 1538 return null; 1539 case LAMBDA: 1540 return frameStack2.head.tree; 1541 default: 1542 frameStack2 = frameStack2.tail; 1543 } 1544 } 1545 Assert.error(); 1546 return null; 1547 } 1548 1549 private boolean inClassWithinLambda() { 1550 if (frameStack.isEmpty()) { 1551 return false; 1552 } 1553 List<Frame> frameStack2 = frameStack; 1554 boolean classFound = false; 1555 while (frameStack2.nonEmpty()) { 1556 switch (frameStack2.head.tree.getTag()) { 1557 case LAMBDA: 1558 return classFound; 1559 case CLASSDEF: 1560 classFound = true; 1561 frameStack2 = frameStack2.tail; 1562 break; 1563 default: 1564 frameStack2 = frameStack2.tail; 1565 } 1566 } 1567 // No lambda 1568 return false; 1569 } 1570 1571 /** 1572 * Return the declaration corresponding to a symbol in the enclosing 1573 * scope; the depth parameter is used to filter out symbols defined 1574 * in nested scopes (which do not need to undergo capture). 1575 */ 1576 private JCTree capturedDecl(int depth, Symbol sym) { 1577 int currentDepth = frameStack.size() - 1; 1578 for (Frame block : frameStack) { 1579 switch (block.tree.getTag()) { 1580 case CLASSDEF: 1581 ClassSymbol clazz = ((JCClassDecl)block.tree).sym; 1582 if (sym.isMemberOf(clazz, types)) { 1583 return currentDepth > depth ? null : block.tree; 1584 } 1585 break; 1586 case VARDEF: 1587 if (((JCVariableDecl)block.tree).sym == sym && 1588 sym.owner.kind == MTH) { //only locals are captured 1589 return currentDepth > depth ? null : block.tree; 1590 } 1591 break; 1592 case BLOCK: 1593 case METHODDEF: 1594 case LAMBDA: 1595 if (block.locals != null && block.locals.contains(sym)) { 1596 return currentDepth > depth ? null : block.tree; 1597 } 1598 break; 1599 default: 1600 Assert.error("bad decl kind " + block.tree.getTag()); 1601 } 1602 currentDepth--; 1603 } 1604 return null; 1605 } 1606 1607 private TranslationContext<?> context() { 1608 for (Frame frame : frameStack) { 1609 TranslationContext<?> context = contextMap.get(frame.tree); 1610 if (context != null) { 1611 return context; 1612 } 1613 } 1614 return null; 1615 } 1616 1617 /** 1618 * This is used to filter out those identifiers that needs to be adjusted 1619 * when translating away lambda expressions 1620 */ 1621 private boolean lambdaIdentSymbolFilter(Symbol sym) { 1622 return (sym.kind == VAR || sym.kind == MTH) 1623 && !sym.isStatic() 1624 && sym.name != names.init; 1625 } 1626 1627 /** 1628 * This is used to filter out those new class expressions that need to 1629 * be qualified with an enclosing tree 1630 */ 1631 private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) { 1632 if (context != null 1633 && tree.encl == null 1634 && tree.def == null 1635 && !tree.type.getEnclosingType().hasTag(NONE)) { 1636 Type encl = tree.type.getEnclosingType(); 1637 Type current = context.owner.enclClass().type; 1638 while (!current.hasTag(NONE)) { 1639 if (current.tsym.isSubClass(encl.tsym, types)) { 1640 return true; 1641 } 1642 current = current.getEnclosingType(); 1643 } 1644 return false; 1645 } else { 1646 return false; 1647 } 1648 } 1649 1650 private class Frame { 1651 final JCTree tree; 1652 List<Symbol> locals; 1653 1654 public Frame(JCTree tree) { 1655 this.tree = tree; 1656 } 1657 1658 void addLocal(Symbol sym) { 1659 if (locals == null) { 1660 locals = List.nil(); 1661 } 1662 locals = locals.prepend(sym); 1663 } 1664 } 1665 1666 /** 1667 * This class is used to store important information regarding translation of 1668 * lambda expression/method references (see subclasses). 1669 */ 1670 private abstract class TranslationContext<T extends JCFunctionalExpression> { 1671 1672 /** the underlying (untranslated) tree */ 1673 final T tree; 1674 1675 /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */ 1676 final Symbol owner; 1677 1678 /** the depth of this lambda expression in the frame stack */ 1679 final int depth; 1680 1681 /** the enclosing translation context (set for nested lambdas/mref) */ 1682 final TranslationContext<?> prev; 1683 1684 /** list of methods to be bridged by the meta-factory */ 1685 final List<Symbol> bridges; 1686 1687 TranslationContext(T tree) { 1688 this.tree = tree; 1689 this.owner = owner(); 1690 this.depth = frameStack.size() - 1; 1691 this.prev = context(); 1692 ClassSymbol csym = 1693 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE); 1694 this.bridges = types.functionalInterfaceBridges(csym); 1695 } 1696 1697 /** does this functional expression need to be created using alternate metafactory? */ 1698 boolean needsAltMetafactory() { 1699 return tree.targets.length() > 1 || 1700 isSerializable() || 1701 bridges.length() > 1; 1702 } 1703 1704 /** does this functional expression require serialization support? */ 1705 boolean isSerializable() { 1706 if (forceSerializable) { 1707 return true; 1708 } 1709 for (Type target : tree.targets) { 1710 if (types.asSuper(target, syms.serializableType.tsym) != null) { 1711 return true; 1712 } 1713 } 1714 return false; 1715 } 1716 1717 /** 1718 * @return Name of the enclosing method to be folded into synthetic 1719 * method name 1720 */ 1721 String enclosingMethodName() { 1722 return syntheticMethodNameComponent(owner.name); 1723 } 1724 1725 /** 1726 * @return Method name in a form that can be folded into a 1727 * component of a synthetic method name 1728 */ 1729 String syntheticMethodNameComponent(Name name) { 1730 if (name == null) { 1731 return "null"; 1732 } 1733 String methodName = name.toString(); 1734 if (methodName.equals("<clinit>")) { 1735 methodName = "static"; 1736 } else if (methodName.equals("<init>")) { 1737 methodName = "new"; 1738 } 1739 return methodName; 1740 } 1741 } 1742 1743 /** 1744 * This class retains all the useful information about a lambda expression; 1745 * the contents of this class are filled by the LambdaAnalyzer visitor, 1746 * and the used by the main translation routines in order to adjust references 1747 * to captured locals/members, etc. 1748 */ 1749 private class LambdaTranslationContext extends TranslationContext<JCLambda> { 1750 1751 /** variable in the enclosing context to which this lambda is assigned */ 1752 final Symbol self; 1753 1754 /** variable in the enclosing context to which this lambda is assigned */ 1755 final Symbol assignedTo; 1756 1757 Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols; 1758 1759 /** the synthetic symbol for the method hoisting the translated lambda */ 1760 MethodSymbol translatedSym; 1761 1762 List<JCVariableDecl> syntheticParams; 1763 1764 /** 1765 * to prevent recursion, track local classes processed 1766 */ 1767 final Set<Symbol> freeVarProcessedLocalClasses; 1768 1769 /** 1770 * For method references converted to lambdas. The method 1771 * reference receiver expression. Must be treated like a captured 1772 * variable. 1773 */ 1774 JCExpression methodReferenceReceiver; 1775 1776 LambdaTranslationContext(JCLambda tree) { 1777 super(tree); 1778 Frame frame = frameStack.head; 1779 switch (frame.tree.getTag()) { 1780 case VARDEF: 1781 assignedTo = self = ((JCVariableDecl) frame.tree).sym; 1782 break; 1783 case ASSIGN: 1784 self = null; 1785 assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable()); 1786 break; 1787 default: 1788 assignedTo = self = null; 1789 break; 1790 } 1791 1792 // This symbol will be filled-in in complete 1793 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass()); 1794 1795 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class); 1796 1797 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>()); 1798 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>()); 1799 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>()); 1800 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>()); 1801 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>()); 1802 1803 freeVarProcessedLocalClasses = new HashSet<>(); 1804 } 1805 1806 /** 1807 * For a serializable lambda, generate a disambiguating string 1808 * which maximizes stability across deserialization. 1809 * 1810 * @return String to differentiate synthetic lambda method names 1811 */ 1812 private String serializedLambdaDisambiguation() { 1813 StringBuilder buf = new StringBuilder(); 1814 // Append the enclosing method signature to differentiate 1815 // overloaded enclosing methods. For lambdas enclosed in 1816 // lambdas, the generated lambda method will not have type yet, 1817 // but the enclosing method's name will have been generated 1818 // with this same method, so it will be unique and never be 1819 // overloaded. 1820 Assert.check( 1821 owner.type != null || 1822 directlyEnclosingLambda() != null); 1823 if (owner.type != null) { 1824 buf.append(typeSig(owner.type)); 1825 buf.append(":"); 1826 } 1827 1828 // Add target type info 1829 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName()); 1830 buf.append(" "); 1831 1832 // Add variable assigned to 1833 if (assignedTo != null) { 1834 buf.append(assignedTo.flatName()); 1835 buf.append("="); 1836 } 1837 //add captured locals info: type, name, order 1838 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) { 1839 if (fv != self) { 1840 buf.append(typeSig(fv.type)); 1841 buf.append(" "); 1842 buf.append(fv.flatName()); 1843 buf.append(","); 1844 } 1845 } 1846 1847 return buf.toString(); 1848 } 1849 1850 /** 1851 * For a non-serializable lambda, generate a simple method. 1852 * 1853 * @return Name to use for the synthetic lambda method name 1854 */ 1855 private Name lambdaName() { 1856 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++)); 1857 } 1858 1859 /** 1860 * For a serializable lambda, generate a method name which maximizes 1861 * name stability across deserialization. 1862 * 1863 * @return Name to use for the synthetic lambda method name 1864 */ 1865 private Name serializedLambdaName() { 1866 StringBuilder buf = new StringBuilder(); 1867 buf.append(names.lambda); 1868 // Append the name of the method enclosing the lambda. 1869 buf.append(enclosingMethodName()); 1870 buf.append('$'); 1871 // Append a hash of the disambiguating string : enclosing method 1872 // signature, etc. 1873 String disam = serializedLambdaDisambiguation(); 1874 buf.append(Integer.toHexString(disam.hashCode())); 1875 buf.append('$'); 1876 // The above appended name components may not be unique, append 1877 // a count based on the above name components. 1878 buf.append(syntheticMethodNameCounts.getIndex(buf)); 1879 String result = buf.toString(); 1880 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam); 1881 return names.fromString(result); 1882 } 1883 1884 /** 1885 * Translate a symbol of a given kind into something suitable for the 1886 * synthetic lambda body 1887 */ 1888 Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) { 1889 Symbol ret; 1890 switch (skind) { 1891 case CAPTURED_THIS: 1892 ret = sym; // self represented 1893 break; 1894 case TYPE_VAR: 1895 // Just erase the type var 1896 ret = new VarSymbol(sym.flags(), name, 1897 types.erasure(sym.type), sym.owner); 1898 1899 /* this information should also be kept for LVT generation at Gen 1900 * a Symbol with pos < startPos won't be tracked. 1901 */ 1902 ((VarSymbol)ret).pos = ((VarSymbol)sym).pos; 1903 break; 1904 case CAPTURED_VAR: 1905 ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) { 1906 @Override 1907 public Symbol baseSymbol() { 1908 //keep mapping with original captured symbol 1909 return sym; 1910 } 1911 }; 1912 break; 1913 case LOCAL_VAR: 1914 ret = new VarSymbol(sym.flags() & FINAL, name, sym.type, translatedSym); 1915 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 1916 break; 1917 case PARAM: 1918 ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, name, types.erasure(sym.type), translatedSym); 1919 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 1920 break; 1921 default: 1922 ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym); 1923 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 1924 } 1925 if (ret != sym) { 1926 ret.setDeclarationAttributes(sym.getRawAttributes()); 1927 ret.setTypeAttributes(sym.getRawTypeAttributes()); 1928 } 1929 return ret; 1930 } 1931 1932 void addSymbol(Symbol sym, LambdaSymbolKind skind) { 1933 Map<Symbol, Symbol> transMap = getSymbolMap(skind); 1934 Name preferredName; 1935 switch (skind) { 1936 case CAPTURED_THIS: 1937 preferredName = names.fromString("encl$" + transMap.size()); 1938 break; 1939 case CAPTURED_VAR: 1940 preferredName = names.fromString("cap$" + transMap.size()); 1941 break; 1942 case LOCAL_VAR: 1943 preferredName = sym.name; 1944 break; 1945 case PARAM: 1946 preferredName = sym.name; 1947 break; 1948 case TYPE_VAR: 1949 preferredName = sym.name; 1950 break; 1951 default: throw new AssertionError(); 1952 } 1953 if (!transMap.containsKey(sym)) { 1954 transMap.put(sym, translate(preferredName, sym, skind)); 1955 } 1956 } 1957 1958 Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) { 1959 Map<Symbol, Symbol> m = translatedSymbols.get(skind); 1960 Assert.checkNonNull(m); 1961 return m; 1962 } 1963 1964 JCTree translate(JCIdent lambdaIdent) { 1965 for (Map<Symbol, Symbol> m : translatedSymbols.values()) { 1966 if (m.containsKey(lambdaIdent.sym)) { 1967 Symbol tSym = m.get(lambdaIdent.sym); 1968 JCTree t = make.Ident(tSym).setType(lambdaIdent.type); 1969 tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes()); 1970 return t; 1971 } 1972 } 1973 return null; 1974 } 1975 1976 /** 1977 * The translatedSym is not complete/accurate until the analysis is 1978 * finished. Once the analysis is finished, the translatedSym is 1979 * "completed" -- updated with type information, access modifiers, 1980 * and full parameter list. 1981 */ 1982 void complete() { 1983 if (syntheticParams != null) { 1984 return; 1985 } 1986 boolean inInterface = translatedSym.owner.isInterface(); 1987 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty(); 1988 1989 // If instance access isn't needed, make it static. 1990 // Interface instance methods must be default methods. 1991 // Lambda methods are private synthetic. 1992 // Inherit ACC_STRICT from the enclosing method, or, for clinit, 1993 // from the class. 1994 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD | 1995 owner.flags_field & STRICTFP | 1996 owner.owner.flags_field & STRICTFP | 1997 PRIVATE | 1998 (thisReferenced? (inInterface? DEFAULT : 0) : STATIC); 1999 2000 //compute synthetic params 2001 ListBuffer<JCVariableDecl> params = new ListBuffer<>(); 2002 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>(); 2003 2004 // The signature of the method is augmented with the following 2005 // synthetic parameters: 2006 // 2007 // 1) reference to enclosing contexts captured by the lambda expression 2008 // 2) enclosing locals captured by the lambda expression 2009 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) { 2010 params.append(make.VarDef((VarSymbol) thisSym, null)); 2011 parameterSymbols.append((VarSymbol) thisSym); 2012 } 2013 for (Symbol thisSym : getSymbolMap(PARAM).values()) { 2014 params.append(make.VarDef((VarSymbol) thisSym, null)); 2015 parameterSymbols.append((VarSymbol) thisSym); 2016 } 2017 syntheticParams = params.toList(); 2018 2019 translatedSym.params = parameterSymbols.toList(); 2020 2021 // Compute and set the lambda name 2022 translatedSym.name = isSerializable() 2023 ? serializedLambdaName() 2024 : lambdaName(); 2025 2026 //prepend synthetic args to translated lambda method signature 2027 translatedSym.type = types.createMethodTypeWithParameters( 2028 generatedLambdaSig(), 2029 TreeInfo.types(syntheticParams)); 2030 } 2031 2032 Type generatedLambdaSig() { 2033 return types.erasure(tree.getDescriptorType(types)); 2034 } 2035 } 2036 2037 /** 2038 * This class retains all the useful information about a method reference; 2039 * the contents of this class are filled by the LambdaAnalyzer visitor, 2040 * and the used by the main translation routines in order to adjust method 2041 * references (i.e. in case a bridge is needed) 2042 */ 2043 private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> { 2044 2045 final boolean isSuper; 2046 final Symbol sigPolySym; 2047 2048 ReferenceTranslationContext(JCMemberReference tree) { 2049 super(tree); 2050 this.isSuper = tree.hasKind(ReferenceKind.SUPER); 2051 this.sigPolySym = isSignaturePolymorphic() 2052 ? makePrivateSyntheticMethod(tree.sym.flags(), 2053 tree.sym.name, 2054 bridgedRefSig(), 2055 tree.sym.enclClass()) 2056 : null; 2057 } 2058 2059 /** 2060 * Get the opcode associated with this method reference 2061 */ 2062 int referenceKind() { 2063 return LambdaToMethod.this.referenceKind(tree.sym); 2064 } 2065 2066 boolean needsVarArgsConversion() { 2067 return tree.varargsElement != null; 2068 } 2069 2070 /** 2071 * @return Is this an array operation like clone() 2072 */ 2073 boolean isArrayOp() { 2074 return tree.sym.owner == syms.arrayClass; 2075 } 2076 2077 boolean receiverAccessible() { 2078 //hack needed to workaround 292 bug (7087658) 2079 //when 292 issue is fixed we should remove this and change the backend 2080 //code to always generate a method handle to an accessible method 2081 return tree.ownerAccessible; 2082 } 2083 2084 /** 2085 * The VM does not support access across nested classes (8010319). 2086 * Were that ever to change, this should be removed. 2087 */ 2088 boolean isPrivateInOtherClass() { 2089 return (tree.sym.flags() & PRIVATE) != 0 && 2090 !types.isSameType( 2091 types.erasure(tree.sym.enclClass().asType()), 2092 types.erasure(owner.enclClass().asType())); 2093 } 2094 2095 /** 2096 * Signature polymorphic methods need special handling. 2097 * e.g. MethodHandle.invoke() MethodHandle.invokeExact() 2098 */ 2099 final boolean isSignaturePolymorphic() { 2100 return tree.sym.kind == MTH && 2101 types.isSignaturePolymorphic((MethodSymbol)tree.sym); 2102 } 2103 2104 /** 2105 * Erasure destroys the implementation parameter subtype 2106 * relationship for intersection types 2107 */ 2108 boolean interfaceParameterIsIntersectionType() { 2109 List<Type> tl = tree.getDescriptorType(types).getParameterTypes(); 2110 if (tree.kind == ReferenceKind.UNBOUND) { 2111 tl = tl.tail; 2112 } 2113 for (; tl.nonEmpty(); tl = tl.tail) { 2114 Type pt = tl.head; 2115 if (pt.getKind() == TypeKind.TYPEVAR) { 2116 TypeVar tv = (TypeVar) pt; 2117 if (tv.bound.getKind() == TypeKind.INTERSECTION) { 2118 return true; 2119 } 2120 } 2121 } 2122 return false; 2123 } 2124 2125 /** 2126 * Does this reference need to be converted to a lambda 2127 * (i.e. var args need to be expanded or "super" is used) 2128 */ 2129 final boolean needsConversionToLambda() { 2130 return interfaceParameterIsIntersectionType() || 2131 isSuper || 2132 needsVarArgsConversion() || 2133 isArrayOp() || 2134 isPrivateInOtherClass() || 2135 !receiverAccessible() || 2136 (tree.getMode() == ReferenceMode.NEW && 2137 tree.kind != ReferenceKind.ARRAY_CTOR && 2138 (tree.sym.owner.isLocal() || tree.sym.owner.isInner())); 2139 } 2140 2141 Type generatedRefSig() { 2142 return types.erasure(tree.sym.type); 2143 } 2144 2145 Type bridgedRefSig() { 2146 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type); 2147 } 2148 } 2149 } 2150 // </editor-fold> 2151 2152 /* 2153 * These keys provide mappings for various translated lambda symbols 2154 * and the prevailing order must be maintained. 2155 */ 2156 enum LambdaSymbolKind { 2157 PARAM, // original to translated lambda parameters 2158 LOCAL_VAR, // original to translated lambda locals 2159 CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters 2160 CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access) 2161 TYPE_VAR // original to translated lambda type variables 2162 } 2163 2164 /** 2165 * **************************************************************** 2166 * Signature Generation 2167 * **************************************************************** 2168 */ 2169 2170 private String typeSig(Type type) { 2171 L2MSignatureGenerator sg = new L2MSignatureGenerator(); 2172 sg.assembleSig(type); 2173 return sg.toString(); 2174 } 2175 2176 private String classSig(Type type) { 2177 L2MSignatureGenerator sg = new L2MSignatureGenerator(); 2178 sg.assembleClassSig(type); 2179 return sg.toString(); 2180 } 2181 2182 /** 2183 * Signature Generation 2184 */ 2185 private class L2MSignatureGenerator extends Types.SignatureGenerator { 2186 2187 /** 2188 * An output buffer for type signatures. 2189 */ 2190 StringBuilder sb = new StringBuilder(); 2191 2192 L2MSignatureGenerator() { 2193 super(types); 2194 } 2195 2196 @Override 2197 protected void append(char ch) { 2198 sb.append(ch); 2199 } 2200 2201 @Override 2202 protected void append(byte[] ba) { 2203 sb.append(new String(ba)); 2204 } 2205 2206 @Override 2207 protected void append(Name name) { 2208 sb.append(name.toString()); 2209 } 2210 2211 @Override 2212 public String toString() { 2213 return sb.toString(); 2214 } 2215 } 2216} 2217