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