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