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 }