1 /*
   2  * Copyright (c) 2010, 2024, 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(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(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.position.onLambda == tree) {
 469                 lambdaTypeAnnos.append(tc);
 470             } else {
 471                 ownerTypeAnnos.append(tc);
 472             }
 473         }
 474         if (lambdaTypeAnnos.nonEmpty()) {
 475             owner.accept(ownerTypeAnnos.toList());
 476             lambda.accept(lambdaTypeAnnos.toList());
 477         }
 478     }
 479 
 480     private JCIdent makeThis(Type type, Symbol owner) {
 481         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
 482                 names._this,
 483                 type,
 484                 owner);
 485         return make.Ident(_this);
 486     }
 487 
 488     /**
 489      * Translate a method reference into an invokedynamic call to the
 490      * meta-factory.
 491      */
 492     @Override
 493     public void visitReference(JCMemberReference tree) {
 494         //first determine the method symbol to be used to generate the sam instance
 495         //this is either the method reference symbol, or the bridged reference symbol
 496         MethodSymbol refSym = (MethodSymbol)tree.sym;
 497 
 498         //the qualifying expression is treated as a special captured arg
 499         JCExpression init = switch (tree.kind) {
 500             case IMPLICIT_INNER,    /* Inner :: new */
 501                  SUPER ->           /* super :: instMethod */
 502                     makeThis(tree.owner.enclClass().asType(), tree.owner.enclClass());
 503             case BOUND ->           /* Expr :: instMethod */
 504                     attr.makeNullCheck(transTypes.coerce(attrEnv, tree.getQualifierExpression(),
 505                             types.erasure(tree.sym.owner.type)));
 506             case UNBOUND,           /* Type :: instMethod */
 507                  STATIC,            /* Type :: staticMethod */
 508                  TOPLEVEL,          /* Top level :: new */
 509                  ARRAY_CTOR ->      /* ArrayType :: new */
 510                     null;
 511         };
 512 
 513         List<JCExpression> indy_args = (init == null) ?
 514                 List.nil() : translate(List.of(init));
 515 
 516         //build a sam instance using an indy call to the meta-factory
 517         result = makeMetafactoryIndyCall(tree, refSym.asHandle(), refSym, indy_args);
 518     }
 519 
 520     /**
 521      * Translate identifiers within a lambda to the mapped identifier
 522      */
 523     @Override
 524     public void visitIdent(JCIdent tree) {
 525         if (lambdaContext == null) {
 526             super.visitIdent(tree);
 527         } else {
 528             int prevPos = make.pos;
 529             try {
 530                 make.at(tree);
 531                 JCTree ltree = lambdaContext.translate(tree);
 532                 if (ltree != null) {
 533                     result = ltree;
 534                 } else {
 535                     //access to untranslated symbols (i.e. compile-time constants,
 536                     //members defined inside the lambda body, etc.) )
 537                     super.visitIdent(tree);
 538                 }
 539             } finally {
 540                 make.at(prevPos);
 541             }
 542         }
 543     }
 544 
 545     @Override
 546     public void visitVarDef(JCVariableDecl tree) {
 547         VarSymbol prevPendingVar = pendingVar;
 548         try {
 549             pendingVar = tree.sym;
 550             if (lambdaContext != null) {
 551                 tree.sym = lambdaContext.addLocal(tree.sym);
 552                 tree.init = translate(tree.init);
 553                 result = tree;
 554             } else {
 555                 super.visitVarDef(tree);
 556             }
 557         } finally {
 558             pendingVar = prevPendingVar;
 559         }
 560     }
 561 
 562     // </editor-fold>
 563 
 564     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
 565 
 566     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
 567         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
 568                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
 569                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
 570     }
 571 
 572     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
 573         Type restype = lambdaMethodDecl.type.getReturnType();
 574         boolean isLambda_void = expr.type.hasTag(VOID);
 575         boolean isTarget_void = restype.hasTag(VOID);
 576         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
 577         int prevPos = make.pos;
 578         try {
 579             if (isTarget_void) {
 580                 //target is void:
 581                 // BODY;
 582                 JCStatement stat = make.at(expr).Exec(expr);
 583                 return make.Block(0, List.of(stat));
 584             } else if (isLambda_void && isTarget_Void) {
 585                 //void to Void conversion:
 586                 // BODY; return null;
 587                 ListBuffer<JCStatement> stats = new ListBuffer<>();
 588                 stats.append(make.at(expr).Exec(expr));
 589                 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
 590                 return make.Block(0, stats.toList());
 591             } else {
 592                 //non-void to non-void conversion:
 593                 // return BODY;
 594                 return make.at(expr).Block(0, List.of(make.Return(expr)));
 595             }
 596         } finally {
 597             make.at(prevPos);
 598         }
 599     }
 600 
 601     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
 602         final Type restype = lambdaMethodDecl.type.getReturnType();
 603         final boolean isTarget_void = restype.hasTag(VOID);
 604         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
 605 
 606         class LambdaBodyTranslator extends TreeTranslator {
 607 
 608             @Override
 609             public void visitClassDef(JCClassDecl tree) {
 610                 //do NOT recurse on any inner classes
 611                 result = tree;
 612             }
 613 
 614             @Override
 615             public void visitLambda(JCLambda tree) {
 616                 //do NOT recurse on any nested lambdas
 617                 result = tree;
 618             }
 619 
 620             @Override
 621             public void visitReturn(JCReturn tree) {
 622                 boolean isLambda_void = tree.expr == null;
 623                 if (isTarget_void && !isLambda_void) {
 624                     //Void to void conversion:
 625                     // { TYPE $loc = RET-EXPR; return; }
 626                     VarSymbol loc = new VarSymbol(SYNTHETIC, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
 627                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
 628                     result = make.Block(0, List.of(varDef, make.Return(null)));
 629                 } else {
 630                     result = tree;
 631                 }
 632 
 633             }
 634         }
 635 
 636         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
 637         if (completeNormally && isTarget_Void) {
 638             //there's no return statement and the lambda (possibly inferred)
 639             //return type is java.lang.Void; emit a synthetic return statement
 640             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
 641         }
 642         return trans_block;
 643     }
 644 
 645     private JCMethodDecl makeDeserializeMethod() {
 646         ListBuffer<JCCase> cases = new ListBuffer<>();
 647         ListBuffer<JCBreak> breaks = new ListBuffer<>();
 648         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
 649             JCBreak br = make.Break(null);
 650             breaks.add(br);
 651             List<JCStatement> stmts = entry.getValue().append(br).toList();
 652             cases.add(make.Case(JCCase.STATEMENT, List.of(make.ConstantCaseLabel(make.Literal(entry.getKey()))), null, stmts, null));
 653         }
 654         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
 655         for (JCBreak br : breaks) {
 656             br.target = sw;
 657         }
 658         JCBlock body = make.Block(0L, List.of(
 659                 sw,
 660                 make.Throw(makeNewClass(
 661                         syms.illegalArgumentExceptionType,
 662                         List.of(make.Literal("Invalid lambda deserialization"))))));
 663         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
 664                 names.deserializeLambda,
 665                 make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
 666                 List.nil(),
 667                 List.of(make.VarDef(kInfo.deserParamSym, null)),
 668                 List.nil(),
 669                 body,
 670                 null);
 671         deser.sym = kInfo.deserMethodSym;
 672         deser.type = kInfo.deserMethodSym.type;
 673         //System.err.printf("DESER: '%s'\n", deser);
 674         return lower.translateMethod(attrEnv, deser, make);
 675     }
 676 
 677     /** Make an attributed class instance creation expression.
 678      *  @param ctype    The class type.
 679      *  @param args     The constructor arguments.
 680      *  @param cons     The constructor symbol
 681      */
 682     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
 683         JCNewClass tree = make.NewClass(null,
 684                 null, make.QualIdent(ctype.tsym), args, null);
 685         tree.constructor = cons;
 686         tree.type = ctype;
 687         return tree;
 688     }
 689 
 690     /** Make an attributed class instance creation expression.
 691      *  @param ctype    The class type.
 692      *  @param args     The constructor arguments.
 693      */
 694     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
 695         return makeNewClass(ctype, args,
 696                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
 697     }
 698 
 699     private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym,
 700                                         DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) {
 701         String functionalInterfaceClass = classSig(targetType);
 702         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
 703         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
 704         Symbol baseMethod = refSym.baseSymbol();
 705         Symbol origMethod = baseMethod.baseSymbol();
 706         if (baseMethod != origMethod && origMethod.owner == syms.objectType.tsym) {
 707             //the implementation method is a java.lang.Object method transferred to an
 708             //interface that does not declare it. Runtime will refer to this method as to
 709             //a java.lang.Object method, so do the same:
 710             refSym = ((MethodSymbol) origMethod).asHandle();
 711         }
 712         String implClass = classSig(types.erasure(refSym.owner.type));
 713         String implMethodName = refSym.getQualifiedName().toString();
 714         String implMethodSignature = typeSig(types.erasure(refSym.type));
 715 
 716         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
 717                 make.Literal(refSym.referenceKind()));
 718         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
 719         int i = 0;
 720         for (Type t : indyType.getParameterTypes()) {
 721             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
 722             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
 723             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
 724             ++i;
 725         }
 726         JCStatement stmt = make.If(
 727                 deserTest(deserTest(deserTest(deserTest(deserTest(
 728                                                         kindTest,
 729                                                         "getFunctionalInterfaceClass", functionalInterfaceClass),
 730                                                 "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
 731                                         "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
 732                                 "getImplClass", implClass),
 733                         "getImplMethodSignature", implMethodSignature),
 734                 make.Return(makeIndyCall(
 735                         pos,
 736                         syms.lambdaMetafactory,
 737                         names.altMetafactory,
 738                         staticArgs, indyType, serArgs.toList(), samSym.name)),
 739                 null);
 740         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
 741         if (stmts == null) {
 742             stmts = new ListBuffer<>();
 743             kInfo.deserializeCases.put(implMethodName, stmts);
 744         }
 745         /* **
 746         System.err.printf("+++++++++++++++++\n");
 747         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
 748         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
 749         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
 750         System.err.printf("*implMethodKind: %d\n", implMethodKind);
 751         System.err.printf("*implClass: '%s'\n", implClass);
 752         System.err.printf("*implMethodName: '%s'\n", implMethodName);
 753         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
 754         ****/
 755         stmts.append(stmt);
 756     }
 757 
 758     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
 759         JCBinary testExpr = make.Binary(Tag.EQ, arg1, arg2);
 760         testExpr.operator = operators.resolveBinary(testExpr, Tag.EQ, argType, argType);
 761         testExpr.setType(syms.booleanType);
 762         return testExpr;
 763     }
 764 
 765     private JCExpression deserTest(JCExpression prev, String func, String lit) {
 766         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.nil(), syms.methodClass);
 767         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.nil());
 768         JCMethodInvocation eqtest = make.Apply(
 769                 List.nil(),
 770                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
 771                 List.of(make.Literal(lit)));
 772         eqtest.setType(syms.booleanType);
 773         JCBinary compound = make.Binary(Tag.AND, prev, eqtest);
 774         compound.operator = operators.resolveBinary(compound, Tag.AND, syms.booleanType, syms.booleanType);
 775         compound.setType(syms.booleanType);
 776         return compound;
 777     }
 778 
 779     private JCExpression deserGetter(String func, Type type) {
 780         return deserGetter(func, type, List.nil(), List.nil());
 781     }
 782 
 783     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
 784         MethodType getmt = new MethodType(argTypes, type, List.nil(), syms.methodClass);
 785         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.nil());
 786         return make.Apply(
 787                 List.nil(),
 788                 make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
 789                 args).setType(type);
 790     }
 791 
 792     /**
 793      * Create new synthetic method with given flags, name, type, owner
 794      */
 795     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
 796         return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
 797     }
 798 
 799     private MethodType typeToMethodType(Type mt) {
 800         Type type = types.erasure(mt);
 801         return new MethodType(type.getParameterTypes(),
 802                 type.getReturnType(),
 803                 type.getThrownTypes(),
 804                 syms.methodClass);
 805     }
 806 
 807     /**
 808      * Generate an indy method call to the meta factory
 809      */
 810     private JCExpression makeMetafactoryIndyCall(JCFunctionalExpression tree,
 811                                                  MethodHandleSymbol refSym, MethodSymbol nonDedupedRefSym,
 812                                                  List<JCExpression> indy_args) {
 813         //determine the static bsm args
 814         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
 815         List<LoadableConstant> staticArgs = List.of(
 816                 typeToMethodType(samSym.type),
 817                 refSym.asHandle(),
 818                 typeToMethodType(tree.getDescriptorType(types)));
 819 
 820         //computed indy arg types
 821         ListBuffer<Type> indy_args_types = new ListBuffer<>();
 822         for (JCExpression arg : indy_args) {
 823             indy_args_types.append(arg.type);
 824         }
 825 
 826         //finally, compute the type of the indy call
 827         MethodType indyType = new MethodType(indy_args_types.toList(),
 828                 tree.type,
 829                 List.nil(),
 830                 syms.methodClass);
 831 
 832         List<Symbol> bridges = bridges(tree);
 833         boolean isSerializable = isSerializable(tree);
 834         boolean isQuotable = isQuotable(tree);
 835         boolean needsAltMetafactory = tree.target.isIntersection() ||
 836                 isSerializable || isQuotable || bridges.length() > 1;
 837 
 838         dumpStats(tree, needsAltMetafactory, nonDedupedRefSym);
 839 
 840         Name metafactoryName = needsAltMetafactory ?
 841                 names.altMetafactory : names.metafactory;
 842 
 843         if (needsAltMetafactory) {
 844             ListBuffer<Type> markers = new ListBuffer<>();
 845             List<Type> targets = tree.target.isIntersection() ?
 846                     types.directSupertypes(tree.target) :
 847                     List.nil();
 848             for (Type t : targets) {
 849                 t = types.erasure(t);
 850                 if (t.tsym != syms.serializableType.tsym &&
 851                         !types.isQuotable(t) &&
 852                         t.tsym != tree.type.tsym &&
 853                         t.tsym != syms.objectType.tsym) {
 854                     markers.append(t);
 855                 }
 856             }
 857             int flags = isSerializable ? FLAG_SERIALIZABLE : 0;
 858             flags |= isQuotable ? FLAG_QUOTABLE : 0;
 859             boolean hasMarkers = markers.nonEmpty();
 860             boolean hasBridges = bridges.nonEmpty();
 861             if (hasMarkers) {
 862                 flags |= FLAG_MARKERS;
 863             }
 864             if (hasBridges) {
 865                 flags |= FLAG_BRIDGES;
 866             }
 867             staticArgs = staticArgs.append(LoadableConstant.Int(flags));
 868             if (hasMarkers) {
 869                 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
 870                 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
 871             }
 872             if (hasBridges) {
 873                 staticArgs = staticArgs.append(LoadableConstant.Int(bridges.length() - 1));
 874                 for (Symbol s : bridges) {
 875                     Type s_erasure = s.erasure(types);
 876                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
 877                         staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
 878                     }
 879                 }
 880             }
 881             if (isQuotable) {
 882                 VarSymbol reflectField = (VarSymbol)tree.codeModel;
 883                 staticArgs = staticArgs.append(reflectField.asMethodHandle(true));
 884             }
 885             if (isSerializable) {
 886                 int prevPos = make.pos;
 887                 try {
 888                     make.at(kInfo.clazz);
 889                     addDeserializationCase(refSym, tree.type, samSym,
 890                             tree, staticArgs, indyType);
 891                 } finally {
 892                     make.at(prevPos);
 893                 }
 894             }
 895         }
 896 
 897         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
 898     }
 899 
 900     /**
 901      * Generate an indy method call with given name, type and static bootstrap
 902      * arguments types
 903      */
 904     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
 905                                       List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
 906                                       Name methName) {
 907         int prevPos = make.pos;
 908         try {
 909             make.at(pos);
 910             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
 911                     syms.stringType,
 912                     syms.methodTypeType).appendList(staticArgs.map(types::constantType));
 913 
 914             MethodSymbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
 915                     bsmName, bsm_staticArgs, List.nil());
 916 
 917             DynamicMethodSymbol dynSym =
 918                     new DynamicMethodSymbol(methName,
 919                             syms.noSymbol,
 920                             bsm.asHandle(),
 921                             indyType,
 922                             staticArgs.toArray(new LoadableConstant[staticArgs.length()]));
 923             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
 924             DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
 925                     dynSym.poolKey(types), dynSym);
 926             qualifier.sym = existing != null ? existing : dynSym;
 927             qualifier.type = indyType.getReturnType();
 928 
 929             JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs);
 930             proxyCall.type = indyType.getReturnType();
 931             return proxyCall;
 932         } finally {
 933             make.at(prevPos);
 934         }
 935     }
 936 
 937     List<Symbol> bridges(JCFunctionalExpression tree) {
 938         ClassSymbol csym =
 939                 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
 940         return types.functionalInterfaceBridges(csym);
 941     }
 942 
 943     /** does this functional expression require serialization support? */
 944     boolean isSerializable(JCFunctionalExpression tree) {
 945         if (forceSerializable) {
 946             return true;
 947         }
 948         return types.asSuper(tree.target, syms.serializableType.tsym) != null;
 949     }
 950 
 951     boolean isQuotable(JCFunctionalExpression tree) {
 952         return tree.codeModel != null;
 953     }
 954 
 955     void dumpStats(JCFunctionalExpression tree, boolean needsAltMetafactory, Symbol sym) {
 956         if (dumpLambdaToMethodStats) {
 957             if (tree instanceof JCLambda lambda) {
 958                 log.note(tree, diags.noteKey(lambda.wasMethodReference ? "mref.stat.1" : "lambda.stat",
 959                         needsAltMetafactory, sym));
 960             } else if (tree instanceof JCMemberReference) {
 961                 log.note(tree, Notes.MrefStat(needsAltMetafactory, null));
 962             }
 963         }
 964     }
 965 
 966     /**
 967      * This class retains all the useful information about a lambda expression,
 968      * and acts as a translation map that is used by the main translation routines
 969      * in order to adjust references to captured locals/members, etc.
 970      */
 971     class LambdaTranslationContext {
 972 
 973         /** the underlying (untranslated) tree */
 974         final JCFunctionalExpression tree;
 975 
 976         /** a translation map from source symbols to translated symbols */
 977         final Map<VarSymbol, VarSymbol> lambdaProxies = new HashMap<>();
 978 
 979         /** the list of symbols captured by this lambda expression */
 980         final List<VarSymbol> capturedVars;
 981 
 982         /** the synthetic symbol for the method hoisting the translated lambda */
 983         final MethodSymbol translatedSym;
 984 
 985         /** the list of parameter declarations of the translated lambda method */
 986         final List<JCVariableDecl> syntheticParams;
 987 
 988         LambdaTranslationContext(JCLambda tree) {
 989             this.tree = tree;
 990             // This symbol will be filled-in in complete
 991             Symbol owner = tree.owner;
 992             if (owner.kind == MTH) {
 993                 final MethodSymbol originalOwner = (MethodSymbol)owner.clone(owner.owner);
 994                 this.translatedSym = new MethodSymbol(0, null, null, owner.enclClass()) {
 995                     @Override
 996                     public MethodSymbol originalEnclosingMethod() {
 997                         return originalOwner;
 998                     }
 999                 };
1000             } else {
1001                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
1002             }
1003             ListBuffer<JCVariableDecl> params = new ListBuffer<>();
1004             ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>();
1005             LambdaCaptureScanner captureScanner = new LambdaCaptureScanner(tree);
1006             capturedVars = captureScanner.analyzeCaptures();
1007             for (VarSymbol captured : capturedVars) {
1008                 VarSymbol trans = addSymbol(captured, LambdaSymbolKind.CAPTURED_VAR);
1009                 params.append(make.VarDef(trans, null));
1010                 parameterSymbols.add(trans);
1011             }
1012             for (JCVariableDecl param : tree.params) {
1013                 VarSymbol trans = addSymbol(param.sym, LambdaSymbolKind.PARAM);
1014                 params.append(make.VarDef(trans, null));
1015                 parameterSymbols.add(trans);
1016             }
1017             syntheticParams = params.toList();
1018             completeLambdaMethodSymbol(owner, captureScanner.capturesThis);
1019             translatedSym.params = parameterSymbols.toList();
1020         }
1021 
1022         void completeLambdaMethodSymbol(Symbol owner, boolean thisReferenced) {
1023             boolean inInterface = owner.enclClass().isInterface();
1024 
1025             // Compute and set the lambda name
1026             Name name = isSerializable(tree)
1027                     ? serializedLambdaName(owner)
1028                     : lambdaName(owner);
1029 
1030             //prepend synthetic args to translated lambda method signature
1031             Type type = types.createMethodTypeWithParameters(
1032                     generatedLambdaSig(),
1033                     TreeInfo.types(syntheticParams));
1034 
1035             // If instance access isn't needed, make it static.
1036             // Interface instance methods must be default methods.
1037             // Lambda methods are private synthetic.
1038             // Inherit ACC_STRICT from the enclosing method, or, for clinit,
1039             // from the class.
1040             long flags = SYNTHETIC | LAMBDA_METHOD |
1041                     owner.flags_field & STRICTFP |
1042                     owner.owner.flags_field & STRICTFP |
1043                     PRIVATE |
1044                     (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
1045 
1046             translatedSym.type = type;
1047             translatedSym.name = name;
1048             translatedSym.flags_field = flags;
1049         }
1050 
1051         /**
1052          * For a serializable lambda, generate a disambiguating string
1053          * which maximizes stability across deserialization.
1054          *
1055          * @return String to differentiate synthetic lambda method names
1056          */
1057         private String serializedLambdaDisambiguation(Symbol owner) {
1058             StringBuilder buf = new StringBuilder();
1059             // Append the enclosing method signature to differentiate
1060             // overloaded enclosing methods.  For lambdas enclosed in
1061             // lambdas, the generated lambda method will not have type yet,
1062             // but the enclosing method's name will have been generated
1063             // with this same method, so it will be unique and never be
1064             // overloaded.
1065             Assert.check(
1066                     owner.type != null ||
1067                             lambdaContext != null);
1068             if (owner.type != null) {
1069                 buf.append(typeSig(owner.type, true));
1070                 buf.append(":");
1071             }
1072 
1073             // Add target type info
1074             buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
1075             buf.append(" ");
1076 
1077             // Add variable assigned to
1078             if (pendingVar != null) {
1079                 buf.append(pendingVar.flatName());
1080                 buf.append("=");
1081             }
1082             //add captured locals info: type, name, order
1083             for (Symbol fv : capturedVars) {
1084                 if (fv != owner) {
1085                     buf.append(typeSig(fv.type, true));
1086                     buf.append(" ");
1087                     buf.append(fv.flatName());
1088                     buf.append(",");
1089                 }
1090             }
1091 
1092             return buf.toString();
1093         }
1094 
1095         /**
1096          * For a non-serializable lambda, generate a simple method.
1097          *
1098          * @return Name to use for the synthetic lambda method name
1099          */
1100         private Name lambdaName(Symbol owner) {
1101             StringBuilder buf = new StringBuilder();
1102             buf.append(names.lambda);
1103             buf.append(syntheticMethodNameComponent(owner));
1104             buf.append("$");
1105             buf.append(kInfo.syntheticNameIndex(buf, 0));
1106             return names.fromString(buf.toString());
1107         }
1108 
1109         /**
1110          * @return Method name in a form that can be folded into a
1111          * component of a synthetic method name
1112          */
1113         String syntheticMethodNameComponent(Symbol owner) {
1114             long ownerFlags = owner.flags();
1115             if ((ownerFlags & BLOCK) != 0) {
1116                 return (ownerFlags & STATIC) != 0 ?
1117                         "static" : "new";
1118             } else if (owner.isConstructor()) {
1119                 return "new";
1120             } else {
1121                 return owner.name.toString();
1122             }
1123         }
1124 
1125         /**
1126          * For a serializable lambda, generate a method name which maximizes
1127          * name stability across deserialization.
1128          *
1129          * @return Name to use for the synthetic lambda method name
1130          */
1131         private Name serializedLambdaName(Symbol owner) {
1132             StringBuilder buf = new StringBuilder();
1133             buf.append(names.lambda);
1134             // Append the name of the method enclosing the lambda.
1135             buf.append(syntheticMethodNameComponent(owner));
1136             buf.append('$');
1137             // Append a hash of the disambiguating string : enclosing method
1138             // signature, etc.
1139             String disam = serializedLambdaDisambiguation(owner);
1140             buf.append(Integer.toHexString(disam.hashCode()));
1141             buf.append('$');
1142             // The above appended name components may not be unique, append
1143             // a count based on the above name components.
1144             buf.append(kInfo.syntheticNameIndex(buf, 1));
1145             String result = buf.toString();
1146             //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
1147             return names.fromString(result);
1148         }
1149 
1150         /**
1151          * Translate a symbol of a given kind into something suitable for the
1152          * synthetic lambda body
1153          */
1154         VarSymbol translate(final VarSymbol sym, LambdaSymbolKind skind) {
1155             VarSymbol ret;
1156             boolean propagateAnnos = true;
1157             switch (skind) {
1158                 case CAPTURED_VAR:
1159                     Name name = (sym.flags() & LOCAL_CAPTURE_FIELD) != 0 ?
1160                             sym.baseSymbol().name : sym.name;
1161                     ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym);
1162                     propagateAnnos = false;
1163                     break;
1164                 case LOCAL_VAR:
1165                     ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
1166                     ret.pos = sym.pos;
1167                     // If sym.data == ElementKind.EXCEPTION_PARAMETER,
1168                     // set ret.data = ElementKind.EXCEPTION_PARAMETER too.
1169                     // Because method com.sun.tools.javac.jvm.Code.fillExceptionParameterPositions and
1170                     // com.sun.tools.javac.jvm.Code.fillLocalVarPosition would use it.
1171                     // See JDK-8257740 for more information.
1172                     if (sym.isExceptionParameter()) {
1173                         ret.setData(ElementKind.EXCEPTION_PARAMETER);
1174                     }
1175                     break;
1176                 case PARAM:
1177                     ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym);
1178                     ret.pos = sym.pos;
1179                     break;
1180                 default:
1181                     Assert.error(skind.name());
1182                     throw new AssertionError();
1183             }
1184             if (ret != sym && propagateAnnos) {
1185                 ret.setDeclarationAttributes(sym.getRawAttributes());
1186                 ret.setTypeAttributes(sym.getRawTypeAttributes());
1187             }
1188             return ret;
1189         }
1190 
1191         VarSymbol addLocal(VarSymbol sym) {
1192             return addSymbol(sym, LambdaSymbolKind.LOCAL_VAR);
1193         }
1194 
1195         private VarSymbol addSymbol(VarSymbol sym, LambdaSymbolKind skind) {
1196             return lambdaProxies.computeIfAbsent(sym, s -> translate(s, skind));
1197         }
1198 
1199         JCTree translate(JCIdent lambdaIdent) {
1200             Symbol tSym = lambdaProxies.get(lambdaIdent.sym);
1201             return tSym != null ?
1202                     make.Ident(tSym).setType(lambdaIdent.type) :
1203                     null;
1204         }
1205 
1206         Type generatedLambdaSig() {
1207             return types.erasure(tree.getDescriptorType(types));
1208         }
1209 
1210         /**
1211          * Compute the set of local variables captured by this lambda expression.
1212          * Also determines whether this lambda expression captures the enclosing 'this'.
1213          */
1214         class LambdaCaptureScanner extends CaptureScanner {
1215             boolean capturesThis;
1216             Set<ClassSymbol> seenClasses = new HashSet<>();
1217 
1218             LambdaCaptureScanner(JCLambda ownerTree) {
1219                 super(ownerTree);
1220             }
1221 
1222             @Override
1223             public void visitClassDef(JCClassDecl tree) {
1224                 seenClasses.add(tree.sym);
1225                 super.visitClassDef(tree);
1226             }
1227 
1228             @Override
1229             public void visitIdent(JCIdent tree) {
1230                 if (!tree.sym.isStatic() &&
1231                         tree.sym.owner.kind == TYP &&
1232                         (tree.sym.kind == VAR || tree.sym.kind == MTH) &&
1233                         !seenClasses.contains(tree.sym.owner)) {
1234                     if ((tree.sym.flags() & LOCAL_CAPTURE_FIELD) != 0) {
1235                         // a local, captured by Lower - re-capture!
1236                         addFreeVar((VarSymbol) tree.sym);
1237                     } else {
1238                         // a reference to an enclosing field or method, we need to capture 'this'
1239                         capturesThis = true;
1240                     }
1241                 } else {
1242                     // might be a local capture
1243                     super.visitIdent(tree);
1244                 }
1245             }
1246 
1247             @Override
1248             public void visitSelect(JCFieldAccess tree) {
1249                 if (tree.sym.kind == VAR &&
1250                         (tree.sym.name == names._this ||
1251                                 tree.sym.name == names._super) &&
1252                         !seenClasses.contains(tree.sym.type.tsym)) {
1253                     capturesThis = true;
1254                 }
1255                 super.visitSelect(tree);
1256             }
1257 
1258             @Override
1259             public void visitAnnotation(JCAnnotation tree) {
1260                 // do nothing (annotation values look like captured instance fields)
1261             }
1262         }
1263 
1264         /*
1265          * These keys provide mappings for various translated lambda symbols
1266          * and the prevailing order must be maintained.
1267          */
1268         enum LambdaSymbolKind {
1269             PARAM,          // original to translated lambda parameters
1270             LOCAL_VAR,      // original to translated lambda locals
1271             CAPTURED_VAR;   // variables in enclosing scope to translated synthetic parameters
1272         }
1273     }
1274 
1275     /**
1276      * ****************************************************************
1277      * Signature Generation
1278      * ****************************************************************
1279      */
1280 
1281     private String typeSig(Type type) {
1282         return typeSig(type, false);
1283     }
1284 
1285     private String typeSig(Type type, boolean allowIllegalSignature) {
1286         try {
1287             L2MSignatureGenerator sg = new L2MSignatureGenerator(allowIllegalSignature);
1288             sg.assembleSig(type);
1289             return sg.toString();
1290         } catch (InvalidSignatureException ex) {
1291             Symbol c = attrEnv.enclClass.sym;
1292             log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
1293             return "<ERRONEOUS>";
1294         }
1295     }
1296 
1297     private String classSig(Type type) {
1298         try {
1299             L2MSignatureGenerator sg = new L2MSignatureGenerator(false);
1300             sg.assembleClassSig(type);
1301             return sg.toString();
1302         } catch (InvalidSignatureException ex) {
1303             Symbol c = attrEnv.enclClass.sym;
1304             log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
1305             return "<ERRONEOUS>";
1306         }
1307     }
1308 
1309     /**
1310      * Signature Generation
1311      */
1312     private class L2MSignatureGenerator extends Types.SignatureGenerator {
1313 
1314         /**
1315          * An output buffer for type signatures.
1316          */
1317         StringBuilder sb = new StringBuilder();
1318 
1319         /**
1320          * Are signatures incompatible with JVM spec allowed?
1321          * Used by {@link LambdaTranslationContext#serializedLambdaDisambiguation(Symbol)}}.
1322          */
1323         boolean allowIllegalSignatures;
1324 
1325         L2MSignatureGenerator(boolean allowIllegalSignatures) {
1326             types.super();
1327             this.allowIllegalSignatures = allowIllegalSignatures;
1328         }
1329 
1330         @Override
1331         protected void reportIllegalSignature(Type t) {
1332             if (!allowIllegalSignatures) {
1333                 super.reportIllegalSignature(t);
1334             }
1335         }
1336 
1337         @Override
1338         protected void append(char ch) {
1339             sb.append(ch);
1340         }
1341 
1342         @Override
1343         protected void append(byte[] ba) {
1344             Name name;
1345             try {
1346                 name = names.fromUtf(ba);
1347             } catch (InvalidUtfException e) {
1348                 throw new AssertionError(e);
1349             }
1350             sb.append(name.toString());
1351         }
1352 
1353         @Override
1354         protected void append(Name name) {
1355             sb.append(name.toString());
1356         }
1357 
1358         @Override
1359         public String toString() {
1360             return sb.toString();
1361         }
1362     }
1363 }