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