1 /* 2 * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.comp; 27 28 import com.sun.tools.javac.code.Attribute; 29 import com.sun.tools.javac.code.Flags; 30 import com.sun.tools.javac.code.Symbol; 31 import com.sun.tools.javac.code.Symbol.ClassSymbol; 32 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; 33 import com.sun.tools.javac.code.Symbol.MethodHandleSymbol; 34 import com.sun.tools.javac.code.Symbol.MethodSymbol; 35 import com.sun.tools.javac.code.Symbol.VarSymbol; 36 import com.sun.tools.javac.code.Symtab; 37 import com.sun.tools.javac.code.Type; 38 import com.sun.tools.javac.code.Type.MethodType; 39 import com.sun.tools.javac.code.Types; 40 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException; 41 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; 42 import com.sun.tools.javac.main.Option; 43 import com.sun.tools.javac.resources.CompilerProperties.Errors; 44 import com.sun.tools.javac.resources.CompilerProperties.Fragments; 45 import com.sun.tools.javac.resources.CompilerProperties.Notes; 46 import com.sun.tools.javac.tree.JCTree; 47 import com.sun.tools.javac.tree.JCTree.JCAnnotation; 48 import com.sun.tools.javac.tree.JCTree.JCBinary; 49 import com.sun.tools.javac.tree.JCTree.JCBlock; 50 import com.sun.tools.javac.tree.JCTree.JCBreak; 51 import com.sun.tools.javac.tree.JCTree.JCCase; 52 import com.sun.tools.javac.tree.JCTree.JCClassDecl; 53 import com.sun.tools.javac.tree.JCTree.JCExpression; 54 import com.sun.tools.javac.tree.JCTree.JCFieldAccess; 55 import com.sun.tools.javac.tree.JCTree.JCFunctionalExpression; 56 import com.sun.tools.javac.tree.JCTree.JCIdent; 57 import com.sun.tools.javac.tree.JCTree.JCLambda; 58 import com.sun.tools.javac.tree.JCTree.JCMemberReference; 59 import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 60 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; 61 import com.sun.tools.javac.tree.JCTree.JCNewClass; 62 import com.sun.tools.javac.tree.JCTree.JCReturn; 63 import com.sun.tools.javac.tree.JCTree.JCStatement; 64 import com.sun.tools.javac.tree.JCTree.JCSwitch; 65 import com.sun.tools.javac.tree.JCTree.JCVariableDecl; 66 import com.sun.tools.javac.tree.JCTree.Tag; 67 import com.sun.tools.javac.tree.TreeInfo; 68 import com.sun.tools.javac.tree.TreeMaker; 69 import com.sun.tools.javac.tree.TreeTranslator; 70 import com.sun.tools.javac.util.Assert; 71 import com.sun.tools.javac.util.Context; 72 import com.sun.tools.javac.util.DiagnosticSource; 73 import com.sun.tools.javac.util.InvalidUtfException; 74 import com.sun.tools.javac.util.JCDiagnostic; 75 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 76 import com.sun.tools.javac.util.List; 77 import com.sun.tools.javac.util.ListBuffer; 78 import com.sun.tools.javac.util.Log; 79 import com.sun.tools.javac.util.Name; 80 import com.sun.tools.javac.util.Names; 81 import com.sun.tools.javac.util.Options; 82 83 import javax.lang.model.element.ElementKind; 84 import java.lang.invoke.LambdaMetafactory; 85 import java.util.HashMap; 86 import java.util.HashSet; 87 import java.util.Map; 88 import java.util.Set; 89 import java.util.function.Consumer; 90 import java.util.function.Supplier; 91 92 import static com.sun.tools.javac.code.Flags.ABSTRACT; 93 import static com.sun.tools.javac.code.Flags.BLOCK; 94 import static com.sun.tools.javac.code.Flags.DEFAULT; 95 import static com.sun.tools.javac.code.Flags.FINAL; 96 import static com.sun.tools.javac.code.Flags.INTERFACE; 97 import static com.sun.tools.javac.code.Flags.LAMBDA_METHOD; 98 import static com.sun.tools.javac.code.Flags.LOCAL_CAPTURE_FIELD; 99 import static com.sun.tools.javac.code.Flags.PARAMETER; 100 import static com.sun.tools.javac.code.Flags.PRIVATE; 101 import static com.sun.tools.javac.code.Flags.STATIC; 102 import static com.sun.tools.javac.code.Flags.STRICTFP; 103 import static com.sun.tools.javac.code.Flags.SYNTHETIC; 104 import static com.sun.tools.javac.code.Kinds.Kind.MTH; 105 import static com.sun.tools.javac.code.Kinds.Kind.TYP; 106 import static com.sun.tools.javac.code.Kinds.Kind.VAR; 107 import static com.sun.tools.javac.code.TypeTag.BOT; 108 import static com.sun.tools.javac.code.TypeTag.VOID; 109 110 /** 111 * This pass desugars lambda expressions into static methods 112 * 113 * <p><b>This is NOT part of any supported API. 114 * If you write code that depends on this, you do so at your own risk. 115 * This code and its internal interfaces are subject to change or 116 * deletion without notice.</b> 117 */ 118 public class LambdaToMethod extends TreeTranslator { 119 120 private final Attr attr; 121 private final JCDiagnostic.Factory diags; 122 private final Log log; 123 private final Lower lower; 124 private final Names names; 125 private final Symtab syms; 126 private final Resolve rs; 127 private final Operators operators; 128 private TreeMaker make; 129 private final Types types; 130 private final TransTypes transTypes; 131 private Env<AttrContext> attrEnv; 132 133 /** info about the current class being processed */ 134 private KlassInfo kInfo; 135 136 /** translation context of the current lambda expression */ 137 private LambdaTranslationContext lambdaContext; 138 139 /** the variable whose initializer is pending */ 140 private VarSymbol pendingVar; 141 142 /** dump statistics about lambda code generation */ 143 private final boolean dumpLambdaToMethodStats; 144 145 /** force serializable representation, for stress testing **/ 146 private final boolean forceSerializable; 147 148 /** true if line or local variable debug info has been requested */ 149 private final boolean debugLinesOrVars; 150 151 /** dump statistics about lambda method deduplication */ 152 private final boolean verboseDeduplication; 153 154 /** deduplicate lambda implementation methods */ 155 private final boolean deduplicateLambdas; 156 157 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */ 158 public static final int FLAG_SERIALIZABLE = LambdaMetafactory.FLAG_SERIALIZABLE; 159 160 /** Flag for alternate metafactories indicating the lambda object has multiple targets */ 161 public static final int FLAG_MARKERS = LambdaMetafactory.FLAG_MARKERS; 162 163 /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */ 164 public static final int FLAG_BRIDGES = LambdaMetafactory.FLAG_BRIDGES; 165 166 /** Flag for alternate metafactories indicating the lambda object is intended to be quotable */ 167 public static final int FLAG_QUOTABLE = 1 << 3; 168 169 // <editor-fold defaultstate="collapsed" desc="Instantiating"> 170 protected static final Context.Key<LambdaToMethod> unlambdaKey = new Context.Key<>(); 171 172 public static LambdaToMethod instance(Context context) { 173 LambdaToMethod instance = context.get(unlambdaKey); 174 if (instance == null) { 175 instance = new LambdaToMethod(context); 176 } 177 return instance; 178 } 179 private LambdaToMethod(Context context) { 180 context.put(unlambdaKey, this); 181 diags = JCDiagnostic.Factory.instance(context); 182 log = Log.instance(context); 183 lower = Lower.instance(context); 184 names = Names.instance(context); 185 syms = Symtab.instance(context); 186 rs = Resolve.instance(context); 187 operators = Operators.instance(context); 188 make = TreeMaker.instance(context); 189 types = Types.instance(context); 190 transTypes = TransTypes.instance(context); 191 Options options = Options.instance(context); 192 dumpLambdaToMethodStats = options.isSet("debug.dumpLambdaToMethodStats"); 193 attr = Attr.instance(context); 194 forceSerializable = options.isSet("forceSerializable"); 195 boolean lineDebugInfo = 196 options.isUnset(Option.G_CUSTOM) || 197 options.isSet(Option.G_CUSTOM, "lines"); 198 boolean varDebugInfo = 199 options.isUnset(Option.G_CUSTOM) 200 ? options.isSet(Option.G) 201 : options.isSet(Option.G_CUSTOM, "vars"); 202 debugLinesOrVars = lineDebugInfo || varDebugInfo; 203 verboseDeduplication = options.isSet("debug.dumpLambdaToMethodDeduplication"); 204 deduplicateLambdas = options.getBoolean("deduplicateLambdas", true); 205 } 206 // </editor-fold> 207 208 class DedupedLambda { 209 private final MethodSymbol symbol; 210 private final JCTree tree; 211 212 private int hashCode; 213 214 DedupedLambda(MethodSymbol symbol, JCTree tree) { 215 this.symbol = symbol; 216 this.tree = tree; 217 } 218 219 @Override 220 public int hashCode() { 221 int hashCode = this.hashCode; 222 if (hashCode == 0) { 223 this.hashCode = hashCode = TreeHasher.hash(types, tree, symbol.params()); 224 } 225 return hashCode; 226 } 227 228 @Override 229 public boolean equals(Object o) { 230 return (o instanceof DedupedLambda dedupedLambda) 231 && types.isSameType(symbol.asType(), dedupedLambda.symbol.asType()) 232 && new TreeDiffer(types, symbol.params(), dedupedLambda.symbol.params()).scan(tree, dedupedLambda.tree); 233 } 234 } 235 236 private class KlassInfo { 237 238 /** 239 * list of methods to append 240 */ 241 private ListBuffer<JCTree> appendedMethodList = new ListBuffer<>(); 242 243 private final Map<DedupedLambda, DedupedLambda> dedupedLambdas = new HashMap<>(); 244 245 private final Map<Object, DynamicMethodSymbol> dynMethSyms = new HashMap<>(); 246 247 /** 248 * list of deserialization cases 249 */ 250 private final Map<String, ListBuffer<JCStatement>> deserializeCases = new HashMap<>(); 251 252 /** 253 * deserialize method symbol 254 */ 255 private final MethodSymbol deserMethodSym; 256 257 /** 258 * deserialize method parameter symbol 259 */ 260 private final VarSymbol deserParamSym; 261 262 private final JCClassDecl clazz; 263 264 private final Map<String, Integer> syntheticNames = new HashMap<>(); 265 266 private KlassInfo(JCClassDecl clazz) { 267 this.clazz = clazz; 268 MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType, 269 List.nil(), syms.methodClass); 270 deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym); 271 deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), 272 syms.serializedLambdaType, deserMethodSym); 273 } 274 275 private void addMethod(JCTree decl) { 276 appendedMethodList = appendedMethodList.prepend(decl); 277 } 278 279 int syntheticNameIndex(StringBuilder buf, int start) { 280 String temp = buf.toString(); 281 Integer count = syntheticNames.get(temp); 282 if (count == null) { 283 count = start; 284 } 285 syntheticNames.put(temp, count + 1); 286 return count; 287 } 288 } 289 290 // <editor-fold defaultstate="collapsed" desc="visitor methods"> 291 public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { 292 this.make = make; 293 this.attrEnv = env; 294 return translate(cdef); 295 } 296 297 /** 298 * Visit a class. 299 * Maintain the translatedMethodList across nested classes. 300 * Append the translatedMethodList to the class after it is translated. 301 */ 302 @Override 303 public void visitClassDef(JCClassDecl tree) { 304 KlassInfo prevKlassInfo = kInfo; 305 DiagnosticSource prevSource = log.currentSource(); 306 LambdaTranslationContext prevLambdaContext = lambdaContext; 307 VarSymbol prevPendingVar = pendingVar; 308 try { 309 kInfo = new KlassInfo(tree); 310 log.useSource(tree.sym.sourcefile); 311 lambdaContext = null; 312 pendingVar = null; 313 super.visitClassDef(tree); 314 if (prevLambdaContext != null) { 315 tree.sym.owner = prevLambdaContext.translatedSym; 316 } 317 if (!kInfo.deserializeCases.isEmpty()) { 318 int prevPos = make.pos; 319 try { 320 make.at(tree); 321 kInfo.addMethod(makeDeserializeMethod()); 322 } finally { 323 make.at(prevPos); 324 } 325 } 326 //add all translated instance methods here 327 List<JCTree> newMethods = kInfo.appendedMethodList.toList(); 328 tree.defs = tree.defs.appendList(newMethods); 329 for (JCTree lambda : newMethods) { 330 tree.sym.members().enter(((JCMethodDecl)lambda).sym); 331 } 332 result = tree; 333 } finally { 334 kInfo = prevKlassInfo; 335 log.useSource(prevSource.getFile()); 336 lambdaContext = prevLambdaContext; 337 pendingVar = prevPendingVar; 338 } 339 } 340 341 /** 342 * Translate a lambda into a method to be inserted into the class. 343 * Then replace the lambda site with an invokedynamic call of to lambda 344 * meta-factory, which will use the lambda method. 345 */ 346 @Override 347 public void visitLambda(JCLambda tree) { 348 LambdaTranslationContext localContext = new LambdaTranslationContext(tree); 349 MethodSymbol sym = localContext.translatedSym; 350 MethodType lambdaType = (MethodType) sym.type; 351 352 { /* Type annotation management: Based on where the lambda features, type annotations that 353 are interior to it, may at this point be attached to the enclosing method, or the first 354 constructor in the class, or in the enclosing class symbol or in the field whose 355 initializer is the lambda. In any event, gather up the annotations that belong to the 356 lambda and attach it to the implementation method. 357 */ 358 359 Symbol owner = tree.owner; 360 apportionTypeAnnotations(tree, 361 owner::getRawTypeAttributes, 362 owner::setTypeAttributes, 363 sym::setTypeAttributes); 364 365 final long ownerFlags = owner.flags(); 366 if ((ownerFlags & Flags.BLOCK) != 0) { 367 ClassSymbol cs = (ClassSymbol) owner.owner; 368 boolean isStaticInit = (ownerFlags & Flags.STATIC) != 0; 369 apportionTypeAnnotations(tree, 370 isStaticInit ? cs::getClassInitTypeAttributes : cs::getInitTypeAttributes, 371 isStaticInit ? cs::setClassInitTypeAttributes : cs::setInitTypeAttributes, 372 sym::appendUniqueTypeAttributes); 373 } 374 375 if (pendingVar != null && pendingVar.getKind() == ElementKind.FIELD) { 376 apportionTypeAnnotations(tree, 377 pendingVar::getRawTypeAttributes, 378 pendingVar::setTypeAttributes, 379 sym::appendUniqueTypeAttributes); 380 } 381 } 382 383 //create the method declaration hoisting the lambda body 384 JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field), 385 sym.name, 386 make.QualIdent(lambdaType.getReturnType().tsym), 387 List.nil(), 388 localContext.syntheticParams, 389 lambdaType.getThrownTypes() == null ? 390 List.nil() : 391 make.Types(lambdaType.getThrownTypes()), 392 null, 393 null); 394 lambdaDecl.sym = sym; 395 lambdaDecl.type = lambdaType; 396 397 //now that we have generated a method for the lambda expression, 398 //we can translate the lambda into a method reference pointing to the newly 399 //created method. 400 // 401 //Note that we need to adjust the method handle so that it will match the 402 //signature of the SAM descriptor - this means that the method reference 403 //should be added the following synthetic arguments: 404 // 405 // * the "this" argument if it is an instance method 406 // * enclosing locals captured by the lambda expression 407 408 ListBuffer<JCExpression> syntheticInits = new ListBuffer<>(); 409 410 if (!sym.isStatic()) { 411 syntheticInits.append(makeThis( 412 sym.owner.enclClass().asType(), 413 tree.owner.enclClass())); 414 } 415 416 //add captured locals 417 for (Symbol fv : localContext.capturedVars) { 418 JCExpression captured_local = make.Ident(fv).setType(fv.type); 419 syntheticInits.append(captured_local); 420 } 421 422 //then, determine the arguments to the indy call 423 List<JCExpression> indy_args = translate(syntheticInits.toList()); 424 425 LambdaTranslationContext prevLambdaContext = lambdaContext; 426 try { 427 lambdaContext = localContext; 428 //translate lambda body 429 //As the lambda body is translated, all references to lambda locals, 430 //captured variables, enclosing members are adjusted accordingly 431 //to refer to the static method parameters (rather than i.e. accessing 432 //captured members directly). 433 lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl)); 434 } finally { 435 lambdaContext = prevLambdaContext; 436 } 437 438 boolean dedupe = false; 439 if (deduplicateLambdas && !debugLinesOrVars && !isSerializable(tree)) { 440 DedupedLambda dedupedLambda = new DedupedLambda(lambdaDecl.sym, lambdaDecl.body); 441 DedupedLambda existing = kInfo.dedupedLambdas.putIfAbsent(dedupedLambda, dedupedLambda); 442 if (existing != null) { 443 sym = existing.symbol; 444 dedupe = true; 445 if (verboseDeduplication) log.note(tree, Notes.VerboseL2mDeduplicate(sym)); 446 } 447 } 448 if (!dedupe) { 449 //Add the method to the list of methods to be added to this class. 450 kInfo.addMethod(lambdaDecl); 451 } 452 453 //convert to an invokedynamic call 454 result = makeMetafactoryIndyCall(tree, sym.asHandle(), localContext.translatedSym, indy_args); 455 } 456 457 // where 458 // Reassign type annotations from the source that should really belong to the lambda 459 private void apportionTypeAnnotations(JCLambda tree, 460 Supplier<List<Attribute.TypeCompound>> source, 461 Consumer<List<Attribute.TypeCompound>> owner, 462 Consumer<List<Attribute.TypeCompound>> lambda) { 463 464 ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>(); 465 ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>(); 466 467 for (Attribute.TypeCompound tc : source.get()) { 468 if (tc.hasUnknownPosition()) { 469 // Handle container annotations 470 tc.tryFixPosition(); 471 } 472 if (tc.position.onLambda == tree) { 473 lambdaTypeAnnos.append(tc); 474 } else { 475 ownerTypeAnnos.append(tc); 476 } 477 } 478 if (lambdaTypeAnnos.nonEmpty()) { 479 owner.accept(ownerTypeAnnos.toList()); 480 lambda.accept(lambdaTypeAnnos.toList()); 481 } 482 } 483 484 private JCIdent makeThis(Type type, Symbol owner) { 485 VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC, 486 names._this, 487 type, 488 owner); 489 return make.Ident(_this); 490 } 491 492 /** 493 * Translate a method reference into an invokedynamic call to the 494 * meta-factory. 495 */ 496 @Override 497 public void visitReference(JCMemberReference tree) { 498 //first determine the method symbol to be used to generate the sam instance 499 //this is either the method reference symbol, or the bridged reference symbol 500 MethodSymbol refSym = (MethodSymbol)tree.sym; 501 502 //the qualifying expression is treated as a special captured arg 503 JCExpression init = switch (tree.kind) { 504 case IMPLICIT_INNER, /* Inner :: new */ 505 SUPER -> /* super :: instMethod */ 506 makeThis(tree.owner.enclClass().asType(), tree.owner.enclClass()); 507 case BOUND -> /* Expr :: instMethod */ 508 attr.makeNullCheck(transTypes.coerce(attrEnv, tree.getQualifierExpression(), 509 types.erasure(tree.sym.owner.type))); 510 case UNBOUND, /* Type :: instMethod */ 511 STATIC, /* Type :: staticMethod */ 512 TOPLEVEL, /* Top level :: new */ 513 ARRAY_CTOR -> /* ArrayType :: new */ 514 null; 515 }; 516 517 List<JCExpression> indy_args = (init == null) ? 518 List.nil() : translate(List.of(init)); 519 520 //build a sam instance using an indy call to the meta-factory 521 result = makeMetafactoryIndyCall(tree, refSym.asHandle(), refSym, indy_args); 522 } 523 524 /** 525 * Translate identifiers within a lambda to the mapped identifier 526 */ 527 @Override 528 public void visitIdent(JCIdent tree) { 529 if (lambdaContext == null) { 530 super.visitIdent(tree); 531 } else { 532 int prevPos = make.pos; 533 try { 534 make.at(tree); 535 JCTree ltree = lambdaContext.translate(tree); 536 if (ltree != null) { 537 result = ltree; 538 } else { 539 //access to untranslated symbols (i.e. compile-time constants, 540 //members defined inside the lambda body, etc.) ) 541 super.visitIdent(tree); 542 } 543 } finally { 544 make.at(prevPos); 545 } 546 } 547 } 548 549 @Override 550 public void visitVarDef(JCVariableDecl tree) { 551 VarSymbol prevPendingVar = pendingVar; 552 try { 553 pendingVar = tree.sym; 554 if (lambdaContext != null) { 555 tree.sym = lambdaContext.addLocal(tree.sym); 556 tree.init = translate(tree.init); 557 result = tree; 558 } else { 559 super.visitVarDef(tree); 560 } 561 } finally { 562 pendingVar = prevPendingVar; 563 } 564 } 565 566 // </editor-fold> 567 568 // <editor-fold defaultstate="collapsed" desc="Translation helper methods"> 569 570 private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) { 571 return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ? 572 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) : 573 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally); 574 } 575 576 private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) { 577 Type restype = lambdaMethodDecl.type.getReturnType(); 578 boolean isLambda_void = expr.type.hasTag(VOID); 579 boolean isTarget_void = restype.hasTag(VOID); 580 boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); 581 int prevPos = make.pos; 582 try { 583 if (isTarget_void) { 584 //target is void: 585 // BODY; 586 JCStatement stat = make.at(expr).Exec(expr); 587 return make.Block(0, List.of(stat)); 588 } else if (isLambda_void && isTarget_Void) { 589 //void to Void conversion: 590 // BODY; return null; 591 ListBuffer<JCStatement> stats = new ListBuffer<>(); 592 stats.append(make.at(expr).Exec(expr)); 593 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); 594 return make.Block(0, stats.toList()); 595 } else { 596 //non-void to non-void conversion: 597 // return BODY; 598 return make.at(expr).Block(0, List.of(make.Return(expr))); 599 } 600 } finally { 601 make.at(prevPos); 602 } 603 } 604 605 private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) { 606 final Type restype = lambdaMethodDecl.type.getReturnType(); 607 final boolean isTarget_void = restype.hasTag(VOID); 608 boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); 609 610 class LambdaBodyTranslator extends TreeTranslator { 611 612 @Override 613 public void visitClassDef(JCClassDecl tree) { 614 //do NOT recurse on any inner classes 615 result = tree; 616 } 617 618 @Override 619 public void visitLambda(JCLambda tree) { 620 //do NOT recurse on any nested lambdas 621 result = tree; 622 } 623 624 @Override 625 public void visitReturn(JCReturn tree) { 626 boolean isLambda_void = tree.expr == null; 627 if (isTarget_void && !isLambda_void) { 628 //Void to void conversion: 629 // { TYPE $loc = RET-EXPR; return; } 630 VarSymbol loc = new VarSymbol(SYNTHETIC, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym); 631 JCVariableDecl varDef = make.VarDef(loc, tree.expr); 632 result = make.Block(0, List.of(varDef, make.Return(null))); 633 } else { 634 result = tree; 635 } 636 637 } 638 } 639 640 JCBlock trans_block = new LambdaBodyTranslator().translate(block); 641 if (completeNormally && isTarget_Void) { 642 //there's no return statement and the lambda (possibly inferred) 643 //return type is java.lang.Void; emit a synthetic return statement 644 trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); 645 } 646 return trans_block; 647 } 648 649 private JCMethodDecl makeDeserializeMethod() { 650 ListBuffer<JCCase> cases = new ListBuffer<>(); 651 ListBuffer<JCBreak> breaks = new ListBuffer<>(); 652 for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) { 653 JCBreak br = make.Break(null); 654 breaks.add(br); 655 List<JCStatement> stmts = entry.getValue().append(br).toList(); 656 cases.add(make.Case(JCCase.STATEMENT, List.of(make.ConstantCaseLabel(make.Literal(entry.getKey()))), null, stmts, null)); 657 } 658 JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList()); 659 for (JCBreak br : breaks) { 660 br.target = sw; 661 } 662 JCBlock body = make.Block(0L, List.of( 663 sw, 664 make.Throw(makeNewClass( 665 syms.illegalArgumentExceptionType, 666 List.of(make.Literal("Invalid lambda deserialization")))))); 667 JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()), 668 names.deserializeLambda, 669 make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym), 670 List.nil(), 671 List.of(make.VarDef(kInfo.deserParamSym, null)), 672 List.nil(), 673 body, 674 null); 675 deser.sym = kInfo.deserMethodSym; 676 deser.type = kInfo.deserMethodSym.type; 677 //System.err.printf("DESER: '%s'\n", deser); 678 return lower.translateMethod(attrEnv, deser, make); 679 } 680 681 /** Make an attributed class instance creation expression. 682 * @param ctype The class type. 683 * @param args The constructor arguments. 684 * @param cons The constructor symbol 685 */ 686 JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) { 687 JCNewClass tree = make.NewClass(null, 688 null, make.QualIdent(ctype.tsym), args, null); 689 tree.constructor = cons; 690 tree.type = ctype; 691 return tree; 692 } 693 694 /** Make an attributed class instance creation expression. 695 * @param ctype The class type. 696 * @param args The constructor arguments. 697 */ 698 JCNewClass makeNewClass(Type ctype, List<JCExpression> args) { 699 return makeNewClass(ctype, args, 700 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil())); 701 } 702 703 private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym, 704 DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) { 705 String functionalInterfaceClass = classSig(targetType); 706 String functionalInterfaceMethodName = samSym.getSimpleName().toString(); 707 String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type)); 708 Symbol baseMethod = refSym.baseSymbol(); 709 Symbol origMethod = baseMethod.baseSymbol(); 710 if (baseMethod != origMethod && origMethod.owner == syms.objectType.tsym) { 711 //the implementation method is a java.lang.Object method transferred to an 712 //interface that does not declare it. Runtime will refer to this method as to 713 //a java.lang.Object method, so do the same: 714 refSym = ((MethodSymbol) origMethod).asHandle(); 715 } 716 String implClass = classSig(types.erasure(refSym.owner.type)); 717 String implMethodName = refSym.getQualifiedName().toString(); 718 String implMethodSignature = typeSig(types.erasure(refSym.type)); 719 720 JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), 721 make.Literal(refSym.referenceKind())); 722 ListBuffer<JCExpression> serArgs = new ListBuffer<>(); 723 int i = 0; 724 for (Type t : indyType.getParameterTypes()) { 725 List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList(); 726 List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList(); 727 serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg))); 728 ++i; 729 } 730 JCStatement stmt = make.If( 731 deserTest(deserTest(deserTest(deserTest(deserTest( 732 kindTest, 733 "getFunctionalInterfaceClass", functionalInterfaceClass), 734 "getFunctionalInterfaceMethodName", functionalInterfaceMethodName), 735 "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature), 736 "getImplClass", implClass), 737 "getImplMethodSignature", implMethodSignature), 738 make.Return(makeIndyCall( 739 pos, 740 syms.lambdaMetafactory, 741 names.altMetafactory, 742 staticArgs, indyType, serArgs.toList(), samSym.name)), 743 null); 744 ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName); 745 if (stmts == null) { 746 stmts = new ListBuffer<>(); 747 kInfo.deserializeCases.put(implMethodName, stmts); 748 } 749 /* ** 750 System.err.printf("+++++++++++++++++\n"); 751 System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass); 752 System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName); 753 System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature); 754 System.err.printf("*implMethodKind: %d\n", implMethodKind); 755 System.err.printf("*implClass: '%s'\n", implClass); 756 System.err.printf("*implMethodName: '%s'\n", implMethodName); 757 System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature); 758 ****/ 759 stmts.append(stmt); 760 } 761 762 private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) { 763 JCBinary testExpr = make.Binary(Tag.EQ, arg1, arg2); 764 testExpr.operator = operators.resolveBinary(testExpr, Tag.EQ, argType, argType); 765 testExpr.setType(syms.booleanType); 766 return testExpr; 767 } 768 769 private JCExpression deserTest(JCExpression prev, String func, String lit) { 770 MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.nil(), syms.methodClass); 771 Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.nil()); 772 JCMethodInvocation eqtest = make.Apply( 773 List.nil(), 774 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt), 775 List.of(make.Literal(lit))); 776 eqtest.setType(syms.booleanType); 777 JCBinary compound = make.Binary(Tag.AND, prev, eqtest); 778 compound.operator = operators.resolveBinary(compound, Tag.AND, syms.booleanType, syms.booleanType); 779 compound.setType(syms.booleanType); 780 return compound; 781 } 782 783 private JCExpression deserGetter(String func, Type type) { 784 return deserGetter(func, type, List.nil(), List.nil()); 785 } 786 787 private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) { 788 MethodType getmt = new MethodType(argTypes, type, List.nil(), syms.methodClass); 789 Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.nil()); 790 return make.Apply( 791 List.nil(), 792 make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt), 793 args).setType(type); 794 } 795 796 /** 797 * Create new synthetic method with given flags, name, type, owner 798 */ 799 private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) { 800 return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner); 801 } 802 803 private MethodType typeToMethodType(Type mt) { 804 Type type = types.erasure(mt); 805 return new MethodType(type.getParameterTypes(), 806 type.getReturnType(), 807 type.getThrownTypes(), 808 syms.methodClass); 809 } 810 811 /** 812 * Generate an indy method call to the meta factory 813 */ 814 private JCExpression makeMetafactoryIndyCall(JCFunctionalExpression tree, 815 MethodHandleSymbol refSym, MethodSymbol nonDedupedRefSym, 816 List<JCExpression> indy_args) { 817 //determine the static bsm args 818 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym); 819 List<LoadableConstant> staticArgs = List.of( 820 typeToMethodType(samSym.type), 821 refSym.asHandle(), 822 typeToMethodType(tree.getDescriptorType(types))); 823 824 //computed indy arg types 825 ListBuffer<Type> indy_args_types = new ListBuffer<>(); 826 for (JCExpression arg : indy_args) { 827 indy_args_types.append(arg.type); 828 } 829 830 //finally, compute the type of the indy call 831 MethodType indyType = new MethodType(indy_args_types.toList(), 832 tree.type, 833 List.nil(), 834 syms.methodClass); 835 836 List<Symbol> bridges = bridges(tree); 837 boolean isSerializable = isSerializable(tree); 838 boolean isQuotable = isQuotable(tree); 839 boolean needsAltMetafactory = tree.target.isIntersection() || 840 isSerializable || isQuotable || bridges.length() > 1; 841 842 dumpStats(tree, needsAltMetafactory, nonDedupedRefSym); 843 844 Name metafactoryName = needsAltMetafactory ? 845 names.altMetafactory : names.metafactory; 846 847 if (needsAltMetafactory) { 848 ListBuffer<Type> markers = new ListBuffer<>(); 849 List<Type> targets = tree.target.isIntersection() ? 850 types.directSupertypes(tree.target) : 851 List.nil(); 852 for (Type t : targets) { 853 t = types.erasure(t); 854 if (t.tsym != syms.serializableType.tsym && 855 !types.isQuotable(t) && 856 t.tsym != tree.type.tsym && 857 t.tsym != syms.objectType.tsym) { 858 markers.append(t); 859 } 860 } 861 int flags = isSerializable ? FLAG_SERIALIZABLE : 0; 862 flags |= isQuotable ? FLAG_QUOTABLE : 0; 863 boolean hasMarkers = markers.nonEmpty(); 864 boolean hasBridges = bridges.nonEmpty(); 865 if (hasMarkers) { 866 flags |= FLAG_MARKERS; 867 } 868 if (hasBridges) { 869 flags |= FLAG_BRIDGES; 870 } 871 staticArgs = staticArgs.append(LoadableConstant.Int(flags)); 872 if (hasMarkers) { 873 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length())); 874 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList())); 875 } 876 if (hasBridges) { 877 staticArgs = staticArgs.append(LoadableConstant.Int(bridges.length() - 1)); 878 for (Symbol s : bridges) { 879 Type s_erasure = s.erasure(types); 880 if (!types.isSameType(s_erasure, samSym.erasure(types))) { 881 staticArgs = staticArgs.append(((MethodType)s.erasure(types))); 882 } 883 } 884 } 885 if (isQuotable) { 886 MethodSymbol opMethodSym = tree.codeModel; 887 staticArgs = staticArgs.append(opMethodSym.asHandle()); 888 } 889 if (isSerializable) { 890 int prevPos = make.pos; 891 try { 892 make.at(kInfo.clazz); 893 addDeserializationCase(refSym, tree.type, samSym, 894 tree, staticArgs, indyType); 895 } finally { 896 make.at(prevPos); 897 } 898 } 899 } 900 901 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name); 902 } 903 904 /** 905 * Generate an indy method call with given name, type and static bootstrap 906 * arguments types 907 */ 908 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, 909 List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs, 910 Name methName) { 911 int prevPos = make.pos; 912 try { 913 make.at(pos); 914 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType, 915 syms.stringType, 916 syms.methodTypeType).appendList(staticArgs.map(types::constantType)); 917 918 MethodSymbol bsm = rs.resolveInternalMethod(pos, attrEnv, site, 919 bsmName, bsm_staticArgs, List.nil()); 920 921 DynamicMethodSymbol dynSym = 922 new DynamicMethodSymbol(methName, 923 syms.noSymbol, 924 bsm.asHandle(), 925 indyType, 926 staticArgs.toArray(new LoadableConstant[staticArgs.length()])); 927 JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName); 928 DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent( 929 dynSym.poolKey(types), dynSym); 930 qualifier.sym = existing != null ? existing : dynSym; 931 qualifier.type = indyType.getReturnType(); 932 933 JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs); 934 proxyCall.type = indyType.getReturnType(); 935 return proxyCall; 936 } finally { 937 make.at(prevPos); 938 } 939 } 940 941 List<Symbol> bridges(JCFunctionalExpression tree) { 942 ClassSymbol csym = 943 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE); 944 return types.functionalInterfaceBridges(csym); 945 } 946 947 /** does this functional expression require serialization support? */ 948 boolean isSerializable(JCFunctionalExpression tree) { 949 if (forceSerializable) { 950 return true; 951 } 952 return types.asSuper(tree.target, syms.serializableType.tsym) != null; 953 } 954 955 boolean isQuotable(JCFunctionalExpression tree) { 956 return tree.codeModel != null; 957 } 958 959 void dumpStats(JCFunctionalExpression tree, boolean needsAltMetafactory, Symbol sym) { 960 if (dumpLambdaToMethodStats) { 961 if (tree instanceof JCLambda lambda) { 962 log.note(tree, diags.noteKey(lambda.wasMethodReference ? "mref.stat.1" : "lambda.stat", 963 needsAltMetafactory, sym)); 964 } else if (tree instanceof JCMemberReference) { 965 log.note(tree, Notes.MrefStat(needsAltMetafactory, null)); 966 } 967 } 968 } 969 970 /** 971 * This class retains all the useful information about a lambda expression, 972 * and acts as a translation map that is used by the main translation routines 973 * in order to adjust references to captured locals/members, etc. 974 */ 975 class LambdaTranslationContext { 976 977 /** the underlying (untranslated) tree */ 978 final JCFunctionalExpression tree; 979 980 /** a translation map from source symbols to translated symbols */ 981 final Map<VarSymbol, VarSymbol> lambdaProxies = new HashMap<>(); 982 983 /** the list of symbols captured by this lambda expression */ 984 final List<VarSymbol> capturedVars; 985 986 /** the synthetic symbol for the method hoisting the translated lambda */ 987 final MethodSymbol translatedSym; 988 989 /** the list of parameter declarations of the translated lambda method */ 990 final List<JCVariableDecl> syntheticParams; 991 992 LambdaTranslationContext(JCLambda tree) { 993 this.tree = tree; 994 // This symbol will be filled-in in complete 995 Symbol owner = tree.owner; 996 if (owner.kind == MTH) { 997 final MethodSymbol originalOwner = (MethodSymbol)owner.clone(owner.owner); 998 this.translatedSym = new MethodSymbol(0, null, null, owner.enclClass()) { 999 @Override 1000 public MethodSymbol originalEnclosingMethod() { 1001 return originalOwner; 1002 } 1003 }; 1004 } else { 1005 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass()); 1006 } 1007 ListBuffer<JCVariableDecl> params = new ListBuffer<>(); 1008 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>(); 1009 LambdaCaptureScanner captureScanner = new LambdaCaptureScanner(tree); 1010 capturedVars = captureScanner.analyzeCaptures(); 1011 for (VarSymbol captured : capturedVars) { 1012 VarSymbol trans = addSymbol(captured, LambdaSymbolKind.CAPTURED_VAR); 1013 params.append(make.VarDef(trans, null)); 1014 parameterSymbols.add(trans); 1015 } 1016 for (JCVariableDecl param : tree.params) { 1017 VarSymbol trans = addSymbol(param.sym, LambdaSymbolKind.PARAM); 1018 params.append(make.VarDef(trans, null)); 1019 parameterSymbols.add(trans); 1020 } 1021 syntheticParams = params.toList(); 1022 completeLambdaMethodSymbol(owner, captureScanner.capturesThis); 1023 translatedSym.params = parameterSymbols.toList(); 1024 } 1025 1026 void completeLambdaMethodSymbol(Symbol owner, boolean thisReferenced) { 1027 boolean inInterface = owner.enclClass().isInterface(); 1028 1029 // Compute and set the lambda name 1030 Name name = isSerializable(tree) 1031 ? serializedLambdaName(owner) 1032 : lambdaName(owner); 1033 1034 //prepend synthetic args to translated lambda method signature 1035 Type type = types.createMethodTypeWithParameters( 1036 generatedLambdaSig(), 1037 TreeInfo.types(syntheticParams)); 1038 1039 // If instance access isn't needed, make it static. 1040 // Interface instance methods must be default methods. 1041 // Lambda methods are private synthetic. 1042 // Inherit ACC_STRICT from the enclosing method, or, for clinit, 1043 // from the class. 1044 long flags = SYNTHETIC | LAMBDA_METHOD | 1045 owner.flags_field & STRICTFP | 1046 owner.owner.flags_field & STRICTFP | 1047 PRIVATE | 1048 (thisReferenced? (inInterface? DEFAULT : 0) : STATIC); 1049 1050 translatedSym.type = type; 1051 translatedSym.name = name; 1052 translatedSym.flags_field = flags; 1053 } 1054 1055 /** 1056 * For a serializable lambda, generate a disambiguating string 1057 * which maximizes stability across deserialization. 1058 * 1059 * @return String to differentiate synthetic lambda method names 1060 */ 1061 private String serializedLambdaDisambiguation(Symbol owner) { 1062 StringBuilder buf = new StringBuilder(); 1063 // Append the enclosing method signature to differentiate 1064 // overloaded enclosing methods. For lambdas enclosed in 1065 // lambdas, the generated lambda method will not have type yet, 1066 // but the enclosing method's name will have been generated 1067 // with this same method, so it will be unique and never be 1068 // overloaded. 1069 Assert.check( 1070 owner.type != null || 1071 lambdaContext != null); 1072 if (owner.type != null) { 1073 buf.append(typeSig(owner.type, true)); 1074 buf.append(":"); 1075 } 1076 1077 // Add target type info 1078 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName()); 1079 buf.append(" "); 1080 1081 // Add variable assigned to 1082 if (pendingVar != null) { 1083 buf.append(pendingVar.flatName()); 1084 buf.append("="); 1085 } 1086 //add captured locals info: type, name, order 1087 for (Symbol fv : capturedVars) { 1088 if (fv != owner) { 1089 buf.append(typeSig(fv.type, true)); 1090 buf.append(" "); 1091 buf.append(fv.flatName()); 1092 buf.append(","); 1093 } 1094 } 1095 1096 return buf.toString(); 1097 } 1098 1099 /** 1100 * For a non-serializable lambda, generate a simple method. 1101 * 1102 * @return Name to use for the synthetic lambda method name 1103 */ 1104 private Name lambdaName(Symbol owner) { 1105 StringBuilder buf = new StringBuilder(); 1106 buf.append(names.lambda); 1107 buf.append(syntheticMethodNameComponent(owner)); 1108 buf.append("$"); 1109 buf.append(kInfo.syntheticNameIndex(buf, 0)); 1110 return names.fromString(buf.toString()); 1111 } 1112 1113 /** 1114 * @return Method name in a form that can be folded into a 1115 * component of a synthetic method name 1116 */ 1117 String syntheticMethodNameComponent(Symbol owner) { 1118 long ownerFlags = owner.flags(); 1119 if ((ownerFlags & BLOCK) != 0) { 1120 return (ownerFlags & STATIC) != 0 ? 1121 "static" : "new"; 1122 } else if (owner.isConstructor()) { 1123 return "new"; 1124 } else { 1125 return owner.name.toString(); 1126 } 1127 } 1128 1129 /** 1130 * For a serializable lambda, generate a method name which maximizes 1131 * name stability across deserialization. 1132 * 1133 * @return Name to use for the synthetic lambda method name 1134 */ 1135 private Name serializedLambdaName(Symbol owner) { 1136 StringBuilder buf = new StringBuilder(); 1137 buf.append(names.lambda); 1138 // Append the name of the method enclosing the lambda. 1139 buf.append(syntheticMethodNameComponent(owner)); 1140 buf.append('$'); 1141 // Append a hash of the disambiguating string : enclosing method 1142 // signature, etc. 1143 String disam = serializedLambdaDisambiguation(owner); 1144 buf.append(Integer.toHexString(disam.hashCode())); 1145 buf.append('$'); 1146 // The above appended name components may not be unique, append 1147 // a count based on the above name components. 1148 buf.append(kInfo.syntheticNameIndex(buf, 1)); 1149 String result = buf.toString(); 1150 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam); 1151 return names.fromString(result); 1152 } 1153 1154 /** 1155 * Translate a symbol of a given kind into something suitable for the 1156 * synthetic lambda body 1157 */ 1158 VarSymbol translate(final VarSymbol sym, LambdaSymbolKind skind) { 1159 VarSymbol ret; 1160 boolean propagateAnnos = true; 1161 switch (skind) { 1162 case CAPTURED_VAR: 1163 Name name = (sym.flags() & LOCAL_CAPTURE_FIELD) != 0 ? 1164 sym.baseSymbol().name : sym.name; 1165 ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym); 1166 propagateAnnos = false; 1167 break; 1168 case LOCAL_VAR: 1169 ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym); 1170 ret.pos = sym.pos; 1171 // If sym.data == ElementKind.EXCEPTION_PARAMETER, 1172 // set ret.data = ElementKind.EXCEPTION_PARAMETER too. 1173 // Because method com.sun.tools.javac.jvm.Code.fillExceptionParameterPositions and 1174 // com.sun.tools.javac.jvm.Code.fillLocalVarPosition would use it. 1175 // See JDK-8257740 for more information. 1176 if (sym.isExceptionParameter()) { 1177 ret.setData(ElementKind.EXCEPTION_PARAMETER); 1178 } 1179 break; 1180 case PARAM: 1181 ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym); 1182 ret.pos = sym.pos; 1183 break; 1184 default: 1185 Assert.error(skind.name()); 1186 throw new AssertionError(); 1187 } 1188 if (ret != sym && propagateAnnos) { 1189 ret.setDeclarationAttributes(sym.getRawAttributes()); 1190 ret.setTypeAttributes(sym.getRawTypeAttributes()); 1191 } 1192 return ret; 1193 } 1194 1195 VarSymbol addLocal(VarSymbol sym) { 1196 return addSymbol(sym, LambdaSymbolKind.LOCAL_VAR); 1197 } 1198 1199 private VarSymbol addSymbol(VarSymbol sym, LambdaSymbolKind skind) { 1200 return lambdaProxies.computeIfAbsent(sym, s -> translate(s, skind)); 1201 } 1202 1203 JCTree translate(JCIdent lambdaIdent) { 1204 Symbol tSym = lambdaProxies.get(lambdaIdent.sym); 1205 return tSym != null ? 1206 make.Ident(tSym).setType(lambdaIdent.type) : 1207 null; 1208 } 1209 1210 Type generatedLambdaSig() { 1211 return types.erasure(tree.getDescriptorType(types)); 1212 } 1213 1214 /** 1215 * Compute the set of local variables captured by this lambda expression. 1216 * Also determines whether this lambda expression captures the enclosing 'this'. 1217 */ 1218 class LambdaCaptureScanner extends CaptureScanner { 1219 boolean capturesThis; 1220 Set<ClassSymbol> seenClasses = new HashSet<>(); 1221 1222 LambdaCaptureScanner(JCLambda ownerTree) { 1223 super(ownerTree); 1224 } 1225 1226 @Override 1227 public void visitClassDef(JCClassDecl tree) { 1228 seenClasses.add(tree.sym); 1229 super.visitClassDef(tree); 1230 } 1231 1232 @Override 1233 public void visitIdent(JCIdent tree) { 1234 if (!tree.sym.isStatic() && 1235 tree.sym.owner.kind == TYP && 1236 (tree.sym.kind == VAR || tree.sym.kind == MTH) && 1237 !seenClasses.contains(tree.sym.owner)) { 1238 if ((tree.sym.flags() & LOCAL_CAPTURE_FIELD) != 0) { 1239 // a local, captured by Lower - re-capture! 1240 addFreeVar((VarSymbol) tree.sym); 1241 } else { 1242 // a reference to an enclosing field or method, we need to capture 'this' 1243 capturesThis = true; 1244 } 1245 } else { 1246 // might be a local capture 1247 super.visitIdent(tree); 1248 } 1249 } 1250 1251 @Override 1252 public void visitSelect(JCFieldAccess tree) { 1253 if (tree.sym.kind == VAR && 1254 (tree.sym.name == names._this || 1255 tree.sym.name == names._super) && 1256 !seenClasses.contains(tree.sym.type.tsym)) { 1257 capturesThis = true; 1258 } 1259 super.visitSelect(tree); 1260 } 1261 1262 @Override 1263 public void visitAnnotation(JCAnnotation tree) { 1264 // do nothing (annotation values look like captured instance fields) 1265 } 1266 } 1267 1268 /* 1269 * These keys provide mappings for various translated lambda symbols 1270 * and the prevailing order must be maintained. 1271 */ 1272 enum LambdaSymbolKind { 1273 PARAM, // original to translated lambda parameters 1274 LOCAL_VAR, // original to translated lambda locals 1275 CAPTURED_VAR; // variables in enclosing scope to translated synthetic parameters 1276 } 1277 } 1278 1279 /** 1280 * **************************************************************** 1281 * Signature Generation 1282 * **************************************************************** 1283 */ 1284 1285 private String typeSig(Type type) { 1286 return typeSig(type, false); 1287 } 1288 1289 private String typeSig(Type type, boolean allowIllegalSignature) { 1290 try { 1291 L2MSignatureGenerator sg = new L2MSignatureGenerator(allowIllegalSignature); 1292 sg.assembleSig(type); 1293 return sg.toString(); 1294 } catch (InvalidSignatureException ex) { 1295 Symbol c = attrEnv.enclClass.sym; 1296 log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type()))); 1297 return "<ERRONEOUS>"; 1298 } 1299 } 1300 1301 private String classSig(Type type) { 1302 try { 1303 L2MSignatureGenerator sg = new L2MSignatureGenerator(false); 1304 sg.assembleClassSig(type); 1305 return sg.toString(); 1306 } catch (InvalidSignatureException ex) { 1307 Symbol c = attrEnv.enclClass.sym; 1308 log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type()))); 1309 return "<ERRONEOUS>"; 1310 } 1311 } 1312 1313 /** 1314 * Signature Generation 1315 */ 1316 private class L2MSignatureGenerator extends Types.SignatureGenerator { 1317 1318 /** 1319 * An output buffer for type signatures. 1320 */ 1321 StringBuilder sb = new StringBuilder(); 1322 1323 /** 1324 * Are signatures incompatible with JVM spec allowed? 1325 * Used by {@link LambdaTranslationContext#serializedLambdaDisambiguation(Symbol)}}. 1326 */ 1327 boolean allowIllegalSignatures; 1328 1329 L2MSignatureGenerator(boolean allowIllegalSignatures) { 1330 types.super(); 1331 this.allowIllegalSignatures = allowIllegalSignatures; 1332 } 1333 1334 @Override 1335 protected void reportIllegalSignature(Type t) { 1336 if (!allowIllegalSignatures) { 1337 super.reportIllegalSignature(t); 1338 } 1339 } 1340 1341 @Override 1342 protected void append(char ch) { 1343 sb.append(ch); 1344 } 1345 1346 @Override 1347 protected void append(byte[] ba) { 1348 Name name; 1349 try { 1350 name = names.fromUtf(ba); 1351 } catch (InvalidUtfException e) { 1352 throw new AssertionError(e); 1353 } 1354 sb.append(name.toString()); 1355 } 1356 1357 @Override 1358 protected void append(Name name) { 1359 sb.append(name.toString()); 1360 } 1361 1362 @Override 1363 public String toString() { 1364 return sb.toString(); 1365 } 1366 } 1367 }