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