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