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