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