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