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