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