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