1 /*
   2  * Copyright (c) 2010, 2022, 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.Symbol.MethodHandleSymbol;
  29 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
  30 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
  31 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  32 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  33 import com.sun.tools.javac.tree.*;
  34 import com.sun.tools.javac.tree.JCTree.*;
  35 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
  36 import com.sun.tools.javac.tree.TreeMaker;
  37 import com.sun.tools.javac.tree.TreeTranslator;
  38 import com.sun.tools.javac.code.Attribute;
  39 import com.sun.tools.javac.code.Symbol;
  40 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  41 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
  42 import com.sun.tools.javac.code.Symbol.MethodSymbol;
  43 import com.sun.tools.javac.code.Symbol.TypeSymbol;
  44 import com.sun.tools.javac.code.Symbol.VarSymbol;
  45 import com.sun.tools.javac.code.Symtab;
  46 import com.sun.tools.javac.code.Type;
  47 import com.sun.tools.javac.code.Type.MethodType;
  48 import com.sun.tools.javac.code.Type.TypeVar;
  49 import com.sun.tools.javac.code.Types;
  50 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
  51 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
  52 import com.sun.tools.javac.resources.CompilerProperties.Notes;
  53 import com.sun.tools.javac.jvm.*;
  54 import com.sun.tools.javac.util.*;
  55 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  56 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
  57 
  58 import java.util.EnumMap;
  59 import java.util.HashMap;
  60 import java.util.HashSet;
  61 import java.util.LinkedHashMap;
  62 import java.util.Map;
  63 import java.util.Optional;
  64 import java.util.Set;
  65 import java.util.function.Consumer;
  66 import java.util.function.Supplier;
  67 
  68 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
  69 import static com.sun.tools.javac.code.Flags.*;
  70 import static com.sun.tools.javac.code.Kinds.Kind.*;
  71 import static com.sun.tools.javac.code.TypeTag.*;
  72 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  73 
  74 import javax.lang.model.element.ElementKind;
  75 import javax.lang.model.type.TypeKind;
  76 
  77 import com.sun.tools.javac.main.Option;
  78 
  79 /**
  80  * This pass desugars lambda expressions into static methods
  81  *
  82  *  <p><b>This is NOT part of any supported API.
  83  *  If you write code that depends on this, you do so at your own risk.
  84  *  This code and its internal interfaces are subject to change or
  85  *  deletion without notice.</b>
  86  */
  87 public class LambdaToMethod extends TreeTranslator {
  88 
  89     private Attr attr;
  90     private JCDiagnostic.Factory diags;
  91     private Log log;
  92     private Lower lower;
  93     private Names names;
  94     private Symtab syms;
  95     private Resolve rs;
  96     private Operators operators;
  97     private TreeMaker make;
  98     private Types types;
  99     private TransTypes transTypes;
 100     private Env<AttrContext> attrEnv;
 101 
 102     /** the analyzer scanner */
 103     private LambdaAnalyzerPreprocessor analyzer;
 104 
 105     /** map from lambda trees to translation contexts */
 106     private Map<JCTree, TranslationContext<?>> contextMap;
 107 
 108     /** current translation context (visitor argument) */
 109     private TranslationContext<?> context;
 110 
 111     /** info about the current class being processed */
 112     private KlassInfo kInfo;
 113 
 114     /** dump statistics about lambda code generation */
 115     private final boolean dumpLambdaToMethodStats;
 116 
 117     /** force serializable representation, for stress testing **/
 118     private final boolean forceSerializable;
 119 
 120     /** true if line or local variable debug info has been requested */
 121     private final boolean debugLinesOrVars;
 122 
 123     /** dump statistics about lambda method deduplication */
 124     private final boolean verboseDeduplication;
 125 
 126     /** deduplicate lambda implementation methods */
 127     private final boolean deduplicateLambdas;
 128 
 129     /** lambda proxy is a dynamic nestmate */
 130     private final boolean nestmateLambdas;
 131 
 132     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
 133     public static final int FLAG_SERIALIZABLE = 1 << 0;
 134 
 135     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
 136     public static final int FLAG_MARKERS = 1 << 1;
 137 
 138     /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
 139     public static final int FLAG_BRIDGES = 1 << 2;
 140 
 141     // <editor-fold defaultstate="collapsed" desc="Instantiating">
 142     protected static final Context.Key<LambdaToMethod> unlambdaKey = new Context.Key<>();
 143 
 144     public static LambdaToMethod instance(Context context) {
 145         LambdaToMethod instance = context.get(unlambdaKey);
 146         if (instance == null) {
 147             instance = new LambdaToMethod(context);
 148         }
 149         return instance;
 150     }
 151     private LambdaToMethod(Context context) {
 152         context.put(unlambdaKey, this);
 153         diags = JCDiagnostic.Factory.instance(context);
 154         log = Log.instance(context);
 155         lower = Lower.instance(context);
 156         names = Names.instance(context);
 157         syms = Symtab.instance(context);
 158         rs = Resolve.instance(context);
 159         operators = Operators.instance(context);
 160         make = TreeMaker.instance(context);
 161         types = Types.instance(context);
 162         transTypes = TransTypes.instance(context);
 163         analyzer = new LambdaAnalyzerPreprocessor();
 164         Options options = Options.instance(context);
 165         dumpLambdaToMethodStats = options.isSet("debug.dumpLambdaToMethodStats");
 166         attr = Attr.instance(context);
 167         forceSerializable = options.isSet("forceSerializable");
 168         boolean lineDebugInfo =
 169             options.isUnset(Option.G_CUSTOM) ||
 170             options.isSet(Option.G_CUSTOM, "lines");
 171         boolean varDebugInfo =
 172             options.isUnset(Option.G_CUSTOM)
 173             ? options.isSet(Option.G)
 174             : options.isSet(Option.G_CUSTOM, "vars");
 175         debugLinesOrVars = lineDebugInfo || varDebugInfo;
 176         verboseDeduplication = options.isSet("debug.dumpLambdaToMethodDeduplication");
 177         deduplicateLambdas = options.getBoolean("deduplicateLambdas", true);
 178         nestmateLambdas = Target.instance(context).runtimeUseNestAccess();
 179     }
 180     // </editor-fold>
 181 
 182     class DedupedLambda {
 183         private final MethodSymbol symbol;
 184         private final JCTree tree;
 185 
 186         private int hashCode;
 187 
 188         DedupedLambda(MethodSymbol symbol, JCTree tree) {
 189             this.symbol = symbol;
 190             this.tree = tree;
 191         }
 192 
 193 
 194         @Override
 195         public int hashCode() {
 196             int hashCode = this.hashCode;
 197             if (hashCode == 0) {
 198                 this.hashCode = hashCode = TreeHasher.hash(tree, symbol.params());
 199             }
 200             return hashCode;
 201         }
 202 
 203         @Override
 204         public boolean equals(Object o) {
 205             return (o instanceof DedupedLambda dedupedLambda)
 206                     && types.isSameType(symbol.asType(), dedupedLambda.symbol.asType())
 207                     && new TreeDiffer(symbol.params(), dedupedLambda.symbol.params()).scan(tree, dedupedLambda.tree);
 208         }
 209     }
 210 
 211     private class KlassInfo {
 212 
 213         /**
 214          * list of methods to append
 215          */
 216         private ListBuffer<JCTree> appendedMethodList;
 217 
 218         private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
 219 
 220         private Map<Object, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
 221 
 222         /**
 223          * list of deserialization cases
 224          */
 225         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
 226 
 227        /**
 228          * deserialize method symbol
 229          */
 230         private final MethodSymbol deserMethodSym;
 231 
 232         /**
 233          * deserialize method parameter symbol
 234          */
 235         private final VarSymbol deserParamSym;
 236 
 237         private final JCClassDecl clazz;
 238 
 239         private KlassInfo(JCClassDecl clazz) {
 240             this.clazz = clazz;
 241             appendedMethodList = new ListBuffer<>();
 242             dedupedLambdas = new HashMap<>();
 243             deserializeCases = new HashMap<>();
 244             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
 245                     List.nil(), syms.methodClass);
 246             deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
 247             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
 248                     syms.serializedLambdaType, deserMethodSym);
 249         }
 250 
 251         private void addMethod(JCTree decl) {
 252             appendedMethodList = appendedMethodList.prepend(decl);
 253         }
 254     }
 255 
 256     // <editor-fold defaultstate="collapsed" desc="translate methods">
 257     @Override
 258     public <T extends JCTree> T translate(T tree) {
 259         TranslationContext<?> newContext = contextMap.get(tree);
 260         return translate(tree, newContext != null ? newContext : context);
 261     }
 262 
 263     <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
 264         TranslationContext<?> prevContext = context;
 265         try {
 266             context = newContext;
 267             return super.translate(tree);
 268         }
 269         finally {
 270             context = prevContext;
 271         }
 272     }
 273 
 274     <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
 275         ListBuffer<T> buf = new ListBuffer<>();
 276         for (T tree : trees) {
 277             buf.append(translate(tree, newContext));
 278         }
 279         return buf.toList();
 280     }
 281 
 282     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
 283         this.make = make;
 284         this.attrEnv = env;
 285         this.context = null;
 286         this.contextMap = new HashMap<>();
 287         return translate(cdef);
 288     }
 289     // </editor-fold>
 290 
 291     // <editor-fold defaultstate="collapsed" desc="visitor methods">
 292     /**
 293      * Visit a class.
 294      * Maintain the translatedMethodList across nested classes.
 295      * Append the translatedMethodList to the class after it is translated.
 296      * @param tree
 297      */
 298     @Override
 299     public void visitClassDef(JCClassDecl tree) {
 300         if (tree.sym.owner.kind == PCK) {
 301             //analyze class
 302             tree = analyzer.analyzeAndPreprocessClass(tree);
 303         }
 304         KlassInfo prevKlassInfo = kInfo;
 305         try {
 306             kInfo = new KlassInfo(tree);
 307             super.visitClassDef(tree);
 308             if (!kInfo.deserializeCases.isEmpty()) {
 309                 int prevPos = make.pos;
 310                 try {
 311                     make.at(tree);
 312                     kInfo.addMethod(makeDeserializeMethod(tree.sym));
 313                 } finally {
 314                     make.at(prevPos);
 315                 }
 316             }
 317             //add all translated instance methods here
 318             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
 319             tree.defs = tree.defs.appendList(newMethods);
 320             for (JCTree lambda : newMethods) {
 321                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
 322             }
 323             result = tree;
 324         } finally {
 325             kInfo = prevKlassInfo;
 326         }
 327     }
 328 
 329     /**
 330      * Translate a lambda into a method to be inserted into the class.
 331      * Then replace the lambda site with an invokedynamic call of to lambda
 332      * meta-factory, which will use the lambda method.
 333      * @param tree
 334      */
 335     @Override
 336     public void visitLambda(JCLambda tree) {
 337         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
 338         MethodSymbol sym = localContext.translatedSym;
 339         MethodType lambdaType = (MethodType) sym.type;
 340 
 341         {   /* Type annotation management: Based on where the lambda features, type annotations that
 342                are interior to it, may at this point be attached to the enclosing method, or the first
 343                constructor in the class, or in the enclosing class symbol or in the field whose
 344                initializer is the lambda. In any event, gather up the annotations that belong to the
 345                lambda and attach it to the implementation method.
 346             */
 347 
 348             Symbol owner = localContext.owner;
 349             apportionTypeAnnotations(tree,
 350                     owner::getRawTypeAttributes,
 351                     owner::setTypeAttributes,
 352                     sym::setTypeAttributes);
 353 
 354 
 355             boolean init;
 356             // TODO - can <vnew> exist in this context?
 357             if ((init = names.isInitOrVNew(owner.name)) || owner.name == names.clinit) {
 358                 owner = owner.owner;
 359                 apportionTypeAnnotations(tree,
 360                         init ? owner::getInitTypeAttributes : owner::getClassInitTypeAttributes,
 361                         init ? owner::setInitTypeAttributes : owner::setClassInitTypeAttributes,
 362                         sym::appendUniqueTypeAttributes);
 363             }
 364             if (localContext.self != null && localContext.self.getKind() == ElementKind.FIELD) {
 365                 owner = localContext.self;
 366                 apportionTypeAnnotations(tree,
 367                         owner::getRawTypeAttributes,
 368                         owner::setTypeAttributes,
 369                         sym::appendUniqueTypeAttributes);
 370             }
 371         }
 372 
 373         //create the method declaration hoisting the lambda body
 374         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
 375                 sym.name,
 376                 make.QualIdent(lambdaType.getReturnType().tsym).setType(lambdaType.getReturnType()),
 377                 List.nil(),
 378                 localContext.syntheticParams,
 379                 lambdaType.getThrownTypes() == null ?
 380                     List.nil() :
 381                     make.Types(lambdaType.getThrownTypes()),
 382                 null,
 383                 null);
 384         lambdaDecl.sym = sym;
 385         lambdaDecl.type = lambdaType;
 386 
 387         //translate lambda body
 388         //As the lambda body is translated, all references to lambda locals,
 389         //captured variables, enclosing members are adjusted accordingly
 390         //to refer to the static method parameters (rather than i.e. accessing
 391         //captured members directly).
 392         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
 393 
 394         boolean dedupe = false;
 395         if (deduplicateLambdas && !debugLinesOrVars && !localContext.isSerializable()) {
 396             DedupedLambda dedupedLambda = new DedupedLambda(lambdaDecl.sym, lambdaDecl.body);
 397             DedupedLambda existing = kInfo.dedupedLambdas.putIfAbsent(dedupedLambda, dedupedLambda);
 398             if (existing != null) {
 399                 sym = existing.symbol;
 400                 dedupe = true;
 401                 if (verboseDeduplication) log.note(tree, Notes.VerboseL2mDeduplicate(sym));
 402             }
 403         }
 404         if (!dedupe) {
 405             //Add the method to the list of methods to be added to this class.
 406             kInfo.addMethod(lambdaDecl);
 407         }
 408 
 409         //now that we have generated a method for the lambda expression,
 410         //we can translate the lambda into a method reference pointing to the newly
 411         //created method.
 412         //
 413         //Note that we need to adjust the method handle so that it will match the
 414         //signature of the SAM descriptor - this means that the method reference
 415         //should be added the following synthetic arguments:
 416         //
 417         // * the "this" argument if it is an instance method
 418         // * enclosing locals captured by the lambda expression
 419 
 420         ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
 421 
 422         if (localContext.methodReferenceReceiver != null) {
 423             syntheticInits.append(localContext.methodReferenceReceiver);
 424         } else if (!sym.isStatic()) {
 425             syntheticInits.append(makeThis(
 426                     sym.owner.enclClass().asType(),
 427                     localContext.owner.enclClass()));
 428         }
 429 
 430         //add captured locals
 431         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
 432             if (fv != localContext.self) {
 433                 JCExpression captured_local = make.Ident(fv).setType(fv.type);
 434                 syntheticInits.append(captured_local);
 435             }
 436         }
 437         // add captured outer this instances (used only when `this' capture itself is illegal)
 438         for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) {
 439             JCExpression captured_local = make.QualThis(fv.type);
 440             syntheticInits.append(captured_local);
 441         }
 442 
 443         //then, determine the arguments to the indy call
 444         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
 445 
 446         //convert to an invokedynamic call
 447         result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args);
 448     }
 449 
 450     // where
 451         // Reassign type annotations from the source that should really belong to the lambda
 452         private void apportionTypeAnnotations(JCLambda tree,
 453                                               Supplier<List<Attribute.TypeCompound>> source,
 454                                               Consumer<List<Attribute.TypeCompound>> owner,
 455                                               Consumer<List<Attribute.TypeCompound>> lambda) {
 456 
 457             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
 458             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
 459 
 460             for (Attribute.TypeCompound tc : source.get()) {
 461                 if (tc.position.onLambda == tree) {
 462                     lambdaTypeAnnos.append(tc);
 463                 } else {
 464                     ownerTypeAnnos.append(tc);
 465                 }
 466             }
 467             if (lambdaTypeAnnos.nonEmpty()) {
 468                 owner.accept(ownerTypeAnnos.toList());
 469                 lambda.accept(lambdaTypeAnnos.toList());
 470             }
 471         }
 472 
 473     private JCIdent makeThis(Type type, Symbol owner) {
 474         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
 475                 names._this,
 476                 type,
 477                 owner);
 478         return make.Ident(_this);
 479     }
 480 
 481     /**
 482      * Translate a method reference into an invokedynamic call to the
 483      * meta-factory.
 484      * @param tree
 485      */
 486     @Override
 487     public void visitReference(JCMemberReference tree) {
 488         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
 489 
 490         //first determine the method symbol to be used to generate the sam instance
 491         //this is either the method reference symbol, or the bridged reference symbol
 492         MethodSymbol refSym = (MethodSymbol)tree.sym;
 493 
 494         //the qualifying expression is treated as a special captured arg
 495         JCExpression init;
 496         switch(tree.kind) {
 497 
 498             case IMPLICIT_INNER:    /** Inner :: new */
 499             case SUPER:             /** super :: instMethod */
 500                 init = makeThis(
 501                     localContext.owner.enclClass().asType(),
 502                     localContext.owner.enclClass());
 503                 break;
 504 
 505             case BOUND:             /** Expr :: instMethod */
 506                 init = transTypes.coerce(attrEnv, tree.getQualifierExpression(),
 507                     types.erasure(tree.sym.owner.type));
 508                 init = attr.makeNullCheck(init);
 509                 break;
 510 
 511             case UNBOUND:           /** Type :: instMethod */
 512             case STATIC:            /** Type :: staticMethod */
 513             case TOPLEVEL:          /** Top level :: new */
 514             case ARRAY_CTOR:        /** ArrayType :: new */
 515                 init = null;
 516                 break;
 517 
 518             default:
 519                 throw new InternalError("Should not have an invalid kind");
 520         }
 521 
 522         if (init != null) {
 523             refSym = (MethodSymbol) types.binaryQualifier(refSym, init.type);
 524         }
 525         List<JCExpression> indy_args = init==null? List.nil() : translate(List.of(init), localContext.prev);
 526 
 527 
 528         //build a sam instance using an indy call to the meta-factory
 529         result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args);
 530     }
 531 
 532     /**
 533      * Translate identifiers within a lambda to the mapped identifier
 534      * @param tree
 535      */
 536     @Override
 537     public void visitIdent(JCIdent tree) {
 538         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
 539             super.visitIdent(tree);
 540         } else {
 541             int prevPos = make.pos;
 542             try {
 543                 make.at(tree);
 544 
 545                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
 546                 JCTree ltree = lambdaContext.translate(tree);
 547                 if (ltree != null) {
 548                     result = ltree;
 549                 } else {
 550                     //access to untranslated symbols (i.e. compile-time constants,
 551                     //members defined inside the lambda body, etc.) )
 552                     super.visitIdent(tree);
 553                 }
 554             } finally {
 555                 make.at(prevPos);
 556             }
 557         }
 558     }
 559 
 560     /**
 561      * Translate qualified `this' references within a lambda to the mapped identifier
 562      * @param tree
 563      */
 564     @Override
 565     public void visitSelect(JCFieldAccess tree) {
 566         if (context == null || !analyzer.lambdaFieldAccessFilter(tree)) {
 567             super.visitSelect(tree);
 568         } else {
 569             int prevPos = make.pos;
 570             try {
 571                 make.at(tree);
 572 
 573                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
 574                 JCTree ltree = lambdaContext.translate(tree);
 575                 if (ltree != null) {
 576                     result = ltree;
 577                 } else {
 578                     super.visitSelect(tree);
 579                 }
 580             } finally {
 581                 make.at(prevPos);
 582             }
 583         }
 584     }
 585 
 586     /**
 587      * Translate instance creation expressions with implicit enclosing instances
 588      * @param tree
 589      */
 590     @Override
 591     public void visitNewClass(JCNewClass tree) {
 592         if (context == null || !analyzer.lambdaNewClassFilter(context, tree)) {
 593             super.visitNewClass(tree);
 594         } else {
 595             int prevPos = make.pos;
 596             try {
 597                 make.at(tree);
 598 
 599                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
 600                 tree = lambdaContext.translate(tree);
 601                 super.visitNewClass(tree);
 602             } finally {
 603                 make.at(prevPos);
 604             }
 605         }
 606     }
 607 
 608     @Override
 609     public void visitVarDef(JCVariableDecl tree) {
 610         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
 611         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
 612             tree.init = translate(tree.init);
 613             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
 614             result = tree;
 615         } else {
 616             super.visitVarDef(tree);
 617         }
 618     }
 619 
 620     // </editor-fold>
 621 
 622     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
 623 
 624     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
 625         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
 626                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
 627                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
 628     }
 629 
 630     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
 631         Type restype = lambdaMethodDecl.type.getReturnType();
 632         boolean isLambda_void = expr.type.hasTag(VOID);
 633         boolean isTarget_void = restype.hasTag(VOID);
 634         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
 635         int prevPos = make.pos;
 636         try {
 637             if (isTarget_void) {
 638                 //target is void:
 639                 // BODY;
 640                 JCStatement stat = make.at(expr).Exec(expr);
 641                 return make.Block(0, List.of(stat));
 642             } else if (isLambda_void && isTarget_Void) {
 643                 //void to Void conversion:
 644                 // BODY; return null;
 645                 ListBuffer<JCStatement> stats = new ListBuffer<>();
 646                 stats.append(make.at(expr).Exec(expr));
 647                 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
 648                 return make.Block(0, stats.toList());
 649             } else {
 650                 //non-void to non-void conversion:
 651                 // return BODY;
 652                 return make.at(expr).Block(0, List.of(make.Return(expr)));
 653             }
 654         } finally {
 655             make.at(prevPos);
 656         }
 657     }
 658 
 659     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
 660         final Type restype = lambdaMethodDecl.type.getReturnType();
 661         final boolean isTarget_void = restype.hasTag(VOID);
 662         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
 663 
 664         class LambdaBodyTranslator extends TreeTranslator {
 665 
 666             @Override
 667             public void visitClassDef(JCClassDecl tree) {
 668                 //do NOT recurse on any inner classes
 669                 result = tree;
 670             }
 671 
 672             @Override
 673             public void visitLambda(JCLambda tree) {
 674                 //do NOT recurse on any nested lambdas
 675                 result = tree;
 676             }
 677 
 678             @Override
 679             public void visitReturn(JCReturn tree) {
 680                 boolean isLambda_void = tree.expr == null;
 681                 if (isTarget_void && !isLambda_void) {
 682                     //Void to void conversion:
 683                     // { TYPE $loc = RET-EXPR; return; }
 684                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
 685                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
 686                     result = make.Block(0, List.of(varDef, make.Return(null)));
 687                 } else {
 688                     result = tree;
 689                 }
 690 
 691             }
 692         }
 693 
 694         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
 695         if (completeNormally && isTarget_Void) {
 696             //there's no return statement and the lambda (possibly inferred)
 697             //return type is java.lang.Void; emit a synthetic return statement
 698             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
 699         }
 700         return trans_block;
 701     }
 702 
 703     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
 704         ListBuffer<JCCase> cases = new ListBuffer<>();
 705         ListBuffer<JCBreak> breaks = new ListBuffer<>();
 706         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
 707             JCBreak br = make.Break(null);
 708             breaks.add(br);
 709             List<JCStatement> stmts = entry.getValue().append(br).toList();
 710             cases.add(make.Case(JCCase.STATEMENT, List.of(make.ConstantCaseLabel(make.Literal(entry.getKey()))), stmts, null));
 711         }
 712         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
 713         for (JCBreak br : breaks) {
 714             br.target = sw;
 715         }
 716         JCBlock body = make.Block(0L, List.of(
 717                 sw,
 718                 make.Throw(makeNewClass(
 719                     syms.illegalArgumentExceptionType,
 720                     List.of(make.Literal("Invalid lambda deserialization"))))));
 721         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
 722                         names.deserializeLambda,
 723                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
 724                         List.nil(),
 725                         List.of(make.VarDef(kInfo.deserParamSym, null)),
 726                         List.nil(),
 727                         body,
 728                         null);
 729         deser.sym = kInfo.deserMethodSym;
 730         deser.type = kInfo.deserMethodSym.type;
 731         //System.err.printf("DESER: '%s'\n", deser);
 732         return deser;
 733     }
 734 
 735     /** Make an attributed class instance creation expression.
 736      *  @param ctype    The class type.
 737      *  @param args     The constructor arguments.
 738      *  @param cons     The constructor symbol
 739      */
 740     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
 741         JCNewClass tree = make.NewClass(null,
 742             null, make.QualIdent(ctype.tsym), args, null);
 743         tree.constructor = cons;
 744         tree.type = ctype;
 745         return tree;
 746     }
 747 
 748     /** Make an attributed class instance creation expression.
 749      *  @param ctype    The class type.
 750      *  @param args     The constructor arguments.
 751      */
 752     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
 753         return makeNewClass(ctype, args,
 754                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
 755      }
 756 
 757     private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym,
 758                                         DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) {
 759         String functionalInterfaceClass = classSig(targetType);
 760         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
 761         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
 762         Symbol baseMethod = refSym.baseSymbol();
 763         Symbol origMethod = baseMethod.baseSymbol();
 764         if (baseMethod != origMethod && origMethod.owner == syms.objectType.tsym) {
 765             //the implementation method is a java.lang.Object method transferred to an
 766             //interface that does not declare it. Runtime will refer to this method as to
 767             //a java.lang.Object method, so do the same:
 768             refSym = ((MethodSymbol) origMethod).asHandle();
 769         }
 770         String implClass = classSig(types.erasure(refSym.owner.type));
 771         String implMethodName = refSym.getQualifiedName().toString();
 772         String implMethodSignature = typeSig(types.erasure(refSym.type));
 773 
 774         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
 775                 make.Literal(refSym.referenceKind()));
 776         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
 777         int i = 0;
 778         for (Type t : indyType.getParameterTypes()) {
 779             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
 780             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
 781             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
 782             ++i;
 783         }
 784         JCStatement stmt = make.If(
 785                 deserTest(deserTest(deserTest(deserTest(deserTest(
 786                     kindTest,
 787                     "getFunctionalInterfaceClass", functionalInterfaceClass),
 788                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
 789                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
 790                     "getImplClass", implClass),
 791                     "getImplMethodSignature", implMethodSignature),
 792                 make.Return(makeIndyCall(
 793                     pos,
 794                     syms.lambdaMetafactory,
 795                     names.altMetafactory,
 796                     staticArgs, indyType, serArgs.toList(), samSym.name)),
 797                 null);
 798         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
 799         if (stmts == null) {
 800             stmts = new ListBuffer<>();
 801             kInfo.deserializeCases.put(implMethodName, stmts);
 802         }
 803         /****
 804         System.err.printf("+++++++++++++++++\n");
 805         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
 806         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
 807         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
 808         System.err.printf("*implMethodKind: %d\n", implMethodKind);
 809         System.err.printf("*implClass: '%s'\n", implClass);
 810         System.err.printf("*implMethodName: '%s'\n", implMethodName);
 811         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
 812         ****/
 813         stmts.append(stmt);
 814     }
 815 
 816     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
 817         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
 818         testExpr.operator = operators.resolveBinary(testExpr, JCTree.Tag.EQ, argType, argType);
 819         testExpr.setType(syms.booleanType);
 820         return testExpr;
 821     }
 822 
 823     private JCExpression deserTest(JCExpression prev, String func, String lit) {
 824         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.nil(), syms.methodClass);
 825         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.nil());
 826         JCMethodInvocation eqtest = make.Apply(
 827                 List.nil(),
 828                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
 829                 List.of(make.Literal(lit)));
 830         eqtest.setType(syms.booleanType);
 831         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
 832         compound.operator = operators.resolveBinary(compound, JCTree.Tag.AND, syms.booleanType, syms.booleanType);
 833         compound.setType(syms.booleanType);
 834         return compound;
 835     }
 836 
 837     private JCExpression deserGetter(String func, Type type) {
 838         return deserGetter(func, type, List.nil(), List.nil());
 839     }
 840 
 841     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
 842         MethodType getmt = new MethodType(argTypes, type, List.nil(), syms.methodClass);
 843         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.nil());
 844         return make.Apply(
 845                     List.nil(),
 846                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
 847                     args).setType(type);
 848     }
 849 
 850     /**
 851      * Create new synthetic method with given flags, name, type, owner
 852      */
 853     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
 854         return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
 855     }
 856 
 857     /**
 858      * Create new synthetic variable with given flags, name, type, owner
 859      */
 860     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
 861         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
 862     }
 863 
 864     /**
 865      * Set varargsElement field on a given tree (must be either a new class tree
 866      * or a method call tree)
 867      */
 868     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
 869         if (varargsElement != null) {
 870             switch (tree.getTag()) {
 871                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
 872                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
 873                 case TYPECAST: setVarargsIfNeeded(((JCTypeCast) tree).expr, varargsElement); break;
 874                 default: throw new AssertionError();
 875             }
 876         }
 877     }
 878 
 879     /**
 880      * Convert method/constructor arguments by inserting appropriate cast
 881      * as required by type-erasure - this is needed when bridging a lambda/method
 882      * reference, as the bridged signature might require downcast to be compatible
 883      * with the generated signature.
 884      */
 885     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
 886        Assert.check(meth.kind == MTH);
 887        List<Type> formals = types.erasure(meth.type).getParameterTypes();
 888        if (varargsElement != null) {
 889            Assert.check((meth.flags() & VARARGS) != 0);
 890        }
 891        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
 892     }
 893 
 894     // </editor-fold>
 895 
 896     /**
 897      * Converts a method reference which cannot be used directly into a lambda
 898      */
 899     private class MemberReferenceToLambda {
 900 
 901         private final JCMemberReference tree;
 902         private final ReferenceTranslationContext localContext;
 903         private final Symbol owner;
 904         private final ListBuffer<JCExpression> args = new ListBuffer<>();
 905         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
 906 
 907         private JCExpression receiverExpression = null;
 908 
 909         MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) {
 910             this.tree = tree;
 911             this.localContext = localContext;
 912             this.owner = owner;
 913         }
 914 
 915         JCLambda lambda() {
 916             int prevPos = make.pos;
 917             try {
 918                 make.at(tree);
 919 
 920                 //body generation - this can be either a method call or a
 921                 //new instance creation expression, depending on the member reference kind
 922                 VarSymbol rcvr = addParametersReturnReceiver();
 923                 JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
 924                         ? expressionInvoke(rcvr)
 925                         : expressionNew();
 926 
 927                 JCLambda slam = make.Lambda(params.toList(), expr);
 928                 slam.target = tree.target;
 929                 slam.type = tree.type;
 930                 slam.pos = tree.pos;
 931                 return slam;
 932             } finally {
 933                 make.at(prevPos);
 934             }
 935         }
 936 
 937         /**
 938          * Generate the parameter list for the converted member reference.
 939          *
 940          * @return The receiver variable symbol, if any
 941          */
 942         VarSymbol addParametersReturnReceiver() {
 943             Type samDesc = localContext.bridgedRefSig();
 944             List<Type> samPTypes = samDesc.getParameterTypes();
 945             List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes();
 946 
 947             // Determine the receiver, if any
 948             VarSymbol rcvr;
 949             switch (tree.kind) {
 950                 case BOUND:
 951                     // The receiver is explicit in the method reference
 952                     rcvr = addParameter("rec$", tree.getQualifierExpression().type, false);
 953                     receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
 954                     break;
 955                 case UNBOUND:
 956                     // The receiver is the first parameter, extract it and
 957                     // adjust the SAM and unerased type lists accordingly
 958                     rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false);
 959                     samPTypes = samPTypes.tail;
 960                     descPTypes = descPTypes.tail;
 961                     break;
 962                 default:
 963                     rcvr = null;
 964                     break;
 965             }
 966             List<Type> implPTypes = tree.sym.type.getParameterTypes();
 967             int implSize = implPTypes.size();
 968             int samSize = samPTypes.size();
 969             // Last parameter to copy from referenced method, exclude final var args
 970             int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize;
 971 
 972             // Failsafe -- assure match-up
 973             boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size();
 974 
 975             // Use parameter types of the implementation method unless the unerased
 976             // SAM parameter type is an intersection type, in that case use the
 977             // erased SAM parameter type so that the supertype relationship
 978             // the implementation method parameters is not obscured.
 979             // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes
 980             // are used as pointers to the current parameter type information
 981             // and are thus not usable afterwards.
 982             for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) {
 983                 // By default use the implementation method parameter type
 984                 Type parmType = implPTypes.head;
 985                 if (checkForIntersection) {
 986                     if (descPTypes.head.getKind() == TypeKind.INTERSECTION) {
 987                         parmType = samPTypes.head;
 988                     }
 989                     // If the unerased parameter type is a type variable whose
 990                     // bound is an intersection (eg. <T extends A & B>) then
 991                     // use the SAM parameter type
 992                     if (descPTypes.head.getKind() == TypeKind.TYPEVAR) {
 993                         TypeVar tv = (TypeVar) descPTypes.head;
 994                         if (tv.getUpperBound().getKind() == TypeKind.INTERSECTION) {
 995                             parmType = samPTypes.head;
 996                         }
 997                     }
 998                 }
 999                 addParameter("x$" + i, parmType, true);
1000 
1001                 // Advance to the next parameter
1002                 implPTypes = implPTypes.tail;
1003                 samPTypes = samPTypes.tail;
1004                 descPTypes = descPTypes.tail;
1005             }
1006             // Flatten out the var args
1007             for (int i = last; i < samSize; ++i) {
1008                 addParameter("xva$" + i, tree.varargsElement, true);
1009             }
1010 
1011             return rcvr;
1012         }
1013 
1014         JCExpression getReceiverExpression() {
1015             return receiverExpression;
1016         }
1017 
1018         private JCExpression makeReceiver(VarSymbol rcvr) {
1019             if (rcvr == null) return null;
1020             JCExpression rcvrExpr = make.Ident(rcvr);
1021             boolean protAccess =
1022                     isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, owner);
1023             Type rcvrType = tree.ownerAccessible && !protAccess ? tree.sym.enclClass().type
1024                                                                 : tree.expr.type;
1025             if (rcvrType == syms.arrayClass.type) {
1026                 // Map the receiver type to the actually type, not just "array"
1027                 rcvrType = tree.getQualifierExpression().type;
1028             }
1029             if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
1030                 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
1031             }
1032             return rcvrExpr;
1033         }
1034 
1035         /**
1036          * determine the receiver of the method call - the receiver can
1037          * be a type qualifier, the synthetic receiver parameter or 'super'.
1038          */
1039         private JCExpression expressionInvoke(VarSymbol rcvr) {
1040             JCExpression qualifier =
1041                     (rcvr != null) ?
1042                         makeReceiver(rcvr) :
1043                         tree.getQualifierExpression();
1044 
1045             //create the qualifier expression
1046             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
1047             select.sym = tree.sym;
1048             select.type = tree.sym.erasure(types);
1049 
1050             //create the method call expression
1051             JCExpression apply = make.Apply(List.nil(), select,
1052                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
1053                     setType(tree.sym.erasure(types).getReturnType());
1054 
1055             apply = transTypes.coerce(attrEnv, apply,
1056                     types.erasure(localContext.tree.referentType.getReturnType()));
1057 
1058             setVarargsIfNeeded(apply, tree.varargsElement);
1059             return apply;
1060         }
1061 
1062         /**
1063          * Lambda body to use for a 'new'.
1064          */
1065         private JCExpression expressionNew() {
1066             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
1067                 //create the array creation expression
1068                 JCNewArray newArr = make.NewArray(
1069                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
1070                         List.of(make.Ident(params.first())),
1071                         null);
1072                 newArr.type = tree.getQualifierExpression().type;
1073                 return newArr;
1074             } else {
1075                 //create the instance creation expression
1076                 //note that method reference syntax does not allow an explicit
1077                 //enclosing class (so the enclosing class is null)
1078                 // but this may need to be patched up later with the proxy for the outer this
1079                 JCNewClass newClass = make.NewClass(null,
1080                         List.nil(),
1081                         make.Type(tree.getQualifierExpression().type),
1082                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
1083                         null);
1084                 newClass.constructor = tree.sym;
1085                 newClass.constructorType = tree.sym.erasure(types);
1086                 newClass.type = tree.getQualifierExpression().type;
1087                 setVarargsIfNeeded(newClass, tree.varargsElement);
1088                 return newClass;
1089             }
1090         }
1091 
1092         private VarSymbol addParameter(String name, Type p, boolean genArg) {
1093             VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
1094             vsym.pos = tree.pos;
1095             params.append(make.VarDef(vsym, null));
1096             if (genArg) {
1097                 args.append(make.Ident(vsym));
1098             }
1099             return vsym;
1100         }
1101     }
1102 
1103     private MethodType typeToMethodType(Type mt) {
1104         Type type = types.erasure(mt);
1105         return new MethodType(type.getParameterTypes(),
1106                         type.getReturnType(),
1107                         type.getThrownTypes(),
1108                         syms.methodClass);
1109     }
1110 
1111     /**
1112      * Generate an indy method call to the meta factory
1113      */
1114     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
1115             MethodHandleSymbol refSym, List<JCExpression> indy_args) {
1116         JCFunctionalExpression tree = context.tree;
1117         //determine the static bsm args
1118         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
1119         List<LoadableConstant> staticArgs = List.of(
1120                 typeToMethodType(samSym.type),
1121                 refSym.asHandle(),
1122                 typeToMethodType(tree.getDescriptorType(types)));
1123 
1124         //computed indy arg types
1125         ListBuffer<Type> indy_args_types = new ListBuffer<>();
1126         for (JCExpression arg : indy_args) {
1127             indy_args_types.append(arg.type);
1128         }
1129 
1130         //finally, compute the type of the indy call
1131         MethodType indyType = new MethodType(indy_args_types.toList(),
1132                 tree.type,
1133                 List.nil(),
1134                 syms.methodClass);
1135 
1136         Name metafactoryName = context.needsAltMetafactory() ?
1137                 names.altMetafactory : names.metafactory;
1138 
1139         if (context.needsAltMetafactory()) {
1140             ListBuffer<Type> markers = new ListBuffer<>();
1141             List<Type> targets = tree.target.isIntersection() ?
1142                     types.directSupertypes(tree.target) :
1143                     List.nil();
1144             for (Type t : targets) {
1145                 t = types.erasure(t);
1146                 if (t.tsym != syms.serializableType.tsym &&
1147                     t.tsym != tree.type.tsym &&
1148                     t.tsym != syms.objectType.tsym) {
1149                     markers.append(t);
1150                 }
1151             }
1152             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
1153             boolean hasMarkers = markers.nonEmpty();
1154             boolean hasBridges = context.bridges.nonEmpty();
1155             if (hasMarkers) {
1156                 flags |= FLAG_MARKERS;
1157             }
1158             if (hasBridges) {
1159                 flags |= FLAG_BRIDGES;
1160             }
1161             staticArgs = staticArgs.append(LoadableConstant.Int(flags));
1162             if (hasMarkers) {
1163                 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
1164                 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
1165             }
1166             if (hasBridges) {
1167                 staticArgs = staticArgs.append(LoadableConstant.Int(context.bridges.length() - 1));
1168                 for (Symbol s : context.bridges) {
1169                     Type s_erasure = s.erasure(types);
1170                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
1171                         staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
1172                     }
1173                 }
1174             }
1175             if (context.isSerializable()) {
1176                 int prevPos = make.pos;
1177                 try {
1178                     make.at(kInfo.clazz);
1179                     addDeserializationCase(refSym, tree.type, samSym,
1180                             tree, staticArgs, indyType);
1181                 } finally {
1182                     make.at(prevPos);
1183                 }
1184             }
1185         }
1186 
1187         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
1188     }
1189 
1190     /**
1191      * Generate an indy method call with given name, type and static bootstrap
1192      * arguments types
1193      */
1194     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
1195                                       List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
1196                                       Name methName) {
1197         int prevPos = make.pos;
1198         try {
1199             make.at(pos);
1200             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
1201                 syms.stringType,
1202                 syms.methodTypeType).appendList(staticArgs.map(types::constantType));
1203 
1204             MethodSymbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
1205                     bsmName, bsm_staticArgs, List.nil());
1206 
1207             DynamicMethodSymbol dynSym =
1208                     new DynamicMethodSymbol(methName,
1209                                             syms.noSymbol,
1210                                             bsm.asHandle(),
1211                                             indyType,
1212                                             staticArgs.toArray(new LoadableConstant[staticArgs.length()]));
1213             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
1214             DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
1215                     dynSym.poolKey(types), dynSym);
1216             qualifier.sym = existing != null ? existing : dynSym;
1217             qualifier.type = indyType.getReturnType();
1218 
1219             JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs);
1220             proxyCall.type = indyType.getReturnType();
1221             return proxyCall;
1222         } finally {
1223             make.at(prevPos);
1224         }
1225     }
1226 
1227     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1228     /**
1229      * This visitor collects information about translation of a lambda expression.
1230      * More specifically, it keeps track of the enclosing contexts and captured locals
1231      * accessed by the lambda being translated (as well as other useful info).
1232      * It also translates away problems for LambdaToMethod.
1233      */
1234     class LambdaAnalyzerPreprocessor extends TreeTranslator {
1235 
1236         /** the frame stack - used to reconstruct translation info about enclosing scopes */
1237         private List<Frame> frameStack;
1238 
1239         /**
1240          * keep the count of lambda expression (used to generate unambiguous
1241          * names)
1242          */
1243         private int lambdaCount = 0;
1244 
1245         /**
1246          * List of types undergoing construction via explicit constructor chaining.
1247          */
1248         private List<ClassSymbol> typesUnderConstruction;
1249 
1250         /**
1251          * keep the count of lambda expression defined in given context (used to
1252          * generate unambiguous names for serializable lambdas)
1253          */
1254         private class SyntheticMethodNameCounter {
1255             private Map<String, Integer> map = new HashMap<>();
1256             int getIndex(StringBuilder buf) {
1257                 String temp = buf.toString();
1258                 Integer count = map.get(temp);
1259                 if (count == null) {
1260                     count = 0;
1261                 }
1262                 ++count;
1263                 map.put(temp, count);
1264                 return count;
1265             }
1266         }
1267         private SyntheticMethodNameCounter syntheticMethodNameCounts =
1268                 new SyntheticMethodNameCounter();
1269 
1270         private Map<Symbol, JCClassDecl> localClassDefs;
1271 
1272         /**
1273          * maps for fake clinit symbols to be used as owners of lambda occurring in
1274          * a static var init context
1275          */
1276         private Map<ClassSymbol, Symbol> clinits = new HashMap<>();
1277 
1278         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
1279             frameStack = List.nil();
1280             typesUnderConstruction = List.nil();
1281             localClassDefs = new HashMap<>();
1282             return translate(tree);
1283         }
1284 
1285         @Override
1286         public void visitApply(JCMethodInvocation tree) {
1287             List<ClassSymbol> previousNascentTypes = typesUnderConstruction;
1288             try {
1289                 Name methName = TreeInfo.name(tree.meth);
1290                 if (methName == names._this || methName == names._super) {
1291                     typesUnderConstruction = typesUnderConstruction.prepend(currentClass());
1292                 }
1293                 super.visitApply(tree);
1294             } finally {
1295                 typesUnderConstruction = previousNascentTypes;
1296             }
1297         }
1298             // where
1299             private ClassSymbol currentClass() {
1300                 for (Frame frame : frameStack) {
1301                     if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
1302                         JCClassDecl cdef = (JCClassDecl) frame.tree;
1303                         return cdef.sym;
1304                     }
1305                 }
1306                 return null;
1307             }
1308 
1309         @Override
1310         public void visitBlock(JCBlock tree) {
1311             List<Frame> prevStack = frameStack;
1312             try {
1313                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
1314                     frameStack = frameStack.prepend(new Frame(tree));
1315                 }
1316                 super.visitBlock(tree);
1317             }
1318             finally {
1319                 frameStack = prevStack;
1320             }
1321         }
1322 
1323         @Override
1324         public void visitClassDef(JCClassDecl tree) {
1325             List<Frame> prevStack = frameStack;
1326             int prevLambdaCount = lambdaCount;
1327             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
1328                     syntheticMethodNameCounts;
1329             Map<ClassSymbol, Symbol> prevClinits = clinits;
1330             DiagnosticSource prevSource = log.currentSource();
1331             try {
1332                 log.useSource(tree.sym.sourcefile);
1333                 lambdaCount = 0;
1334                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
1335                 prevClinits = new HashMap<>();
1336                 if (tree.sym.owner.kind == MTH) {
1337                     localClassDefs.put(tree.sym, tree);
1338                 }
1339                 if (directlyEnclosingLambda() != null) {
1340                     tree.sym.owner = owner();
1341                     if (tree.sym.hasOuterInstance()) {
1342                         //if a class is defined within a lambda, the lambda must capture
1343                         //its enclosing instance (if any)
1344                         TranslationContext<?> localContext = context();
1345                         final TypeSymbol outerInstanceSymbol = tree.sym.type.getEnclosingType().tsym;
1346                         while (localContext != null && !localContext.owner.isStatic()) {
1347                             if (localContext.tree.hasTag(LAMBDA)) {
1348                                 JCTree block = capturedDecl(localContext.depth, outerInstanceSymbol);
1349                                 if (block == null) break;
1350                                 ((LambdaTranslationContext)localContext)
1351                                         .addSymbol(outerInstanceSymbol, CAPTURED_THIS);
1352                             }
1353                             localContext = localContext.prev;
1354                         }
1355                     }
1356                 }
1357                 frameStack = frameStack.prepend(new Frame(tree));
1358                 super.visitClassDef(tree);
1359             }
1360             finally {
1361                 log.useSource(prevSource.getFile());
1362                 frameStack = prevStack;
1363                 lambdaCount = prevLambdaCount;
1364                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
1365                 clinits = prevClinits;
1366             }
1367         }
1368 
1369         @Override
1370         public void visitIdent(JCIdent tree) {
1371             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
1372                 if (tree.sym.kind == VAR &&
1373                         tree.sym.owner.kind == MTH &&
1374                         tree.type.constValue() == null) {
1375                     TranslationContext<?> localContext = context();
1376                     while (localContext != null) {
1377                         if (localContext.tree.getTag() == LAMBDA) {
1378                             JCTree block = capturedDecl(localContext.depth, tree.sym);
1379                             if (block == null) break;
1380                             ((LambdaTranslationContext)localContext)
1381                                     .addSymbol(tree.sym, CAPTURED_VAR);
1382                         }
1383                         localContext = localContext.prev;
1384                     }
1385                 } else if (tree.sym.owner.kind == TYP) {
1386                     TranslationContext<?> localContext = context();
1387                     while (localContext != null  && !localContext.owner.isStatic()) {
1388                         if (localContext.tree.hasTag(LAMBDA)) {
1389                             JCTree block = capturedDecl(localContext.depth, tree.sym);
1390                             if (block == null) break;
1391                             switch (block.getTag()) {
1392                                 case CLASSDEF:
1393                                     JCClassDecl cdecl = (JCClassDecl)block;
1394                                     ((LambdaTranslationContext)localContext)
1395                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
1396                                     break;
1397                                 default:
1398                                     Assert.error("bad block kind");
1399                             }
1400                         }
1401                         localContext = localContext.prev;
1402                     }
1403                 }
1404             }
1405             super.visitIdent(tree);
1406         }
1407 
1408         @Override
1409         public void visitLambda(JCLambda tree) {
1410             analyzeLambda(tree, "lambda.stat");
1411         }
1412 
1413         private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) {
1414             // Translation of the receiver expression must occur first
1415             JCExpression rcvr = translate(methodReferenceReceiver);
1416             LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1");
1417             if (rcvr != null) {
1418                 context.methodReferenceReceiver = rcvr;
1419             }
1420         }
1421 
1422         private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) {
1423             List<Frame> prevStack = frameStack;
1424             try {
1425                 LambdaTranslationContext context = new LambdaTranslationContext(tree);
1426                 frameStack = frameStack.prepend(new Frame(tree));
1427                 for (JCVariableDecl param : tree.params) {
1428                     context.addSymbol(param.sym, PARAM);
1429                     frameStack.head.addLocal(param.sym);
1430                 }
1431                 contextMap.put(tree, context);
1432                 super.visitLambda(tree);
1433                 context.complete();
1434                 if (dumpLambdaToMethodStats) {
1435                     log.note(tree, diags.noteKey(statKey, context.needsAltMetafactory(), context.translatedSym));
1436                 }
1437                 return context;
1438             }
1439             finally {
1440                 frameStack = prevStack;
1441             }
1442         }
1443 
1444         @Override
1445         public void visitMethodDef(JCMethodDecl tree) {
1446             List<Frame> prevStack = frameStack;
1447             try {
1448                 frameStack = frameStack.prepend(new Frame(tree));
1449                 super.visitMethodDef(tree);
1450             }
1451             finally {
1452                 frameStack = prevStack;
1453             }
1454         }
1455 
1456         @Override
1457         public void visitNewClass(JCNewClass tree) {
1458             TypeSymbol def = tree.type.tsym;
1459             boolean inReferencedClass = currentlyInClass(def);
1460             boolean isLocal = def.isDirectlyOrIndirectlyLocal();
1461             if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
1462                 TranslationContext<?> localContext = context();
1463                 final TypeSymbol outerInstanceSymbol = tree.type.getEnclosingType().tsym;
1464                 while (localContext != null  && !localContext.owner.isStatic()) {
1465                     if (localContext.tree.hasTag(LAMBDA)) {
1466                         if (outerInstanceSymbol != null) {
1467                             JCTree block = capturedDecl(localContext.depth, outerInstanceSymbol);
1468                             if (block == null) break;
1469                         }
1470                         ((LambdaTranslationContext)localContext)
1471                                 .addSymbol(outerInstanceSymbol, CAPTURED_THIS);
1472                     }
1473                     localContext = localContext.prev;
1474                 }
1475             }
1476             super.visitNewClass(tree);
1477             if (context() != null && !inReferencedClass && isLocal) {
1478                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
1479                 captureLocalClassDefs(def, lambdaContext);
1480             }
1481         }
1482         //where
1483             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
1484                 JCClassDecl localCDef = localClassDefs.get(csym);
1485                 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
1486                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
1487                         @Override
1488                         void addFreeVars(ClassSymbol c) {
1489                             captureLocalClassDefs(c, lambdaContext);
1490                         }
1491                         @Override
1492                         void visitSymbol(Symbol sym) {
1493                             if (sym.kind == VAR &&
1494                                     sym.owner.kind == MTH &&
1495                                     ((VarSymbol)sym).getConstValue() == null) {
1496                                 TranslationContext<?> localContext = context();
1497                                 while (localContext != null) {
1498                                     if (localContext.tree.getTag() == LAMBDA) {
1499                                         JCTree block = capturedDecl(localContext.depth, sym);
1500                                         if (block == null) break;
1501                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
1502                                     }
1503                                     localContext = localContext.prev;
1504                                 }
1505                             }
1506                         }
1507                     };
1508                     fvc.scan(localCDef);
1509                 }
1510         }
1511         //where
1512         boolean currentlyInClass(Symbol csym) {
1513             for (Frame frame : frameStack) {
1514                 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
1515                     JCClassDecl cdef = (JCClassDecl) frame.tree;
1516                     if (cdef.sym == csym) {
1517                         return true;
1518                     }
1519                 }
1520             }
1521             return false;
1522         }
1523 
1524         /**
1525          * Method references to local class constructors, may, if the local
1526          * class references local variables, have implicit constructor
1527          * parameters added in Lower; As a result, the invokedynamic bootstrap
1528          * information added in the LambdaToMethod pass will have the wrong
1529          * signature. Hooks between Lower and LambdaToMethod have been added to
1530          * handle normal "new" in this case. This visitor converts potentially
1531          * affected method references into a lambda containing a normal
1532          * expression.
1533          *
1534          * @param tree
1535          */
1536         @Override
1537         public void visitReference(JCMemberReference tree) {
1538             ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree);
1539             contextMap.put(tree, rcontext);
1540             if (rcontext.needsConversionToLambda()) {
1541                  // Convert to a lambda, and process as such
1542                 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner());
1543                 analyzeLambda(conv.lambda(), conv.getReceiverExpression());
1544             } else {
1545                 super.visitReference(tree);
1546                 if (dumpLambdaToMethodStats) {
1547                     log.note(tree, Notes.MrefStat(rcontext.needsAltMetafactory(), null));
1548                 }
1549             }
1550         }
1551 
1552         @Override
1553         public void visitSelect(JCFieldAccess tree) {
1554             if (context() != null && tree.sym.kind == VAR &&
1555                         (tree.sym.name == names._this ||
1556                          tree.sym.name == names._super)) {
1557                 // A select of this or super means, if we are in a lambda,
1558                 // we much have an instance context
1559                 TranslationContext<?> localContext = context();
1560                 while (localContext != null  && !localContext.owner.isStatic()) {
1561                     if (localContext.tree.hasTag(LAMBDA)) {
1562                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
1563                         if (clazz == null) break;
1564                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
1565                     }
1566                     localContext = localContext.prev;
1567                 }
1568             }
1569             super.visitSelect(tree);
1570         }
1571 
1572         @Override
1573         public void visitVarDef(JCVariableDecl tree) {
1574             TranslationContext<?> context = context();
1575             if (context != null && context instanceof LambdaTranslationContext lambdaContext) {
1576                 if (frameStack.head.tree.hasTag(LAMBDA)) {
1577                     lambdaContext.addSymbol(tree.sym, LOCAL_VAR);
1578                 }
1579                 // Check for type variables (including as type arguments).
1580                 // If they occur within class nested in a lambda, mark for erasure
1581                 Type type = tree.sym.asType();
1582             }
1583 
1584             List<Frame> prevStack = frameStack;
1585             try {
1586                 if (tree.sym.owner.kind == MTH) {
1587                     frameStack.head.addLocal(tree.sym);
1588                 }
1589                 frameStack = frameStack.prepend(new Frame(tree));
1590                 super.visitVarDef(tree);
1591             }
1592             finally {
1593                 frameStack = prevStack;
1594             }
1595         }
1596 
1597         /**
1598          * Return a valid owner given the current declaration stack
1599          * (required to skip synthetic lambda symbols)
1600          */
1601         private Symbol owner() {
1602             return owner(false);
1603         }
1604 
1605         @SuppressWarnings("fallthrough")
1606         private Symbol owner(boolean skipLambda) {
1607             List<Frame> frameStack2 = frameStack;
1608             while (frameStack2.nonEmpty()) {
1609                 switch (frameStack2.head.tree.getTag()) {
1610                     case VARDEF:
1611                         if (((JCVariableDecl)frameStack2.head.tree).sym.isDirectlyOrIndirectlyLocal()) {
1612                             frameStack2 = frameStack2.tail;
1613                             break;
1614                         }
1615                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
1616                         return initSym(cdecl.sym,
1617                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
1618                     case BLOCK:
1619                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
1620                         return initSym(cdecl2.sym,
1621                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
1622                     case CLASSDEF:
1623                         return ((JCClassDecl)frameStack2.head.tree).sym;
1624                     case METHODDEF:
1625                         return ((JCMethodDecl)frameStack2.head.tree).sym;
1626                     case LAMBDA:
1627                         if (!skipLambda)
1628                             return ((LambdaTranslationContext)contextMap
1629                                     .get(frameStack2.head.tree)).translatedSym;
1630                     default:
1631                         frameStack2 = frameStack2.tail;
1632                 }
1633             }
1634             Assert.error();
1635             return null;
1636         }
1637 
1638         private Symbol initSym(ClassSymbol csym, long flags) {
1639             boolean isStatic = (flags & STATIC) != 0;
1640             if (isStatic) {
1641                 /* static clinits are generated in Gen, so we need to use a fake
1642                  * one. Attr creates a fake clinit method while attributing
1643                  * lambda expressions used as initializers of static fields, so
1644                  * let's use that one.
1645                  */
1646                 MethodSymbol clinit = attr.removeClinit(csym);
1647                 if (clinit != null) {
1648                     clinits.put(csym, clinit);
1649                     return clinit;
1650                 }
1651 
1652                 /* if no clinit is found at Attr, then let's try at clinits.
1653                  */
1654                 clinit = (MethodSymbol)clinits.get(csym);
1655                 if (clinit == null) {
1656                     /* no luck, let's create a new one
1657                      */
1658                     clinit = makePrivateSyntheticMethod(STATIC,
1659                             names.clinit,
1660                             new MethodType(List.nil(), syms.voidType,
1661                                 List.nil(), syms.methodClass),
1662                             csym);
1663                     clinits.put(csym, clinit);
1664                 }
1665                 return clinit;
1666             } else {
1667                 //get the first constructor and treat it as the instance init sym
1668                 Name constructorName = csym.isConcreteValueClass() ? names.vnew : names.init;
1669                 for (Symbol s : csym.members_field.getSymbolsByName(constructorName)) {
1670                     return s;
1671                 }
1672             }
1673             Assert.error("init not found");
1674             return null;
1675         }
1676 
1677         private JCTree directlyEnclosingLambda() {
1678             if (frameStack.isEmpty()) {
1679                 return null;
1680             }
1681             List<Frame> frameStack2 = frameStack;
1682             while (frameStack2.nonEmpty()) {
1683                 switch (frameStack2.head.tree.getTag()) {
1684                     case CLASSDEF:
1685                     case METHODDEF:
1686                         return null;
1687                     case LAMBDA:
1688                         return frameStack2.head.tree;
1689                     default:
1690                         frameStack2 = frameStack2.tail;
1691                 }
1692             }
1693             Assert.error();
1694             return null;
1695         }
1696 
1697         private boolean inClassWithinLambda() {
1698             if (frameStack.isEmpty()) {
1699                 return false;
1700             }
1701             List<Frame> frameStack2 = frameStack;
1702             boolean classFound = false;
1703             while (frameStack2.nonEmpty()) {
1704                 switch (frameStack2.head.tree.getTag()) {
1705                     case LAMBDA:
1706                         return classFound;
1707                     case CLASSDEF:
1708                         classFound = true;
1709                         frameStack2 = frameStack2.tail;
1710                         break;
1711                     default:
1712                         frameStack2 = frameStack2.tail;
1713                 }
1714             }
1715             // No lambda
1716             return false;
1717         }
1718 
1719         /**
1720          * Return the declaration corresponding to a symbol in the enclosing
1721          * scope; the depth parameter is used to filter out symbols defined
1722          * in nested scopes (which do not need to undergo capture).
1723          */
1724         private JCTree capturedDecl(int depth, Symbol sym) {
1725             int currentDepth = frameStack.size() - 1;
1726             for (Frame block : frameStack) {
1727                 switch (block.tree.getTag()) {
1728                     case CLASSDEF:
1729                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
1730                         if (clazz.isSubClass(sym, types) || sym.isMemberOf(clazz, types)) {
1731                             return currentDepth > depth ? null : block.tree;
1732                         }
1733                         break;
1734                     case VARDEF:
1735                         if ((((JCVariableDecl)block.tree).sym == sym &&
1736                                 sym.owner.kind == MTH) || //only locals are captured
1737                             (block.locals != null && block.locals.contains(sym))) {
1738                             return currentDepth > depth ? null : block.tree;
1739                         }
1740                         break;
1741                     case BLOCK:
1742                     case METHODDEF:
1743                     case LAMBDA:
1744                         if (block.locals != null && block.locals.contains(sym)) {
1745                             return currentDepth > depth ? null : block.tree;
1746                         }
1747                         break;
1748                     default:
1749                         Assert.error("bad decl kind " + block.tree.getTag());
1750                 }
1751                 currentDepth--;
1752             }
1753             return null;
1754         }
1755 
1756         private TranslationContext<?> context() {
1757             for (Frame frame : frameStack) {
1758                 TranslationContext<?> context = contextMap.get(frame.tree);
1759                 if (context != null) {
1760                     return context;
1761                 }
1762             }
1763             return null;
1764         }
1765 
1766         /**
1767          *  This is used to filter out those identifiers that needs to be adjusted
1768          *  when translating away lambda expressions
1769          */
1770         private boolean lambdaIdentSymbolFilter(Symbol sym) {
1771             return (sym.kind == VAR || sym.kind == MTH)
1772                     && !sym.isStatic()
1773                     && !names.isInitOrVNew(sym.name);
1774         }
1775 
1776         /**
1777          *  This is used to filter out those select nodes that need to be adjusted
1778          *  when translating away lambda expressions - at the moment, this is the
1779          *  set of nodes that select `this' (qualified this)
1780          */
1781         private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) {
1782             return (context instanceof LambdaTranslationContext lambdaContext)
1783                     && !fAccess.sym.isStatic()
1784                     && fAccess.name == names._this
1785                     && (fAccess.sym.owner.kind == TYP)
1786                     && !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty();
1787         }
1788 
1789         /**
1790          * This is used to filter out those new class expressions that need to
1791          * be qualified with an enclosing tree
1792          */
1793         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
1794             if (context != null
1795                     && tree.encl == null
1796                     && tree.def == null
1797                     && !tree.type.getEnclosingType().hasTag(NONE)) {
1798                 Type encl = tree.type.getEnclosingType();
1799                 Type current = context.owner.enclClass().type;
1800                 while (!current.hasTag(NONE)) {
1801                     if (current.tsym.isSubClass(encl.tsym, types)) {
1802                         return true;
1803                     }
1804                     current = current.getEnclosingType();
1805                 }
1806                 return false;
1807             } else {
1808                 return false;
1809             }
1810         }
1811 
1812         private class Frame {
1813             final JCTree tree;
1814             List<Symbol> locals;
1815 
1816             public Frame(JCTree tree) {
1817                 this.tree = tree;
1818             }
1819 
1820             void addLocal(Symbol sym) {
1821                 if (locals == null) {
1822                     locals = List.nil();
1823                 }
1824                 locals = locals.prepend(sym);
1825             }
1826         }
1827 
1828         /**
1829          * This class is used to store important information regarding translation of
1830          * lambda expression/method references (see subclasses).
1831          */
1832         abstract class TranslationContext<T extends JCFunctionalExpression> {
1833 
1834             /** the underlying (untranslated) tree */
1835             final T tree;
1836 
1837             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
1838             final Symbol owner;
1839 
1840             /** the depth of this lambda expression in the frame stack */
1841             final int depth;
1842 
1843             /** the enclosing translation context (set for nested lambdas/mref) */
1844             final TranslationContext<?> prev;
1845 
1846             /** list of methods to be bridged by the meta-factory */
1847             final List<Symbol> bridges;
1848 
1849             TranslationContext(T tree) {
1850                 this.tree = tree;
1851                 this.owner = owner(true);
1852                 this.depth = frameStack.size() - 1;
1853                 this.prev = context();
1854                 ClassSymbol csym =
1855                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
1856                 this.bridges = types.functionalInterfaceBridges(csym);
1857             }
1858 
1859             /** does this functional expression need to be created using alternate metafactory? */
1860             boolean needsAltMetafactory() {
1861                 return tree.target.isIntersection() ||
1862                         isSerializable() ||
1863                         bridges.length() > 1;
1864             }
1865 
1866             /** does this functional expression require serialization support? */
1867             boolean isSerializable() {
1868                 if (forceSerializable) {
1869                     return true;
1870                 }
1871                 return types.asSuper(tree.target.referenceProjectionOrSelf(), syms.serializableType.tsym) != null;
1872             }
1873 
1874             /**
1875              * @return Name of the enclosing method to be folded into synthetic
1876              * method name
1877              */
1878             String enclosingMethodName() {
1879                 return syntheticMethodNameComponent(owner.name);
1880             }
1881 
1882             /**
1883              * @return Method name in a form that can be folded into a
1884              * component of a synthetic method name
1885              */
1886             String syntheticMethodNameComponent(Name name) {
1887                 if (name == null) {
1888                     return "null";
1889                 }
1890                 String methodName = name.toString();
1891                 if (methodName.equals("<clinit>")) {
1892                     methodName = "static";
1893                 } else if (methodName.equals("<init>")) {
1894                     methodName = "new";
1895                 } else if (methodName.equals("<vnew>")) {
1896                     methodName = "vnew";
1897                 }
1898                 return methodName;
1899             }
1900         }
1901 
1902         /**
1903          * This class retains all the useful information about a lambda expression;
1904          * the contents of this class are filled by the LambdaAnalyzer visitor,
1905          * and the used by the main translation routines in order to adjust references
1906          * to captured locals/members, etc.
1907          */
1908         class LambdaTranslationContext extends TranslationContext<JCLambda> {
1909 
1910             /** variable in the enclosing context to which this lambda is assigned */
1911             final Symbol self;
1912 
1913             /** variable in the enclosing context to which this lambda is assigned */
1914             final Symbol assignedTo;
1915 
1916             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
1917 
1918             /** the synthetic symbol for the method hoisting the translated lambda */
1919             MethodSymbol translatedSym;
1920 
1921             List<JCVariableDecl> syntheticParams;
1922 
1923             /**
1924              * to prevent recursion, track local classes processed
1925              */
1926             final Set<Symbol> freeVarProcessedLocalClasses;
1927 
1928             /**
1929              * For method references converted to lambdas.  The method
1930              * reference receiver expression. Must be treated like a captured
1931              * variable.
1932              */
1933             JCExpression methodReferenceReceiver;
1934 
1935             LambdaTranslationContext(JCLambda tree) {
1936                 super(tree);
1937                 Frame frame = frameStack.head;
1938                 switch (frame.tree.getTag()) {
1939                     case VARDEF:
1940                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
1941                         break;
1942                     case ASSIGN:
1943                         self = null;
1944                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
1945                         break;
1946                     default:
1947                         assignedTo = self = null;
1948                         break;
1949                  }
1950 
1951                 // This symbol will be filled-in in complete
1952                 if (owner.kind == MTH) {
1953                     final MethodSymbol originalOwner = (MethodSymbol)owner.clone(owner.owner);
1954                     this.translatedSym = new MethodSymbol(SYNTHETIC | PRIVATE, null, null, owner.enclClass()) {
1955                         @Override
1956                         public MethodSymbol originalEnclosingMethod() {
1957                             return originalOwner;
1958                         }
1959                     };
1960                 } else {
1961                     this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
1962                 }
1963                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
1964 
1965                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
1966                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
1967                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
1968                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
1969                 translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>());
1970 
1971                 freeVarProcessedLocalClasses = new HashSet<>();
1972             }
1973 
1974              /**
1975              * For a serializable lambda, generate a disambiguating string
1976              * which maximizes stability across deserialization.
1977              *
1978              * @return String to differentiate synthetic lambda method names
1979              */
1980             private String serializedLambdaDisambiguation() {
1981                 StringBuilder buf = new StringBuilder();
1982                 // Append the enclosing method signature to differentiate
1983                 // overloaded enclosing methods.  For lambdas enclosed in
1984                 // lambdas, the generated lambda method will not have type yet,
1985                 // but the enclosing method's name will have been generated
1986                 // with this same method, so it will be unique and never be
1987                 // overloaded.
1988                 Assert.check(
1989                         owner.type != null ||
1990                         directlyEnclosingLambda() != null);
1991                 if (owner.type != null) {
1992                     buf.append(typeSig(owner.type, true));
1993                     buf.append(":");
1994                 }
1995 
1996                 // Add target type info
1997                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
1998                 buf.append(" ");
1999 
2000                 // Add variable assigned to
2001                 if (assignedTo != null) {
2002                     buf.append(assignedTo.flatName());
2003                     buf.append("=");
2004                 }
2005                 //add captured locals info: type, name, order
2006                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
2007                     if (fv != self) {
2008                         buf.append(typeSig(fv.type, true));
2009                         buf.append(" ");
2010                         buf.append(fv.flatName());
2011                         buf.append(",");
2012                     }
2013                 }
2014 
2015                 return buf.toString();
2016             }
2017 
2018             /**
2019              * For a non-serializable lambda, generate a simple method.
2020              *
2021              * @return Name to use for the synthetic lambda method name
2022              */
2023             private Name lambdaName() {
2024                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
2025             }
2026 
2027             /**
2028              * For a serializable lambda, generate a method name which maximizes
2029              * name stability across deserialization.
2030              *
2031              * @return Name to use for the synthetic lambda method name
2032              */
2033             private Name serializedLambdaName() {
2034                 StringBuilder buf = new StringBuilder();
2035                 buf.append(names.lambda);
2036                 // Append the name of the method enclosing the lambda.
2037                 buf.append(enclosingMethodName());
2038                 buf.append('$');
2039                 // Append a hash of the disambiguating string : enclosing method
2040                 // signature, etc.
2041                 String disam = serializedLambdaDisambiguation();
2042                 buf.append(Integer.toHexString(disam.hashCode()));
2043                 buf.append('$');
2044                 // The above appended name components may not be unique, append
2045                 // a count based on the above name components.
2046                 buf.append(syntheticMethodNameCounts.getIndex(buf));
2047                 String result = buf.toString();
2048                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
2049                 return names.fromString(result);
2050             }
2051 
2052             /**
2053              * Translate a symbol of a given kind into something suitable for the
2054              * synthetic lambda body
2055              */
2056             Symbol translate(final Symbol sym, LambdaSymbolKind skind) {
2057                 Symbol ret;
2058                 switch (skind) {
2059                     case CAPTURED_THIS:
2060                         ret = sym;  // self represented
2061                         break;
2062                     case CAPTURED_VAR:
2063                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
2064                             @Override
2065                             public Symbol baseSymbol() {
2066                                 //keep mapping with original captured symbol
2067                                 return sym;
2068                             }
2069                         };
2070                         break;
2071                     case CAPTURED_OUTER_THIS:
2072                         Name name = names.fromString(sym.flatName().toString().replace('.', '$') + names.dollarThis);
2073                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
2074                             @Override
2075                             public Symbol baseSymbol() {
2076                                 //keep mapping with original captured symbol
2077                                 return sym;
2078                             }
2079                         };
2080                         break;
2081                     case LOCAL_VAR:
2082                         ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym) {
2083                             @Override
2084                             public Symbol baseSymbol() {
2085                                 //keep mapping with original symbol
2086                                 return sym;
2087                             }
2088                         };
2089                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
2090                         // If sym.data == ElementKind.EXCEPTION_PARAMETER,
2091                         // set ret.data = ElementKind.EXCEPTION_PARAMETER too.
2092                         // Because method com.sun.tools.javac.jvm.Code.fillExceptionParameterPositions and
2093                         // com.sun.tools.javac.jvm.Code.fillLocalVarPosition would use it.
2094                         // See JDK-8257740 for more information.
2095                         if (((VarSymbol) sym).isExceptionParameter()) {
2096                             ((VarSymbol) ret).setData(ElementKind.EXCEPTION_PARAMETER);
2097                         }
2098                         break;
2099                     case PARAM:
2100                         ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym);
2101                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
2102                         // Set ret.data. Same as case LOCAL_VAR above.
2103                         if (((VarSymbol) sym).isExceptionParameter()) {
2104                             ((VarSymbol) ret).setData(ElementKind.EXCEPTION_PARAMETER);
2105                         }
2106                         break;
2107                     default:
2108                         Assert.error(skind.name());
2109                         throw new AssertionError();
2110                 }
2111                 if (ret != sym && skind.propagateAnnotations()) {
2112                     ret.setDeclarationAttributes(sym.getRawAttributes());
2113                     ret.setTypeAttributes(sym.getRawTypeAttributes());
2114                 }
2115                 return ret;
2116             }
2117 
2118             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
2119                 if (skind == CAPTURED_THIS && sym != null && sym.kind == TYP && !typesUnderConstruction.isEmpty()) {
2120                     ClassSymbol currentClass = currentClass();
2121                     if (currentClass != null && typesUnderConstruction.contains(currentClass)) {
2122                         // reference must be to enclosing outer instance, mutate capture kind.
2123                         Assert.check(sym != currentClass); // should have been caught right in Attr
2124                         skind = CAPTURED_OUTER_THIS;
2125                     }
2126                 }
2127                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
2128                 if (!transMap.containsKey(sym)) {
2129                     transMap.put(sym, translate(sym, skind));
2130                 }
2131             }
2132 
2133             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
2134                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
2135                 Assert.checkNonNull(m);
2136                 return m;
2137             }
2138 
2139             JCTree translate(JCIdent lambdaIdent) {
2140                 for (LambdaSymbolKind kind : LambdaSymbolKind.values()) {
2141                     Map<Symbol, Symbol> m = getSymbolMap(kind);
2142                     switch(kind) {
2143                         default:
2144                             if (m.containsKey(lambdaIdent.sym)) {
2145                                 Symbol tSym = m.get(lambdaIdent.sym);
2146                                 JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
2147                                 return t;
2148                             }
2149                             break;
2150                         case CAPTURED_OUTER_THIS:
2151                             Optional<Symbol> proxy = m.keySet().stream()
2152                                     .filter(out -> lambdaIdent.sym.isMemberOf(out.type.tsym, types))
2153                                     .reduce((a, b) -> a.isEnclosedBy((ClassSymbol)b) ? a : b);
2154                             if (proxy.isPresent()) {
2155                                 // Transform outer instance variable references anchoring them to the captured synthetic.
2156                                 Symbol tSym = m.get(proxy.get());
2157                                 JCExpression t = make.Ident(tSym).setType(lambdaIdent.sym.owner.type);
2158                                 t = make.Select(t, lambdaIdent.name);
2159                                 t.setType(lambdaIdent.type);
2160                                 TreeInfo.setSymbol(t, lambdaIdent.sym);
2161                                 return t;
2162                             }
2163                             break;
2164                     }
2165                 }
2166                 return null;
2167             }
2168 
2169             /* Translate away qualified this expressions, anchoring them to synthetic parameters that
2170                capture the qualified this handle. `fieldAccess' is guaranteed to one such.
2171             */
2172             public JCTree translate(JCFieldAccess fieldAccess) {
2173                 Assert.check(fieldAccess.name == names._this);
2174                 Map<Symbol, Symbol> m = translatedSymbols.get(LambdaSymbolKind.CAPTURED_OUTER_THIS);
2175                 if (m.containsKey(fieldAccess.sym.owner)) {
2176                     Symbol tSym = m.get(fieldAccess.sym.owner);
2177                     JCExpression t = make.Ident(tSym).setType(fieldAccess.sym.owner.type);
2178                     return t;
2179                 }
2180                 return null;
2181             }
2182 
2183             /* Translate away naked new instance creation expressions with implicit enclosing instances,
2184                anchoring them to synthetic parameters that stand proxy for the qualified outer this handle.
2185             */
2186             public JCNewClass translate(JCNewClass newClass) {
2187                 Assert.check(newClass.clazz.type.tsym.hasOuterInstance() && newClass.encl == null);
2188                 Map<Symbol, Symbol> m = translatedSymbols.get(LambdaSymbolKind.CAPTURED_OUTER_THIS);
2189                 final Type enclosingType = newClass.clazz.type.getEnclosingType();
2190                 if (m.containsKey(enclosingType.tsym)) {
2191                       Symbol tSym = m.get(enclosingType.tsym);
2192                       JCExpression encl = make.Ident(tSym).setType(enclosingType);
2193                       newClass.encl = encl;
2194                 }
2195                 return newClass;
2196             }
2197 
2198             /**
2199              * The translatedSym is not complete/accurate until the analysis is
2200              * finished.  Once the analysis is finished, the translatedSym is
2201              * "completed" -- updated with type information, access modifiers,
2202              * and full parameter list.
2203              */
2204             void complete() {
2205                 if (syntheticParams != null) {
2206                     return;
2207                 }
2208                 boolean inInterface = translatedSym.owner.isInterface();
2209                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
2210 
2211                 // If instance access isn't needed, make it static.
2212                 // Interface instance methods must be default methods.
2213                 // Lambda methods are private synthetic.
2214                 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
2215                 // from the class.
2216                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
2217                         owner.flags_field & STRICTFP |
2218                         owner.owner.flags_field & STRICTFP |
2219                         PRIVATE |
2220                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
2221 
2222                 //compute synthetic params
2223                 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
2224                 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>();
2225 
2226                 // The signature of the method is augmented with the following
2227                 // synthetic parameters:
2228                 //
2229                 // 1) reference to enclosing contexts captured by the lambda expression
2230                 // 2) enclosing locals captured by the lambda expression
2231                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
2232                     params.append(make.VarDef((VarSymbol) thisSym, null));
2233                     parameterSymbols.append((VarSymbol) thisSym);
2234                 }
2235                 for (Symbol thisSym : getSymbolMap(CAPTURED_OUTER_THIS).values()) {
2236                     params.append(make.VarDef((VarSymbol) thisSym, null));
2237                     parameterSymbols.append((VarSymbol) thisSym);
2238                 }
2239                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
2240                     params.append(make.VarDef((VarSymbol) thisSym, null));
2241                     parameterSymbols.append((VarSymbol) thisSym);
2242                 }
2243                 syntheticParams = params.toList();
2244 
2245                 translatedSym.params = parameterSymbols.toList();
2246 
2247                 // Compute and set the lambda name
2248                 translatedSym.name = isSerializable()
2249                         ? serializedLambdaName()
2250                         : lambdaName();
2251 
2252                 //prepend synthetic args to translated lambda method signature
2253                 translatedSym.type = types.createMethodTypeWithParameters(
2254                         generatedLambdaSig(),
2255                         TreeInfo.types(syntheticParams));
2256             }
2257 
2258             Type generatedLambdaSig() {
2259                 return types.erasure(tree.getDescriptorType(types));
2260             }
2261         }
2262 
2263         /**
2264          * This class retains all the useful information about a method reference;
2265          * the contents of this class are filled by the LambdaAnalyzer visitor,
2266          * and the used by the main translation routines in order to adjust method
2267          * references (i.e. in case a bridge is needed)
2268          */
2269         final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
2270 
2271             final boolean isSuper;
2272 
2273             ReferenceTranslationContext(JCMemberReference tree) {
2274                 super(tree);
2275                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
2276             }
2277 
2278             boolean needsVarArgsConversion() {
2279                 return tree.varargsElement != null;
2280             }
2281 
2282             /**
2283              * @return Is this an array operation like clone()
2284              */
2285             boolean isArrayOp() {
2286                 return tree.sym.owner == syms.arrayClass;
2287             }
2288 
2289             boolean receiverAccessible() {
2290                 //hack needed to workaround 292 bug (7087658)
2291                 //when 292 issue is fixed we should remove this and change the backend
2292                 //code to always generate a method handle to an accessible method
2293                 return tree.ownerAccessible;
2294             }
2295 
2296             /**
2297              * This method should be called only when target release <= 14
2298              * where LambdaMetaFactory does not spin nestmate classes.
2299              *
2300              * This method should be removed when --release 14 is not supported.
2301              */
2302             boolean isPrivateInOtherClass() {
2303                 assert !nestmateLambdas;
2304                 return  (tree.sym.flags() & PRIVATE) != 0 &&
2305                         !types.isSameType(
2306                               types.erasure(tree.sym.enclClass().asType()),
2307                               types.erasure(owner.enclClass().asType()));
2308             }
2309 
2310             /**
2311              * Erasure destroys the implementation parameter subtype
2312              * relationship for intersection types.
2313              * Have similar problems for union types too.
2314              */
2315             boolean interfaceParameterIsIntersectionOrUnionType() {
2316                 List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
2317                 for (; tl.nonEmpty(); tl = tl.tail) {
2318                     Type pt = tl.head;
2319                     if (isIntersectionOrUnionType(pt))
2320                         return true;
2321                 }
2322                 return false;
2323             }
2324 
2325             boolean isIntersectionOrUnionType(Type t) {
2326                 switch (t.getKind()) {
2327                     case INTERSECTION:
2328                     case UNION:
2329                         return true;
2330                     case TYPEVAR:
2331                         TypeVar tv = (TypeVar) t;
2332                         return isIntersectionOrUnionType(tv.getUpperBound());
2333                 }
2334                 return false;
2335             }
2336 
2337             /**
2338              * Does this reference need to be converted to a lambda
2339              * (i.e. var args need to be expanded or "super" is used)
2340              */
2341             final boolean needsConversionToLambda() {
2342                 return interfaceParameterIsIntersectionOrUnionType() ||
2343                         isSuper ||
2344                         needsVarArgsConversion() ||
2345                         isArrayOp() ||
2346                         (!nestmateLambdas && isPrivateInOtherClass()) ||
2347                         isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, owner) ||
2348                         !receiverAccessible() ||
2349                         (tree.getMode() == ReferenceMode.NEW &&
2350                           tree.kind != ReferenceKind.ARRAY_CTOR &&
2351                           (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner() || tree.sym.owner.isValueClass()));
2352             }
2353 
2354             Type generatedRefSig() {
2355                 return types.erasure(tree.sym.type);
2356             }
2357 
2358             Type bridgedRefSig() {
2359                 return types.erasure(types.findDescriptorSymbol(tree.target.tsym).type);
2360             }
2361         }
2362     }
2363     // </editor-fold>
2364 
2365     /*
2366      * These keys provide mappings for various translated lambda symbols
2367      * and the prevailing order must be maintained.
2368      */
2369     enum LambdaSymbolKind {
2370         PARAM,          // original to translated lambda parameters
2371         LOCAL_VAR,      // original to translated lambda locals
2372         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
2373         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
2374         CAPTURED_OUTER_THIS; // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)
2375 
2376         boolean propagateAnnotations() {
2377             switch (this) {
2378                 case CAPTURED_VAR:
2379                 case CAPTURED_THIS:
2380                 case CAPTURED_OUTER_THIS:
2381                     return false;
2382                 default:
2383                     return true;
2384            }
2385         }
2386     }
2387 
2388     /**
2389      * ****************************************************************
2390      * Signature Generation
2391      * ****************************************************************
2392      */
2393 
2394     private String typeSig(Type type) {
2395         return typeSig(type, false);
2396     }
2397 
2398     private String typeSig(Type type, boolean allowIllegalSignature) {
2399         try {
2400             L2MSignatureGenerator sg = new L2MSignatureGenerator(allowIllegalSignature);
2401             sg.assembleSig(type);
2402             return sg.toString();
2403         } catch (InvalidSignatureException ex) {
2404             Symbol c = attrEnv.enclClass.sym;
2405             log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
2406             return "<ERRONEOUS>";
2407         }
2408     }
2409 
2410     private String classSig(Type type) {
2411         try {
2412             L2MSignatureGenerator sg = new L2MSignatureGenerator(false);
2413             sg.assembleClassSig(type);
2414             return sg.toString();
2415         } catch (InvalidSignatureException ex) {
2416             Symbol c = attrEnv.enclClass.sym;
2417             log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
2418             return "<ERRONEOUS>";
2419         }
2420     }
2421 
2422     private boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage(Symbol targetReference,
2423                                                                           Symbol currentClass) {
2424         return ((targetReference.flags() & PROTECTED) != 0 &&
2425                 targetReference.packge() != currentClass.packge());
2426     }
2427 
2428     /**
2429      * Signature Generation
2430      */
2431     private class L2MSignatureGenerator extends Types.SignatureGenerator {
2432 
2433         /**
2434          * An output buffer for type signatures.
2435          */
2436         StringBuilder sb = new StringBuilder();
2437 
2438         /**
2439          * Are signatures incompatible with JVM spec allowed?
2440          * Used by {@link LambdaTranslationContext#serializedLambdaDisambiguation()}.
2441          */
2442         boolean allowIllegalSignatures;
2443 
2444         L2MSignatureGenerator(boolean allowIllegalSignatures) {
2445             super(types);
2446             this.allowIllegalSignatures = allowIllegalSignatures;
2447         }
2448 
2449         @Override
2450         protected void reportIllegalSignature(Type t) {
2451             if (!allowIllegalSignatures) {
2452                 super.reportIllegalSignature(t);
2453             }
2454         }
2455 
2456         @Override
2457         protected void append(char ch) {
2458             sb.append(ch);
2459         }
2460 
2461         @Override
2462         protected void append(byte[] ba) {
2463             Name name = names.fromUtf(ba);
2464             sb.append(name.toString());
2465         }
2466 
2467         @Override
2468         protected void append(Name name) {
2469             sb.append(name.toString());
2470         }
2471 
2472         @Override
2473         public String toString() {
2474             return sb.toString();
2475         }
2476     }
2477 }