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