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