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