src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java

Thu, 26 Mar 2015 11:34:50 +0100

author
jlahoda
date
Thu, 26 Mar 2015 11:34:50 +0100
changeset 2734
ba758e1ffa69
parent 2733
7974f6da2d76
child 2893
ca5783d9a597
child 2905
f166261986cc
child 3113
0d7fcabf56ed
permissions
-rw-r--r--

8054220: Debugger doesn't show variables *outside* lambda
8058227: Debugger has no access to outer variables inside Lambda
Summary: Put local variables captured by lambda into the lambda method's LocalVariableTable.
Reviewed-by: mcimadamore, rfield

     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;
    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;
    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;
    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;
    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 {
    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;
    89     /** the analyzer scanner */
    90     private LambdaAnalyzerPreprocessor analyzer;
    92     /** map from lambda trees to translation contexts */
    93     private Map<JCTree, TranslationContext<?>> contextMap;
    95     /** current translation context (visitor argument) */
    96     private TranslationContext<?> context;
    98     /** info about the current class being processed */
    99     private KlassInfo kInfo;
   101     /** dump statistics about lambda code generation */
   102     private boolean dumpLambdaToMethodStats;
   104     /** force serializable representation, for stress testing **/
   105     private final boolean forceSerializable;
   107     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
   108     public static final int FLAG_SERIALIZABLE = 1 << 0;
   110     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
   111     public static final int FLAG_MARKERS = 1 << 1;
   113     /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
   114     public static final int FLAG_BRIDGES = 1 << 2;
   116     // <editor-fold defaultstate="collapsed" desc="Instantiating">
   117     protected static final Context.Key<LambdaToMethod> unlambdaKey =
   118             new Context.Key<LambdaToMethod>();
   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>
   146     private class KlassInfo {
   148         /**
   149          * list of methods to append
   150          */
   151         private ListBuffer<JCTree> appendedMethodList;
   153         /**
   154          * list of deserialization cases
   155          */
   156         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   158        /**
   159          * deserialize method symbol
   160          */
   161         private final MethodSymbol deserMethodSym;
   163         /**
   164          * deserialize method parameter symbol
   165          */
   166         private final VarSymbol deserParamSym;
   168         private final JCClassDecl clazz;
   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         }
   181         private void addMethod(JCTree decl) {
   182             appendedMethodList = appendedMethodList.prepend(decl);
   183         }
   184     }
   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     }
   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     }
   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     }
   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>
   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     }
   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;
   271         {
   272             Symbol owner = localContext.owner;
   273             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   274             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   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         }
   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;
   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));
   310         //Add the method to the list of methods to be added to this class.
   311         kInfo.addMethod(lambdaDecl);
   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
   324         ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
   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         }
   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         }
   342         //then, determine the arguments to the indy call
   343         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   345         //build a sam instance using an indy call to the meta-factory
   346         int refKind = referenceKind(sym);
   348         //convert to an invokedynamic call
   349         result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
   350     }
   352     private JCIdent makeThis(Type type, Symbol owner) {
   353         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
   354                 names._this,
   355                 type,
   356                 owner);
   357         return make.Ident(_this);
   358     }
   360     /**
   361      * Translate a method reference into an invokedynamic call to the
   362      * meta-factory.
   363      * @param tree
   364      */
   365     @Override
   366     public void visitReference(JCMemberReference tree) {
   367         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   369         //first determine the method symbol to be used to generate the sam instance
   370         //this is either the method reference symbol, or the bridged reference symbol
   371         Symbol refSym = localContext.isSignaturePolymorphic()
   372                 ? localContext.sigPolySym
   373                 : tree.sym;
   375         //the qualifying expression is treated as a special captured arg
   376         JCExpression init;
   377         switch(tree.kind) {
   379             case IMPLICIT_INNER:    /** Inner :: new */
   380             case SUPER:             /** super :: instMethod */
   381                 init = makeThis(
   382                     localContext.owner.enclClass().asType(),
   383                     localContext.owner.enclClass());
   384                 break;
   386             case BOUND:             /** Expr :: instMethod */
   387                 init = tree.getQualifierExpression();
   388                 init = attr.makeNullCheck(init);
   389                 break;
   391             case UNBOUND:           /** Type :: instMethod */
   392             case STATIC:            /** Type :: staticMethod */
   393             case TOPLEVEL:          /** Top level :: new */
   394             case ARRAY_CTOR:        /** ArrayType :: new */
   395                 init = null;
   396                 break;
   398             default:
   399                 throw new InternalError("Should not have an invalid kind");
   400         }
   402         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
   405         //build a sam instance using an indy call to the meta-factory
   406         result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
   407     }
   409     /**
   410      * Translate identifiers within a lambda to the mapped identifier
   411      * @param tree
   412      */
   413     @Override
   414     public void visitIdent(JCIdent tree) {
   415         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
   416             super.visitIdent(tree);
   417         } else {
   418             int prevPos = make.pos;
   419             try {
   420                 make.at(tree);
   422                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
   423                 JCTree ltree = lambdaContext.translate(tree);
   424                 if (ltree != null) {
   425                     result = ltree;
   426                 } else {
   427                     //access to untranslated symbols (i.e. compile-time constants,
   428                     //members defined inside the lambda body, etc.) )
   429                     super.visitIdent(tree);
   430                 }
   431             } finally {
   432                 make.at(prevPos);
   433             }
   434         }
   435     }
   437     @Override
   438     public void visitVarDef(JCVariableDecl tree) {
   439         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
   440         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   441             tree.init = translate(tree.init);
   442             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
   443             result = tree;
   444         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   445             JCExpression init = translate(tree.init);
   446             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   447             int prevPos = make.pos;
   448             try {
   449                 result = make.at(tree).VarDef(xsym, init);
   450             } finally {
   451                 make.at(prevPos);
   452             }
   453             // Replace the entered symbol for this variable
   454             Scope sc = tree.sym.owner.members();
   455             if (sc != null) {
   456                 sc.remove(tree.sym);
   457                 sc.enter(xsym);
   458             }
   459         } else {
   460             super.visitVarDef(tree);
   461         }
   462     }
   464     // </editor-fold>
   466     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   468     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   469         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   470                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   471                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   472     }
   474     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   475         Type restype = lambdaMethodDecl.type.getReturnType();
   476         boolean isLambda_void = expr.type.hasTag(VOID);
   477         boolean isTarget_void = restype.hasTag(VOID);
   478         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   479         int prevPos = make.pos;
   480         try {
   481             if (isTarget_void) {
   482                 //target is void:
   483                 // BODY;
   484                 JCStatement stat = make.at(expr).Exec(expr);
   485                 return make.Block(0, List.<JCStatement>of(stat));
   486             } else if (isLambda_void && isTarget_Void) {
   487                 //void to Void conversion:
   488                 // BODY; return null;
   489                 ListBuffer<JCStatement> stats = new ListBuffer<>();
   490                 stats.append(make.at(expr).Exec(expr));
   491                 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   492                 return make.Block(0, stats.toList());
   493             } else {
   494                 //non-void to non-void conversion:
   495                 // return (TYPE)BODY;
   496                 JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   497                 return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
   498             }
   499         } finally {
   500             make.at(prevPos);
   501         }
   502     }
   504     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   505         final Type restype = lambdaMethodDecl.type.getReturnType();
   506         final boolean isTarget_void = restype.hasTag(VOID);
   507         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   509         class LambdaBodyTranslator extends TreeTranslator {
   511             @Override
   512             public void visitClassDef(JCClassDecl tree) {
   513                 //do NOT recurse on any inner classes
   514                 result = tree;
   515             }
   517             @Override
   518             public void visitLambda(JCLambda tree) {
   519                 //do NOT recurse on any nested lambdas
   520                 result = tree;
   521             }
   523             @Override
   524             public void visitReturn(JCReturn tree) {
   525                 boolean isLambda_void = tree.expr == null;
   526                 if (isTarget_void && !isLambda_void) {
   527                     //Void to void conversion:
   528                     // { TYPE $loc = RET-EXPR; return; }
   529                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   530                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   531                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   532                 } else if (!isTarget_void || !isLambda_void) {
   533                     //non-void to non-void conversion:
   534                     // return (TYPE)RET-EXPR;
   535                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   536                     result = tree;
   537                 } else {
   538                     result = tree;
   539                 }
   541             }
   542         }
   544         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   545         if (completeNormally && isTarget_Void) {
   546             //there's no return statement and the lambda (possibly inferred)
   547             //return type is java.lang.Void; emit a synthetic return statement
   548             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   549         }
   550         return trans_block;
   551     }
   553     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   554         ListBuffer<JCCase> cases = new ListBuffer<>();
   555         ListBuffer<JCBreak> breaks = new ListBuffer<>();
   556         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   557             JCBreak br = make.Break(null);
   558             breaks.add(br);
   559             List<JCStatement> stmts = entry.getValue().append(br).toList();
   560             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   561         }
   562         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   563         for (JCBreak br : breaks) {
   564             br.target = sw;
   565         }
   566         JCBlock body = make.Block(0L, List.<JCStatement>of(
   567                 sw,
   568                 make.Throw(makeNewClass(
   569                     syms.illegalArgumentExceptionType,
   570                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   571         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   572                         names.deserializeLambda,
   573                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   574                         List.<JCTypeParameter>nil(),
   575                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   576                         List.<JCExpression>nil(),
   577                         body,
   578                         null);
   579         deser.sym = kInfo.deserMethodSym;
   580         deser.type = kInfo.deserMethodSym.type;
   581         //System.err.printf("DESER: '%s'\n", deser);
   582         return deser;
   583     }
   585     /** Make an attributed class instance creation expression.
   586      *  @param ctype    The class type.
   587      *  @param args     The constructor arguments.
   588      *  @param cons     The constructor symbol
   589      */
   590     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
   591         JCNewClass tree = make.NewClass(null,
   592             null, make.QualIdent(ctype.tsym), args, null);
   593         tree.constructor = cons;
   594         tree.type = ctype;
   595         return tree;
   596     }
   598     /** Make an attributed class instance creation expression.
   599      *  @param ctype    The class type.
   600      *  @param args     The constructor arguments.
   601      */
   602     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   603         return makeNewClass(ctype, args,
   604                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
   605      }
   607     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   608             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   609         String functionalInterfaceClass = classSig(targetType);
   610         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   611         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
   612         String implClass = classSig(types.erasure(refSym.owner.type));
   613         String implMethodName = refSym.getQualifiedName().toString();
   614         String implMethodSignature = typeSig(types.erasure(refSym.type));
   616         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   617         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
   618         int i = 0;
   619         for (Type t : indyType.getParameterTypes()) {
   620             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
   621             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
   622             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   623             ++i;
   624         }
   625         JCStatement stmt = make.If(
   626                 deserTest(deserTest(deserTest(deserTest(deserTest(
   627                     kindTest,
   628                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   629                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   630                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   631                     "getImplClass", implClass),
   632                     "getImplMethodSignature", implMethodSignature),
   633                 make.Return(makeIndyCall(
   634                     pos,
   635                     syms.lambdaMetafactory,
   636                     names.altMetafactory,
   637                     staticArgs, indyType, serArgs.toList(), samSym.name)),
   638                 null);
   639         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   640         if (stmts == null) {
   641             stmts = new ListBuffer<>();
   642             kInfo.deserializeCases.put(implMethodName, stmts);
   643         }
   644         /****
   645         System.err.printf("+++++++++++++++++\n");
   646         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   647         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   648         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   649         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   650         System.err.printf("*implClass: '%s'\n", implClass);
   651         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   652         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   653         ****/
   654         stmts.append(stmt);
   655     }
   657     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   658         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   659         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   660         testExpr.setType(syms.booleanType);
   661         return testExpr;
   662     }
   664     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   665         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   666         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   667         JCMethodInvocation eqtest = make.Apply(
   668                 List.<JCExpression>nil(),
   669                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   670                 List.<JCExpression>of(make.Literal(lit)));
   671         eqtest.setType(syms.booleanType);
   672         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   673         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   674         compound.setType(syms.booleanType);
   675         return compound;
   676     }
   678     private JCExpression deserGetter(String func, Type type) {
   679         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   680     }
   682     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   683         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   684         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   685         return make.Apply(
   686                     List.<JCExpression>nil(),
   687                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   688                     args).setType(type);
   689     }
   691     /**
   692      * Create new synthetic method with given flags, name, type, owner
   693      */
   694     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   695         return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
   696     }
   698     /**
   699      * Create new synthetic variable with given flags, name, type, owner
   700      */
   701     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   702         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   703     }
   705     /**
   706      * Create new synthetic variable with given flags, name, type, owner
   707      */
   708     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   709         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   710     }
   712     /**
   713      * Set varargsElement field on a given tree (must be either a new class tree
   714      * or a method call tree)
   715      */
   716     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   717         if (varargsElement != null) {
   718             switch (tree.getTag()) {
   719                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   720                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   721                 default: throw new AssertionError();
   722             }
   723         }
   724     }
   726     /**
   727      * Convert method/constructor arguments by inserting appropriate cast
   728      * as required by type-erasure - this is needed when bridging a lambda/method
   729      * reference, as the bridged signature might require downcast to be compatible
   730      * with the generated signature.
   731      */
   732     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   733        Assert.check(meth.kind == Kinds.MTH);
   734        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   735        if (varargsElement != null) {
   736            Assert.check((meth.flags() & VARARGS) != 0);
   737        }
   738        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   739     }
   741     // </editor-fold>
   743     /**
   744      * Converts a method reference which cannot be used directly into a lambda
   745      */
   746     private class MemberReferenceToLambda {
   748         private final JCMemberReference tree;
   749         private final ReferenceTranslationContext localContext;
   750         private final Symbol owner;
   751         private final ListBuffer<JCExpression> args = new ListBuffer<>();
   752         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
   754         private JCExpression receiverExpression = null;
   756         MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) {
   757             this.tree = tree;
   758             this.localContext = localContext;
   759             this.owner = owner;
   760         }
   762         JCLambda lambda() {
   763             int prevPos = make.pos;
   764             try {
   765                 make.at(tree);
   767                 //body generation - this can be either a method call or a
   768                 //new instance creation expression, depending on the member reference kind
   769                 VarSymbol rcvr = addParametersReturnReceiver();
   770                 JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
   771                         ? expressionInvoke(rcvr)
   772                         : expressionNew();
   774                 JCLambda slam = make.Lambda(params.toList(), expr);
   775                 slam.targets = tree.targets;
   776                 slam.type = tree.type;
   777                 slam.pos = tree.pos;
   778                 return slam;
   779             } finally {
   780                 make.at(prevPos);
   781             }
   782         }
   784         /**
   785          * Generate the parameter list for the converted member reference.
   786          *
   787          * @return The receiver variable symbol, if any
   788          */
   789         VarSymbol addParametersReturnReceiver() {
   790             Type samDesc = localContext.bridgedRefSig();
   791             List<Type> samPTypes = samDesc.getParameterTypes();
   792             List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes();
   794             // Determine the receiver, if any
   795             VarSymbol rcvr;
   796             switch (tree.kind) {
   797                 case BOUND:
   798                     // The receiver is explicit in the method reference
   799                     rcvr = addParameter("rec$", tree.getQualifierExpression().type, false);
   800                     receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
   801                     break;
   802                 case UNBOUND:
   803                     // The receiver is the first parameter, extract it and
   804                     // adjust the SAM and unerased type lists accordingly
   805                     rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false);
   806                     samPTypes = samPTypes.tail;
   807                     descPTypes = descPTypes.tail;
   808                     break;
   809                 default:
   810                     rcvr = null;
   811                     break;
   812             }
   813             List<Type> implPTypes = tree.sym.type.getParameterTypes();
   814             int implSize = implPTypes.size();
   815             int samSize = samPTypes.size();
   816             // Last parameter to copy from referenced method, exclude final var args
   817             int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize;
   819             // Failsafe -- assure match-up
   820             boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size();
   822             // Use parameter types of the implementation method unless the unerased
   823             // SAM parameter type is an intersection type, in that case use the
   824             // erased SAM parameter type so that the supertype relationship
   825             // the implementation method parameters is not obscured.
   826             // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes
   827             // are used as pointers to the current parameter type information
   828             // and are thus not usable afterwards.
   829             for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) {
   830                 // By default use the implementation method parmeter type
   831                 Type parmType = implPTypes.head;
   832                 // If the unerased parameter type is a type variable whose
   833                 // bound is an intersection (eg. <T extends A & B>) then
   834                 // use the SAM parameter type
   835                 if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) {
   836                     TypeVar tv = (TypeVar) descPTypes.head;
   837                     if (tv.bound.getKind() == TypeKind.INTERSECTION) {
   838                         parmType = samPTypes.head;
   839                     }
   840                 }
   841                 addParameter("x$" + i, parmType, true);
   843                 // Advance to the next parameter
   844                 implPTypes = implPTypes.tail;
   845                 samPTypes = samPTypes.tail;
   846                 descPTypes = descPTypes.tail;
   847             }
   848             // Flatten out the var args
   849             for (int i = last; i < samSize; ++i) {
   850                 addParameter("xva$" + i, tree.varargsElement, true);
   851             }
   853             return rcvr;
   854         }
   856         JCExpression getReceiverExpression() {
   857             return receiverExpression;
   858         }
   860         private JCExpression makeReceiver(VarSymbol rcvr) {
   861             if (rcvr == null) return null;
   862             JCExpression rcvrExpr = make.Ident(rcvr);
   863             Type rcvrType = tree.sym.enclClass().type;
   864             if (rcvrType == syms.arrayClass.type) {
   865                 // Map the receiver type to the actually type, not just "array"
   866                 rcvrType = tree.getQualifierExpression().type;
   867             }
   868             if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   869                 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   870             }
   871             return rcvrExpr;
   872         }
   874         /**
   875          * determine the receiver of the method call - the receiver can
   876          * be a type qualifier, the synthetic receiver parameter or 'super'.
   877          */
   878         private JCExpression expressionInvoke(VarSymbol rcvr) {
   879             JCExpression qualifier =
   880                     tree.sym.isStatic() ?
   881                         make.Type(tree.sym.owner.type) :
   882                         (rcvr != null) ?
   883                             makeReceiver(rcvr) :
   884                             tree.getQualifierExpression();
   886             //create the qualifier expression
   887             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   888             select.sym = tree.sym;
   889             select.type = tree.sym.erasure(types);
   891             //create the method call expression
   892             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   893                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   894                     setType(tree.sym.erasure(types).getReturnType());
   896             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   897             setVarargsIfNeeded(apply, tree.varargsElement);
   898             return apply;
   899         }
   901         /**
   902          * Lambda body to use for a 'new'.
   903          */
   904         private JCExpression expressionNew() {
   905             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   906                 //create the array creation expression
   907                 JCNewArray newArr = make.NewArray(
   908                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   909                         List.of(make.Ident(params.first())),
   910                         null);
   911                 newArr.type = tree.getQualifierExpression().type;
   912                 return newArr;
   913             } else {
   914                 //create the instance creation expression
   915                 //note that method reference syntax does not allow an explicit
   916                 //enclosing class (so the enclosing class is null)
   917                 JCNewClass newClass = make.NewClass(null,
   918                         List.<JCExpression>nil(),
   919                         make.Type(tree.getQualifierExpression().type),
   920                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   921                         null);
   922                 newClass.constructor = tree.sym;
   923                 newClass.constructorType = tree.sym.erasure(types);
   924                 newClass.type = tree.getQualifierExpression().type;
   925                 setVarargsIfNeeded(newClass, tree.varargsElement);
   926                 return newClass;
   927             }
   928         }
   930         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   931             VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
   932             vsym.pos = tree.pos;
   933             params.append(make.VarDef(vsym, null));
   934             if (genArg) {
   935                 args.append(make.Ident(vsym));
   936             }
   937             return vsym;
   938         }
   939     }
   941     private MethodType typeToMethodType(Type mt) {
   942         Type type = types.erasure(mt);
   943         return new MethodType(type.getParameterTypes(),
   944                         type.getReturnType(),
   945                         type.getThrownTypes(),
   946                         syms.methodClass);
   947     }
   949     /**
   950      * Generate an indy method call to the meta factory
   951      */
   952     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
   953             int refKind, Symbol refSym, List<JCExpression> indy_args) {
   954         JCFunctionalExpression tree = context.tree;
   955         //determine the static bsm args
   956         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   957         List<Object> staticArgs = List.<Object>of(
   958                 typeToMethodType(samSym.type),
   959                 new Pool.MethodHandle(refKind, refSym, types),
   960                 typeToMethodType(tree.getDescriptorType(types)));
   962         //computed indy arg types
   963         ListBuffer<Type> indy_args_types = new ListBuffer<>();
   964         for (JCExpression arg : indy_args) {
   965             indy_args_types.append(arg.type);
   966         }
   968         //finally, compute the type of the indy call
   969         MethodType indyType = new MethodType(indy_args_types.toList(),
   970                 tree.type,
   971                 List.<Type>nil(),
   972                 syms.methodClass);
   974         Name metafactoryName = context.needsAltMetafactory() ?
   975                 names.altMetafactory : names.metafactory;
   977         if (context.needsAltMetafactory()) {
   978             ListBuffer<Object> markers = new ListBuffer<>();
   979             for (Type t : tree.targets.tail) {
   980                 if (t.tsym != syms.serializableType.tsym) {
   981                     markers.append(t.tsym);
   982                 }
   983             }
   984             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
   985             boolean hasMarkers = markers.nonEmpty();
   986             boolean hasBridges = context.bridges.nonEmpty();
   987             if (hasMarkers) {
   988                 flags |= FLAG_MARKERS;
   989             }
   990             if (hasBridges) {
   991                 flags |= FLAG_BRIDGES;
   992             }
   993             staticArgs = staticArgs.append(flags);
   994             if (hasMarkers) {
   995                 staticArgs = staticArgs.append(markers.length());
   996                 staticArgs = staticArgs.appendList(markers.toList());
   997             }
   998             if (hasBridges) {
   999                 staticArgs = staticArgs.append(context.bridges.length() - 1);
  1000                 for (Symbol s : context.bridges) {
  1001                     Type s_erasure = s.erasure(types);
  1002                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
  1003                         staticArgs = staticArgs.append(s.erasure(types));
  1007             if (context.isSerializable()) {
  1008                 int prevPos = make.pos;
  1009                 try {
  1010                     make.at(kInfo.clazz);
  1011                     addDeserializationCase(refKind, refSym, tree.type, samSym,
  1012                             tree, staticArgs, indyType);
  1013                 } finally {
  1014                     make.at(prevPos);
  1019         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
  1022     /**
  1023      * Generate an indy method call with given name, type and static bootstrap
  1024      * arguments types
  1025      */
  1026     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
  1027             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
  1028             Name methName) {
  1029         int prevPos = make.pos;
  1030         try {
  1031             make.at(pos);
  1032             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
  1033                     syms.stringType,
  1034                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
  1036             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
  1037                     bsmName, bsm_staticArgs, List.<Type>nil());
  1039             DynamicMethodSymbol dynSym =
  1040                     new DynamicMethodSymbol(methName,
  1041                                             syms.noSymbol,
  1042                                             bsm.isStatic() ?
  1043                                                 ClassFile.REF_invokeStatic :
  1044                                                 ClassFile.REF_invokeVirtual,
  1045                                             (MethodSymbol)bsm,
  1046                                             indyType,
  1047                                             staticArgs.toArray());
  1049             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1050             qualifier.sym = dynSym;
  1051             qualifier.type = indyType.getReturnType();
  1053             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
  1054             proxyCall.type = indyType.getReturnType();
  1055             return proxyCall;
  1056         } finally {
  1057             make.at(prevPos);
  1060     //where
  1061     private List<Type> bsmStaticArgToTypes(List<Object> args) {
  1062         ListBuffer<Type> argtypes = new ListBuffer<>();
  1063         for (Object arg : args) {
  1064             argtypes.append(bsmStaticArgToType(arg));
  1066         return argtypes.toList();
  1069     private Type bsmStaticArgToType(Object arg) {
  1070         Assert.checkNonNull(arg);
  1071         if (arg instanceof ClassSymbol) {
  1072             return syms.classType;
  1073         } else if (arg instanceof Integer) {
  1074             return syms.intType;
  1075         } else if (arg instanceof Long) {
  1076             return syms.longType;
  1077         } else if (arg instanceof Float) {
  1078             return syms.floatType;
  1079         } else if (arg instanceof Double) {
  1080             return syms.doubleType;
  1081         } else if (arg instanceof String) {
  1082             return syms.stringType;
  1083         } else if (arg instanceof Pool.MethodHandle) {
  1084             return syms.methodHandleType;
  1085         } else if (arg instanceof MethodType) {
  1086             return syms.methodTypeType;
  1087         } else {
  1088             Assert.error("bad static arg " + arg.getClass());
  1089             return null;
  1093     /**
  1094      * Get the opcode associated with this method reference
  1095      */
  1096     private int referenceKind(Symbol refSym) {
  1097         if (refSym.isConstructor()) {
  1098             return ClassFile.REF_newInvokeSpecial;
  1099         } else {
  1100             if (refSym.isStatic()) {
  1101                 return ClassFile.REF_invokeStatic;
  1102             } else if ((refSym.flags() & PRIVATE) != 0) {
  1103                 return ClassFile.REF_invokeSpecial;
  1104             } else if (refSym.enclClass().isInterface()) {
  1105                 return ClassFile.REF_invokeInterface;
  1106             } else {
  1107                 return ClassFile.REF_invokeVirtual;
  1112     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1113     /**
  1114      * This visitor collects information about translation of a lambda expression.
  1115      * More specifically, it keeps track of the enclosing contexts and captured locals
  1116      * accessed by the lambda being translated (as well as other useful info).
  1117      * It also translates away problems for LambdaToMethod.
  1118      */
  1119     class LambdaAnalyzerPreprocessor extends TreeTranslator {
  1121         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1122         private List<Frame> frameStack;
  1124         /**
  1125          * keep the count of lambda expression (used to generate unambiguous
  1126          * names)
  1127          */
  1128         private int lambdaCount = 0;
  1130         /**
  1131          * keep the count of lambda expression defined in given context (used to
  1132          * generate unambiguous names for serializable lambdas)
  1133          */
  1134         private class SyntheticMethodNameCounter {
  1135             private Map<String, Integer> map = new HashMap<>();
  1136             int getIndex(StringBuilder buf) {
  1137                 String temp = buf.toString();
  1138                 Integer count = map.get(temp);
  1139                 if (count == null) {
  1140                     count = 0;
  1142                 ++count;
  1143                 map.put(temp, count);
  1144                 return count;
  1147         private SyntheticMethodNameCounter syntheticMethodNameCounts =
  1148                 new SyntheticMethodNameCounter();
  1150         private Map<Symbol, JCClassDecl> localClassDefs;
  1152         /**
  1153          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1154          * a static var init context
  1155          */
  1156         private Map<ClassSymbol, Symbol> clinits =
  1157                 new HashMap<ClassSymbol, Symbol>();
  1159         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
  1160             frameStack = List.nil();
  1161             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1162             return translate(tree);
  1165         @Override
  1166         public void visitBlock(JCBlock tree) {
  1167             List<Frame> prevStack = frameStack;
  1168             try {
  1169                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1170                     frameStack = frameStack.prepend(new Frame(tree));
  1172                 super.visitBlock(tree);
  1174             finally {
  1175                 frameStack = prevStack;
  1179         @Override
  1180         public void visitClassDef(JCClassDecl tree) {
  1181             List<Frame> prevStack = frameStack;
  1182             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
  1183                     syntheticMethodNameCounts;
  1184             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1185             DiagnosticSource prevSource = log.currentSource();
  1186             try {
  1187                 log.useSource(tree.sym.sourcefile);
  1188                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
  1189                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1190                 if (tree.sym.owner.kind == MTH) {
  1191                     localClassDefs.put(tree.sym, tree);
  1193                 if (directlyEnclosingLambda() != null) {
  1194                     tree.sym.owner = owner();
  1195                     if (tree.sym.hasOuterInstance()) {
  1196                         //if a class is defined within a lambda, the lambda must capture
  1197                         //its enclosing instance (if any)
  1198                         TranslationContext<?> localContext = context();
  1199                         while (localContext != null) {
  1200                             if (localContext.tree.getTag() == LAMBDA) {
  1201                                 ((LambdaTranslationContext)localContext)
  1202                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1204                             localContext = localContext.prev;
  1208                 frameStack = frameStack.prepend(new Frame(tree));
  1209                 super.visitClassDef(tree);
  1211             finally {
  1212                 log.useSource(prevSource.getFile());
  1213                 frameStack = prevStack;
  1214                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
  1215                 clinits = prevClinits;
  1219         @Override
  1220         public void visitIdent(JCIdent tree) {
  1221             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1222                 if (tree.sym.kind == VAR &&
  1223                         tree.sym.owner.kind == MTH &&
  1224                         tree.type.constValue() == null) {
  1225                     TranslationContext<?> localContext = context();
  1226                     while (localContext != null) {
  1227                         if (localContext.tree.getTag() == LAMBDA) {
  1228                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1229                             if (block == null) break;
  1230                             ((LambdaTranslationContext)localContext)
  1231                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1233                         localContext = localContext.prev;
  1235                 } else if (tree.sym.owner.kind == TYP) {
  1236                     TranslationContext<?> localContext = context();
  1237                     while (localContext != null) {
  1238                         if (localContext.tree.hasTag(LAMBDA)) {
  1239                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1240                             if (block == null) break;
  1241                             switch (block.getTag()) {
  1242                                 case CLASSDEF:
  1243                                     JCClassDecl cdecl = (JCClassDecl)block;
  1244                                     ((LambdaTranslationContext)localContext)
  1245                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1246                                     break;
  1247                                 default:
  1248                                     Assert.error("bad block kind");
  1251                         localContext = localContext.prev;
  1255             super.visitIdent(tree);
  1258         @Override
  1259         public void visitLambda(JCLambda tree) {
  1260             analyzeLambda(tree, "lambda.stat");
  1263         private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) {
  1264             // Translation of the receiver expression must occur first
  1265             JCExpression rcvr = translate(methodReferenceReceiver);
  1266             LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1");
  1267             if (rcvr != null) {
  1268                 context.methodReferenceReceiver = rcvr;
  1272         private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) {
  1273             List<Frame> prevStack = frameStack;
  1274             try {
  1275                 LambdaTranslationContext context = new LambdaTranslationContext(tree);
  1276                 if (dumpLambdaToMethodStats) {
  1277                     log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym);
  1279                 frameStack = frameStack.prepend(new Frame(tree));
  1280                 for (JCVariableDecl param : tree.params) {
  1281                     context.addSymbol(param.sym, PARAM);
  1282                     frameStack.head.addLocal(param.sym);
  1284                 contextMap.put(tree, context);
  1285                 super.visitLambda(tree);
  1286                 context.complete();
  1287                 return context;
  1289             finally {
  1290                 frameStack = prevStack;
  1294         @Override
  1295         public void visitMethodDef(JCMethodDecl tree) {
  1296             List<Frame> prevStack = frameStack;
  1297             try {
  1298                 frameStack = frameStack.prepend(new Frame(tree));
  1299                 super.visitMethodDef(tree);
  1301             finally {
  1302                 frameStack = prevStack;
  1306         @Override
  1307         public void visitNewClass(JCNewClass tree) {
  1308             TypeSymbol def = tree.type.tsym;
  1309             boolean inReferencedClass = currentlyInClass(def);
  1310             boolean isLocal = def.isLocal();
  1311             if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
  1312                 TranslationContext<?> localContext = context();
  1313                 while (localContext != null) {
  1314                     if (localContext.tree.getTag() == LAMBDA) {
  1315                         ((LambdaTranslationContext)localContext)
  1316                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1318                     localContext = localContext.prev;
  1321             if (context() != null && !inReferencedClass && isLocal) {
  1322                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1323                 captureLocalClassDefs(def, lambdaContext);
  1325             super.visitNewClass(tree);
  1327         //where
  1328             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1329                 JCClassDecl localCDef = localClassDefs.get(csym);
  1330                 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
  1331                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1332                         @Override
  1333                         void addFreeVars(ClassSymbol c) {
  1334                             captureLocalClassDefs(c, lambdaContext);
  1336                         @Override
  1337                         void visitSymbol(Symbol sym) {
  1338                             if (sym.kind == VAR &&
  1339                                     sym.owner.kind == MTH &&
  1340                                     ((VarSymbol)sym).getConstValue() == null) {
  1341                                 TranslationContext<?> localContext = context();
  1342                                 while (localContext != null) {
  1343                                     if (localContext.tree.getTag() == LAMBDA) {
  1344                                         JCTree block = capturedDecl(localContext.depth, sym);
  1345                                         if (block == null) break;
  1346                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1348                                     localContext = localContext.prev;
  1352                     };
  1353                     fvc.scan(localCDef);
  1356         //where
  1357         boolean currentlyInClass(Symbol csym) {
  1358             for (Frame frame : frameStack) {
  1359                 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
  1360                     JCClassDecl cdef = (JCClassDecl) frame.tree;
  1361                     if (cdef.sym == csym) {
  1362                         return true;
  1366             return false;
  1369         /**
  1370          * Method references to local class constructors, may, if the local
  1371          * class references local variables, have implicit constructor
  1372          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1373          * information added in the LambdaToMethod pass will have the wrong
  1374          * signature. Hooks between Lower and LambdaToMethod have been added to
  1375          * handle normal "new" in this case. This visitor converts potentially
  1376          * affected method references into a lambda containing a normal
  1377          * expression.
  1379          * @param tree
  1380          */
  1381         @Override
  1382         public void visitReference(JCMemberReference tree) {
  1383             ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree);
  1384             contextMap.put(tree, rcontext);
  1385             if (rcontext.needsConversionToLambda()) {
  1386                  // Convert to a lambda, and process as such
  1387                 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner());
  1388                 analyzeLambda(conv.lambda(), conv.getReceiverExpression());
  1389             } else {
  1390                 super.visitReference(tree);
  1391                 if (dumpLambdaToMethodStats) {
  1392                     log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null);
  1397         @Override
  1398         public void visitSelect(JCFieldAccess tree) {
  1399             if (context() != null && tree.sym.kind == VAR &&
  1400                         (tree.sym.name == names._this ||
  1401                          tree.sym.name == names._super)) {
  1402                 // A select of this or super means, if we are in a lambda,
  1403                 // we much have an instance context
  1404                 TranslationContext<?> localContext = context();
  1405                 while (localContext != null) {
  1406                     if (localContext.tree.hasTag(LAMBDA)) {
  1407                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1408                         if (clazz == null) break;
  1409                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1411                     localContext = localContext.prev;
  1414             super.visitSelect(tree);
  1417         @Override
  1418         public void visitVarDef(JCVariableDecl tree) {
  1419             TranslationContext<?> context = context();
  1420             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1421                     (LambdaTranslationContext)context :
  1422                     null;
  1423             if (ltc != null) {
  1424                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1425                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1427                 // Check for type variables (including as type arguments).
  1428                 // If they occur within class nested in a lambda, mark for erasure
  1429                 Type type = tree.sym.asType();
  1430                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1431                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1435             List<Frame> prevStack = frameStack;
  1436             try {
  1437                 if (tree.sym.owner.kind == MTH) {
  1438                     frameStack.head.addLocal(tree.sym);
  1440                 frameStack = frameStack.prepend(new Frame(tree));
  1441                 super.visitVarDef(tree);
  1443             finally {
  1444                 frameStack = prevStack;
  1448         /**
  1449          * Return a valid owner given the current declaration stack
  1450          * (required to skip synthetic lambda symbols)
  1451          */
  1452         private Symbol owner() {
  1453             return owner(false);
  1456         @SuppressWarnings("fallthrough")
  1457         private Symbol owner(boolean skipLambda) {
  1458             List<Frame> frameStack2 = frameStack;
  1459             while (frameStack2.nonEmpty()) {
  1460                 switch (frameStack2.head.tree.getTag()) {
  1461                     case VARDEF:
  1462                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1463                             frameStack2 = frameStack2.tail;
  1464                             break;
  1466                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1467                         return initSym(cdecl.sym,
  1468                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1469                     case BLOCK:
  1470                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1471                         return initSym(cdecl2.sym,
  1472                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1473                     case CLASSDEF:
  1474                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1475                     case METHODDEF:
  1476                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1477                     case LAMBDA:
  1478                         if (!skipLambda)
  1479                             return ((LambdaTranslationContext)contextMap
  1480                                     .get(frameStack2.head.tree)).translatedSym;
  1481                     default:
  1482                         frameStack2 = frameStack2.tail;
  1485             Assert.error();
  1486             return null;
  1489         private Symbol initSym(ClassSymbol csym, long flags) {
  1490             boolean isStatic = (flags & STATIC) != 0;
  1491             if (isStatic) {
  1492                 /* static clinits are generated in Gen, so we need to use a fake
  1493                  * one. Attr creates a fake clinit method while attributing
  1494                  * lambda expressions used as initializers of static fields, so
  1495                  * let's use that one.
  1496                  */
  1497                 MethodSymbol clinit = attr.removeClinit(csym);
  1498                 if (clinit != null) {
  1499                     clinits.put(csym, clinit);
  1500                     return clinit;
  1503                 /* if no clinit is found at Attr, then let's try at clinits.
  1504                  */
  1505                 clinit = (MethodSymbol)clinits.get(csym);
  1506                 if (clinit == null) {
  1507                     /* no luck, let's create a new one
  1508                      */
  1509                     clinit = makePrivateSyntheticMethod(STATIC,
  1510                             names.clinit,
  1511                             new MethodType(List.<Type>nil(), syms.voidType,
  1512                                 List.<Type>nil(), syms.methodClass),
  1513                             csym);
  1514                     clinits.put(csym, clinit);
  1516                 return clinit;
  1517             } else {
  1518                 //get the first constructor and treat it as the instance init sym
  1519                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1520                     return s;
  1523             Assert.error("init not found");
  1524             return null;
  1527         private JCTree directlyEnclosingLambda() {
  1528             if (frameStack.isEmpty()) {
  1529                 return null;
  1531             List<Frame> frameStack2 = frameStack;
  1532             while (frameStack2.nonEmpty()) {
  1533                 switch (frameStack2.head.tree.getTag()) {
  1534                     case CLASSDEF:
  1535                     case METHODDEF:
  1536                         return null;
  1537                     case LAMBDA:
  1538                         return frameStack2.head.tree;
  1539                     default:
  1540                         frameStack2 = frameStack2.tail;
  1543             Assert.error();
  1544             return null;
  1547         private boolean inClassWithinLambda() {
  1548             if (frameStack.isEmpty()) {
  1549                 return false;
  1551             List<Frame> frameStack2 = frameStack;
  1552             boolean classFound = false;
  1553             while (frameStack2.nonEmpty()) {
  1554                 switch (frameStack2.head.tree.getTag()) {
  1555                     case LAMBDA:
  1556                         return classFound;
  1557                     case CLASSDEF:
  1558                         classFound = true;
  1559                         frameStack2 = frameStack2.tail;
  1560                         break;
  1561                     default:
  1562                         frameStack2 = frameStack2.tail;
  1565             // No lambda
  1566             return false;
  1569         /**
  1570          * Return the declaration corresponding to a symbol in the enclosing
  1571          * scope; the depth parameter is used to filter out symbols defined
  1572          * in nested scopes (which do not need to undergo capture).
  1573          */
  1574         private JCTree capturedDecl(int depth, Symbol sym) {
  1575             int currentDepth = frameStack.size() - 1;
  1576             for (Frame block : frameStack) {
  1577                 switch (block.tree.getTag()) {
  1578                     case CLASSDEF:
  1579                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1580                         if (sym.isMemberOf(clazz, types)) {
  1581                             return currentDepth > depth ? null : block.tree;
  1583                         break;
  1584                     case VARDEF:
  1585                         if (((JCVariableDecl)block.tree).sym == sym &&
  1586                                 sym.owner.kind == MTH) { //only locals are captured
  1587                             return currentDepth > depth ? null : block.tree;
  1589                         break;
  1590                     case BLOCK:
  1591                     case METHODDEF:
  1592                     case LAMBDA:
  1593                         if (block.locals != null && block.locals.contains(sym)) {
  1594                             return currentDepth > depth ? null : block.tree;
  1596                         break;
  1597                     default:
  1598                         Assert.error("bad decl kind " + block.tree.getTag());
  1600                 currentDepth--;
  1602             return null;
  1605         private TranslationContext<?> context() {
  1606             for (Frame frame : frameStack) {
  1607                 TranslationContext<?> context = contextMap.get(frame.tree);
  1608                 if (context != null) {
  1609                     return context;
  1612             return null;
  1615         /**
  1616          *  This is used to filter out those identifiers that needs to be adjusted
  1617          *  when translating away lambda expressions
  1618          */
  1619         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1620             return (sym.kind == VAR || sym.kind == MTH)
  1621                     && !sym.isStatic()
  1622                     && sym.name != names.init;
  1625         /**
  1626          * This is used to filter out those new class expressions that need to
  1627          * be qualified with an enclosing tree
  1628          */
  1629         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1630             if (context != null
  1631                     && tree.encl == null
  1632                     && tree.def == null
  1633                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1634                 Type encl = tree.type.getEnclosingType();
  1635                 Type current = context.owner.enclClass().type;
  1636                 while (!current.hasTag(NONE)) {
  1637                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1638                         return true;
  1640                     current = current.getEnclosingType();
  1642                 return false;
  1643             } else {
  1644                 return false;
  1648         private class Frame {
  1649             final JCTree tree;
  1650             List<Symbol> locals;
  1652             public Frame(JCTree tree) {
  1653                 this.tree = tree;
  1656             void addLocal(Symbol sym) {
  1657                 if (locals == null) {
  1658                     locals = List.nil();
  1660                 locals = locals.prepend(sym);
  1664         /**
  1665          * This class is used to store important information regarding translation of
  1666          * lambda expression/method references (see subclasses).
  1667          */
  1668         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1670             /** the underlying (untranslated) tree */
  1671             final T tree;
  1673             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1674             final Symbol owner;
  1676             /** the depth of this lambda expression in the frame stack */
  1677             final int depth;
  1679             /** the enclosing translation context (set for nested lambdas/mref) */
  1680             final TranslationContext<?> prev;
  1682             /** list of methods to be bridged by the meta-factory */
  1683             final List<Symbol> bridges;
  1685             TranslationContext(T tree) {
  1686                 this.tree = tree;
  1687                 this.owner = owner();
  1688                 this.depth = frameStack.size() - 1;
  1689                 this.prev = context();
  1690                 ClassSymbol csym =
  1691                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1692                 this.bridges = types.functionalInterfaceBridges(csym);
  1695             /** does this functional expression need to be created using alternate metafactory? */
  1696             boolean needsAltMetafactory() {
  1697                 return tree.targets.length() > 1 ||
  1698                         isSerializable() ||
  1699                         bridges.length() > 1;
  1702             /** does this functional expression require serialization support? */
  1703             boolean isSerializable() {
  1704                 if (forceSerializable) {
  1705                     return true;
  1707                 for (Type target : tree.targets) {
  1708                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1709                         return true;
  1712                 return false;
  1715             /**
  1716              * @return Name of the enclosing method to be folded into synthetic
  1717              * method name
  1718              */
  1719             String enclosingMethodName() {
  1720                 return syntheticMethodNameComponent(owner.name);
  1723             /**
  1724              * @return Method name in a form that can be folded into a
  1725              * component of a synthetic method name
  1726              */
  1727             String syntheticMethodNameComponent(Name name) {
  1728                 if (name == null) {
  1729                     return "null";
  1731                 String methodName = name.toString();
  1732                 if (methodName.equals("<clinit>")) {
  1733                     methodName = "static";
  1734                 } else if (methodName.equals("<init>")) {
  1735                     methodName = "new";
  1737                 return methodName;
  1741         /**
  1742          * This class retains all the useful information about a lambda expression;
  1743          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1744          * and the used by the main translation routines in order to adjust references
  1745          * to captured locals/members, etc.
  1746          */
  1747         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1749             /** variable in the enclosing context to which this lambda is assigned */
  1750             final Symbol self;
  1752             /** variable in the enclosing context to which this lambda is assigned */
  1753             final Symbol assignedTo;
  1755             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
  1757             /** the synthetic symbol for the method hoisting the translated lambda */
  1758             MethodSymbol translatedSym;
  1760             List<JCVariableDecl> syntheticParams;
  1762             /**
  1763              * to prevent recursion, track local classes processed
  1764              */
  1765             final Set<Symbol> freeVarProcessedLocalClasses;
  1767             /**
  1768              * For method references converted to lambdas.  The method
  1769              * reference receiver expression. Must be treated like a captured
  1770              * variable.
  1771              */
  1772             JCExpression methodReferenceReceiver;
  1774             LambdaTranslationContext(JCLambda tree) {
  1775                 super(tree);
  1776                 Frame frame = frameStack.head;
  1777                 switch (frame.tree.getTag()) {
  1778                     case VARDEF:
  1779                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
  1780                         break;
  1781                     case ASSIGN:
  1782                         self = null;
  1783                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
  1784                         break;
  1785                     default:
  1786                         assignedTo = self = null;
  1787                         break;
  1790                 // This symbol will be filled-in in complete
  1791                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
  1793                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
  1795                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
  1796                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
  1797                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
  1798                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
  1799                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
  1801                 freeVarProcessedLocalClasses = new HashSet<>();
  1804              /**
  1805              * For a serializable lambda, generate a disambiguating string
  1806              * which maximizes stability across deserialization.
  1808              * @return String to differentiate synthetic lambda method names
  1809              */
  1810             private String serializedLambdaDisambiguation() {
  1811                 StringBuilder buf = new StringBuilder();
  1812                 // Append the enclosing method signature to differentiate
  1813                 // overloaded enclosing methods.  For lambdas enclosed in
  1814                 // lambdas, the generated lambda method will not have type yet,
  1815                 // but the enclosing method's name will have been generated
  1816                 // with this same method, so it will be unique and never be
  1817                 // overloaded.
  1818                 Assert.check(
  1819                         owner.type != null ||
  1820                         directlyEnclosingLambda() != null);
  1821                 if (owner.type != null) {
  1822                     buf.append(typeSig(owner.type));
  1823                     buf.append(":");
  1826                 // Add target type info
  1827                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
  1828                 buf.append(" ");
  1830                 // Add variable assigned to
  1831                 if (assignedTo != null) {
  1832                     buf.append(assignedTo.flatName());
  1833                     buf.append("=");
  1835                 //add captured locals info: type, name, order
  1836                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
  1837                     if (fv != self) {
  1838                         buf.append(typeSig(fv.type));
  1839                         buf.append(" ");
  1840                         buf.append(fv.flatName());
  1841                         buf.append(",");
  1845                 return buf.toString();
  1848             /**
  1849              * For a non-serializable lambda, generate a simple method.
  1851              * @return Name to use for the synthetic lambda method name
  1852              */
  1853             private Name lambdaName() {
  1854                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
  1857             /**
  1858              * For a serializable lambda, generate a method name which maximizes
  1859              * name stability across deserialization.
  1861              * @return Name to use for the synthetic lambda method name
  1862              */
  1863             private Name serializedLambdaName() {
  1864                 StringBuilder buf = new StringBuilder();
  1865                 buf.append(names.lambda);
  1866                 // Append the name of the method enclosing the lambda.
  1867                 buf.append(enclosingMethodName());
  1868                 buf.append('$');
  1869                 // Append a hash of the disambiguating string : enclosing method
  1870                 // signature, etc.
  1871                 String disam = serializedLambdaDisambiguation();
  1872                 buf.append(Integer.toHexString(disam.hashCode()));
  1873                 buf.append('$');
  1874                 // The above appended name components may not be unique, append
  1875                 // a count based on the above name components.
  1876                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  1877                 String result = buf.toString();
  1878                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
  1879                 return names.fromString(result);
  1882             /**
  1883              * Translate a symbol of a given kind into something suitable for the
  1884              * synthetic lambda body
  1885              */
  1886             Symbol translate(final Symbol sym, LambdaSymbolKind skind) {
  1887                 Symbol ret;
  1888                 switch (skind) {
  1889                     case CAPTURED_THIS:
  1890                         ret = sym;  // self represented
  1891                         break;
  1892                     case TYPE_VAR:
  1893                         // Just erase the type var
  1894                         ret = new VarSymbol(sym.flags(), sym.name,
  1895                                 types.erasure(sym.type), sym.owner);
  1897                         /* this information should also be kept for LVT generation at Gen
  1898                          * a Symbol with pos < startPos won't be tracked.
  1899                          */
  1900                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
  1901                         break;
  1902                     case CAPTURED_VAR:
  1903                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
  1904                             @Override
  1905                             public Symbol baseSymbol() {
  1906                                 //keep mapping with original captured symbol
  1907                                 return sym;
  1909                         };
  1910                         break;
  1911                     case LOCAL_VAR:
  1912                         ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
  1913                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1914                         break;
  1915                     case PARAM:
  1916                         ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym);
  1917                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1918                         break;
  1919                     default:
  1920                         Assert.error(skind.name());
  1921                         throw new AssertionError();
  1923                 if (ret != sym) {
  1924                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1925                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1927                 return ret;
  1930             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1931                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
  1932                 if (!transMap.containsKey(sym)) {
  1933                     transMap.put(sym, translate(sym, skind));
  1937             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
  1938                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
  1939                 Assert.checkNonNull(m);
  1940                 return m;
  1943             JCTree translate(JCIdent lambdaIdent) {
  1944                 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
  1945                     if (m.containsKey(lambdaIdent.sym)) {
  1946                         Symbol tSym = m.get(lambdaIdent.sym);
  1947                         JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
  1948                         tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
  1949                         return t;
  1952                 return null;
  1955             /**
  1956              * The translatedSym is not complete/accurate until the analysis is
  1957              * finished.  Once the analysis is finished, the translatedSym is
  1958              * "completed" -- updated with type information, access modifiers,
  1959              * and full parameter list.
  1960              */
  1961             void complete() {
  1962                 if (syntheticParams != null) {
  1963                     return;
  1965                 boolean inInterface = translatedSym.owner.isInterface();
  1966                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1968                 // If instance access isn't needed, make it static.
  1969                 // Interface instance methods must be default methods.
  1970                 // Lambda methods are private synthetic.
  1971                 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
  1972                 // from the class.
  1973                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
  1974                         owner.flags_field & STRICTFP |
  1975                         owner.owner.flags_field & STRICTFP |
  1976                         PRIVATE |
  1977                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  1979                 //compute synthetic params
  1980                 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
  1981                 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>();
  1983                 // The signature of the method is augmented with the following
  1984                 // synthetic parameters:
  1985                 //
  1986                 // 1) reference to enclosing contexts captured by the lambda expression
  1987                 // 2) enclosing locals captured by the lambda expression
  1988                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
  1989                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1990                     parameterSymbols.append((VarSymbol) thisSym);
  1992                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
  1993                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1994                     parameterSymbols.append((VarSymbol) thisSym);
  1996                 syntheticParams = params.toList();
  1998                 translatedSym.params = parameterSymbols.toList();
  2000                 // Compute and set the lambda name
  2001                 translatedSym.name = isSerializable()
  2002                         ? serializedLambdaName()
  2003                         : lambdaName();
  2005                 //prepend synthetic args to translated lambda method signature
  2006                 translatedSym.type = types.createMethodTypeWithParameters(
  2007                         generatedLambdaSig(),
  2008                         TreeInfo.types(syntheticParams));
  2011             Type generatedLambdaSig() {
  2012                 return types.erasure(tree.getDescriptorType(types));
  2016         /**
  2017          * This class retains all the useful information about a method reference;
  2018          * the contents of this class are filled by the LambdaAnalyzer visitor,
  2019          * and the used by the main translation routines in order to adjust method
  2020          * references (i.e. in case a bridge is needed)
  2021          */
  2022         private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  2024             final boolean isSuper;
  2025             final Symbol sigPolySym;
  2027             ReferenceTranslationContext(JCMemberReference tree) {
  2028                 super(tree);
  2029                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2030                 this.sigPolySym = isSignaturePolymorphic()
  2031                         ? makePrivateSyntheticMethod(tree.sym.flags(),
  2032                                               tree.sym.name,
  2033                                               bridgedRefSig(),
  2034                                               tree.sym.enclClass())
  2035                         : null;
  2038             /**
  2039              * Get the opcode associated with this method reference
  2040              */
  2041             int referenceKind() {
  2042                 return LambdaToMethod.this.referenceKind(tree.sym);
  2045             boolean needsVarArgsConversion() {
  2046                 return tree.varargsElement != null;
  2049             /**
  2050              * @return Is this an array operation like clone()
  2051              */
  2052             boolean isArrayOp() {
  2053                 return tree.sym.owner == syms.arrayClass;
  2056             boolean receiverAccessible() {
  2057                 //hack needed to workaround 292 bug (7087658)
  2058                 //when 292 issue is fixed we should remove this and change the backend
  2059                 //code to always generate a method handle to an accessible method
  2060                 return tree.ownerAccessible;
  2063             /**
  2064              * The VM does not support access across nested classes (8010319).
  2065              * Were that ever to change, this should be removed.
  2066              */
  2067             boolean isPrivateInOtherClass() {
  2068                 return  (tree.sym.flags() & PRIVATE) != 0 &&
  2069                         !types.isSameType(
  2070                               types.erasure(tree.sym.enclClass().asType()),
  2071                               types.erasure(owner.enclClass().asType()));
  2074             /**
  2075              * Signature polymorphic methods need special handling.
  2076              * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
  2077              */
  2078             final boolean isSignaturePolymorphic() {
  2079                 return  tree.sym.kind == MTH &&
  2080                         types.isSignaturePolymorphic((MethodSymbol)tree.sym);
  2083             /**
  2084              * Erasure destroys the implementation parameter subtype
  2085              * relationship for intersection types
  2086              */
  2087             boolean interfaceParameterIsIntersectionType() {
  2088                 List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
  2089                 if (tree.kind == ReferenceKind.UNBOUND) {
  2090                     tl = tl.tail;
  2092                 for (; tl.nonEmpty(); tl = tl.tail) {
  2093                     Type pt = tl.head;
  2094                     if (pt.getKind() == TypeKind.TYPEVAR) {
  2095                         TypeVar tv = (TypeVar) pt;
  2096                         if (tv.bound.getKind() == TypeKind.INTERSECTION) {
  2097                             return true;
  2101                 return false;
  2104             /**
  2105              * Does this reference need to be converted to a lambda
  2106              * (i.e. var args need to be expanded or "super" is used)
  2107              */
  2108             final boolean needsConversionToLambda() {
  2109                 return interfaceParameterIsIntersectionType() ||
  2110                         isSuper ||
  2111                         needsVarArgsConversion() ||
  2112                         isArrayOp() ||
  2113                         isPrivateInOtherClass() ||
  2114                         !receiverAccessible() ||
  2115                         (tree.getMode() == ReferenceMode.NEW &&
  2116                           tree.kind != ReferenceKind.ARRAY_CTOR &&
  2117                           (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
  2120             Type generatedRefSig() {
  2121                 return types.erasure(tree.sym.type);
  2124             Type bridgedRefSig() {
  2125                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  2129     // </editor-fold>
  2131     /*
  2132      * These keys provide mappings for various translated lambda symbols
  2133      * and the prevailing order must be maintained.
  2134      */
  2135     enum LambdaSymbolKind {
  2136         PARAM,          // original to translated lambda parameters
  2137         LOCAL_VAR,      // original to translated lambda locals
  2138         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
  2139         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
  2140         TYPE_VAR;       // original to translated lambda type variables
  2143     /**
  2144      * ****************************************************************
  2145      * Signature Generation
  2146      * ****************************************************************
  2147      */
  2149     private String typeSig(Type type) {
  2150         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2151         sg.assembleSig(type);
  2152         return sg.toString();
  2155     private String classSig(Type type) {
  2156         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2157         sg.assembleClassSig(type);
  2158         return sg.toString();
  2161     /**
  2162      * Signature Generation
  2163      */
  2164     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  2166         /**
  2167          * An output buffer for type signatures.
  2168          */
  2169         StringBuilder sb = new StringBuilder();
  2171         L2MSignatureGenerator() {
  2172             super(types);
  2175         @Override
  2176         protected void append(char ch) {
  2177             sb.append(ch);
  2180         @Override
  2181         protected void append(byte[] ba) {
  2182             sb.append(new String(ba));
  2185         @Override
  2186         protected void append(Name name) {
  2187             sb.append(name.toString());
  2190         @Override
  2191         public String toString() {
  2192             return sb.toString();

mercurial