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