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