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

Wed, 16 Sep 2015 10:56:23 +0200

author
jlahoda
date
Wed, 16 Sep 2015 10:56:23 +0200
changeset 3111
51997141b15c
parent 2701
6906fc8bc514
child 2702
9ca8d8713094
child 3113
0d7fcabf56ed
permissions
-rw-r--r--

8067422: Lambda method names are unnecessarily unstable
Summary: Lambda method numbers are now assigned per class for non-serializable lambdas.
Reviewed-by: mcimadamore, rfield, vromero

     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 = (MethodSymbol)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             int prevLambdaCount = lambdaCount;
  1183             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
  1184                     syntheticMethodNameCounts;
  1185             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1186             DiagnosticSource prevSource = log.currentSource();
  1187             try {
  1188                 log.useSource(tree.sym.sourcefile);
  1189                 lambdaCount = 0;
  1190                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
  1191                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1192                 if (tree.sym.owner.kind == MTH) {
  1193                     localClassDefs.put(tree.sym, tree);
  1195                 if (directlyEnclosingLambda() != null) {
  1196                     tree.sym.owner = owner();
  1197                     if (tree.sym.hasOuterInstance()) {
  1198                         //if a class is defined within a lambda, the lambda must capture
  1199                         //its enclosing instance (if any)
  1200                         TranslationContext<?> localContext = context();
  1201                         while (localContext != null) {
  1202                             if (localContext.tree.getTag() == LAMBDA) {
  1203                                 ((LambdaTranslationContext)localContext)
  1204                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1206                             localContext = localContext.prev;
  1210                 frameStack = frameStack.prepend(new Frame(tree));
  1211                 super.visitClassDef(tree);
  1213             finally {
  1214                 log.useSource(prevSource.getFile());
  1215                 frameStack = prevStack;
  1216                 lambdaCount = prevLambdaCount;
  1217                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
  1218                 clinits = prevClinits;
  1222         @Override
  1223         public void visitIdent(JCIdent tree) {
  1224             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1225                 if (tree.sym.kind == VAR &&
  1226                         tree.sym.owner.kind == MTH &&
  1227                         tree.type.constValue() == null) {
  1228                     TranslationContext<?> localContext = context();
  1229                     while (localContext != null) {
  1230                         if (localContext.tree.getTag() == LAMBDA) {
  1231                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1232                             if (block == null) break;
  1233                             ((LambdaTranslationContext)localContext)
  1234                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1236                         localContext = localContext.prev;
  1238                 } else if (tree.sym.owner.kind == TYP) {
  1239                     TranslationContext<?> localContext = context();
  1240                     while (localContext != null) {
  1241                         if (localContext.tree.hasTag(LAMBDA)) {
  1242                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1243                             if (block == null) break;
  1244                             switch (block.getTag()) {
  1245                                 case CLASSDEF:
  1246                                     JCClassDecl cdecl = (JCClassDecl)block;
  1247                                     ((LambdaTranslationContext)localContext)
  1248                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1249                                     break;
  1250                                 default:
  1251                                     Assert.error("bad block kind");
  1254                         localContext = localContext.prev;
  1258             super.visitIdent(tree);
  1261         @Override
  1262         public void visitLambda(JCLambda tree) {
  1263             analyzeLambda(tree, "lambda.stat");
  1266         private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) {
  1267             // Translation of the receiver expression must occur first
  1268             JCExpression rcvr = translate(methodReferenceReceiver);
  1269             LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1");
  1270             if (rcvr != null) {
  1271                 context.methodReferenceReceiver = rcvr;
  1275         private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) {
  1276             List<Frame> prevStack = frameStack;
  1277             try {
  1278                 LambdaTranslationContext context = new LambdaTranslationContext(tree);
  1279                 if (dumpLambdaToMethodStats) {
  1280                     log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym);
  1282                 frameStack = frameStack.prepend(new Frame(tree));
  1283                 for (JCVariableDecl param : tree.params) {
  1284                     context.addSymbol(param.sym, PARAM);
  1285                     frameStack.head.addLocal(param.sym);
  1287                 contextMap.put(tree, context);
  1288                 super.visitLambda(tree);
  1289                 context.complete();
  1290                 return context;
  1292             finally {
  1293                 frameStack = prevStack;
  1297         @Override
  1298         public void visitMethodDef(JCMethodDecl tree) {
  1299             List<Frame> prevStack = frameStack;
  1300             try {
  1301                 frameStack = frameStack.prepend(new Frame(tree));
  1302                 super.visitMethodDef(tree);
  1304             finally {
  1305                 frameStack = prevStack;
  1309         @Override
  1310         public void visitNewClass(JCNewClass tree) {
  1311             TypeSymbol def = tree.type.tsym;
  1312             boolean inReferencedClass = currentlyInClass(def);
  1313             boolean isLocal = def.isLocal();
  1314             if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
  1315                 TranslationContext<?> localContext = context();
  1316                 while (localContext != null) {
  1317                     if (localContext.tree.getTag() == LAMBDA) {
  1318                         ((LambdaTranslationContext)localContext)
  1319                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1321                     localContext = localContext.prev;
  1324             if (context() != null && !inReferencedClass && isLocal) {
  1325                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1326                 captureLocalClassDefs(def, lambdaContext);
  1328             super.visitNewClass(tree);
  1330         //where
  1331             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1332                 JCClassDecl localCDef = localClassDefs.get(csym);
  1333                 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
  1334                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1335                         @Override
  1336                         void addFreeVars(ClassSymbol c) {
  1337                             captureLocalClassDefs(c, lambdaContext);
  1339                         @Override
  1340                         void visitSymbol(Symbol sym) {
  1341                             if (sym.kind == VAR &&
  1342                                     sym.owner.kind == MTH &&
  1343                                     ((VarSymbol)sym).getConstValue() == null) {
  1344                                 TranslationContext<?> localContext = context();
  1345                                 while (localContext != null) {
  1346                                     if (localContext.tree.getTag() == LAMBDA) {
  1347                                         JCTree block = capturedDecl(localContext.depth, sym);
  1348                                         if (block == null) break;
  1349                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1351                                     localContext = localContext.prev;
  1355                     };
  1356                     fvc.scan(localCDef);
  1359         //where
  1360         boolean currentlyInClass(Symbol csym) {
  1361             for (Frame frame : frameStack) {
  1362                 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
  1363                     JCClassDecl cdef = (JCClassDecl) frame.tree;
  1364                     if (cdef.sym == csym) {
  1365                         return true;
  1369             return false;
  1372         /**
  1373          * Method references to local class constructors, may, if the local
  1374          * class references local variables, have implicit constructor
  1375          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1376          * information added in the LambdaToMethod pass will have the wrong
  1377          * signature. Hooks between Lower and LambdaToMethod have been added to
  1378          * handle normal "new" in this case. This visitor converts potentially
  1379          * affected method references into a lambda containing a normal
  1380          * expression.
  1382          * @param tree
  1383          */
  1384         @Override
  1385         public void visitReference(JCMemberReference tree) {
  1386             ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree);
  1387             contextMap.put(tree, rcontext);
  1388             if (rcontext.needsConversionToLambda()) {
  1389                  // Convert to a lambda, and process as such
  1390                 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner());
  1391                 analyzeLambda(conv.lambda(), conv.getReceiverExpression());
  1392             } else {
  1393                 super.visitReference(tree);
  1394                 if (dumpLambdaToMethodStats) {
  1395                     log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null);
  1400         @Override
  1401         public void visitSelect(JCFieldAccess tree) {
  1402             if (context() != null && tree.sym.kind == VAR &&
  1403                         (tree.sym.name == names._this ||
  1404                          tree.sym.name == names._super)) {
  1405                 // A select of this or super means, if we are in a lambda,
  1406                 // we much have an instance context
  1407                 TranslationContext<?> localContext = context();
  1408                 while (localContext != null) {
  1409                     if (localContext.tree.hasTag(LAMBDA)) {
  1410                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1411                         if (clazz == null) break;
  1412                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1414                     localContext = localContext.prev;
  1417             super.visitSelect(tree);
  1420         @Override
  1421         public void visitVarDef(JCVariableDecl tree) {
  1422             TranslationContext<?> context = context();
  1423             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1424                     (LambdaTranslationContext)context :
  1425                     null;
  1426             if (ltc != null) {
  1427                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1428                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1430                 // Check for type variables (including as type arguments).
  1431                 // If they occur within class nested in a lambda, mark for erasure
  1432                 Type type = tree.sym.asType();
  1433                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1434                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1438             List<Frame> prevStack = frameStack;
  1439             try {
  1440                 if (tree.sym.owner.kind == MTH) {
  1441                     frameStack.head.addLocal(tree.sym);
  1443                 frameStack = frameStack.prepend(new Frame(tree));
  1444                 super.visitVarDef(tree);
  1446             finally {
  1447                 frameStack = prevStack;
  1451         /**
  1452          * Return a valid owner given the current declaration stack
  1453          * (required to skip synthetic lambda symbols)
  1454          */
  1455         private Symbol owner() {
  1456             return owner(false);
  1459         @SuppressWarnings("fallthrough")
  1460         private Symbol owner(boolean skipLambda) {
  1461             List<Frame> frameStack2 = frameStack;
  1462             while (frameStack2.nonEmpty()) {
  1463                 switch (frameStack2.head.tree.getTag()) {
  1464                     case VARDEF:
  1465                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1466                             frameStack2 = frameStack2.tail;
  1467                             break;
  1469                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1470                         return initSym(cdecl.sym,
  1471                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1472                     case BLOCK:
  1473                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1474                         return initSym(cdecl2.sym,
  1475                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1476                     case CLASSDEF:
  1477                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1478                     case METHODDEF:
  1479                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1480                     case LAMBDA:
  1481                         if (!skipLambda)
  1482                             return ((LambdaTranslationContext)contextMap
  1483                                     .get(frameStack2.head.tree)).translatedSym;
  1484                     default:
  1485                         frameStack2 = frameStack2.tail;
  1488             Assert.error();
  1489             return null;
  1492         private Symbol initSym(ClassSymbol csym, long flags) {
  1493             boolean isStatic = (flags & STATIC) != 0;
  1494             if (isStatic) {
  1495                 /* static clinits are generated in Gen, so we need to use a fake
  1496                  * one. Attr creates a fake clinit method while attributing
  1497                  * lambda expressions used as initializers of static fields, so
  1498                  * let's use that one.
  1499                  */
  1500                 MethodSymbol clinit = attr.removeClinit(csym);
  1501                 if (clinit != null) {
  1502                     clinits.put(csym, clinit);
  1503                     return clinit;
  1506                 /* if no clinit is found at Attr, then let's try at clinits.
  1507                  */
  1508                 clinit = (MethodSymbol)clinits.get(csym);
  1509                 if (clinit == null) {
  1510                     /* no luck, let's create a new one
  1511                      */
  1512                     clinit = makePrivateSyntheticMethod(STATIC,
  1513                             names.clinit,
  1514                             new MethodType(List.<Type>nil(), syms.voidType,
  1515                                 List.<Type>nil(), syms.methodClass),
  1516                             csym);
  1517                     clinits.put(csym, clinit);
  1519                 return clinit;
  1520             } else {
  1521                 //get the first constructor and treat it as the instance init sym
  1522                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1523                     return s;
  1526             Assert.error("init not found");
  1527             return null;
  1530         private JCTree directlyEnclosingLambda() {
  1531             if (frameStack.isEmpty()) {
  1532                 return null;
  1534             List<Frame> frameStack2 = frameStack;
  1535             while (frameStack2.nonEmpty()) {
  1536                 switch (frameStack2.head.tree.getTag()) {
  1537                     case CLASSDEF:
  1538                     case METHODDEF:
  1539                         return null;
  1540                     case LAMBDA:
  1541                         return frameStack2.head.tree;
  1542                     default:
  1543                         frameStack2 = frameStack2.tail;
  1546             Assert.error();
  1547             return null;
  1550         private boolean inClassWithinLambda() {
  1551             if (frameStack.isEmpty()) {
  1552                 return false;
  1554             List<Frame> frameStack2 = frameStack;
  1555             boolean classFound = false;
  1556             while (frameStack2.nonEmpty()) {
  1557                 switch (frameStack2.head.tree.getTag()) {
  1558                     case LAMBDA:
  1559                         return classFound;
  1560                     case CLASSDEF:
  1561                         classFound = true;
  1562                         frameStack2 = frameStack2.tail;
  1563                         break;
  1564                     default:
  1565                         frameStack2 = frameStack2.tail;
  1568             // No lambda
  1569             return false;
  1572         /**
  1573          * Return the declaration corresponding to a symbol in the enclosing
  1574          * scope; the depth parameter is used to filter out symbols defined
  1575          * in nested scopes (which do not need to undergo capture).
  1576          */
  1577         private JCTree capturedDecl(int depth, Symbol sym) {
  1578             int currentDepth = frameStack.size() - 1;
  1579             for (Frame block : frameStack) {
  1580                 switch (block.tree.getTag()) {
  1581                     case CLASSDEF:
  1582                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1583                         if (sym.isMemberOf(clazz, types)) {
  1584                             return currentDepth > depth ? null : block.tree;
  1586                         break;
  1587                     case VARDEF:
  1588                         if (((JCVariableDecl)block.tree).sym == sym &&
  1589                                 sym.owner.kind == MTH) { //only locals are captured
  1590                             return currentDepth > depth ? null : block.tree;
  1592                         break;
  1593                     case BLOCK:
  1594                     case METHODDEF:
  1595                     case LAMBDA:
  1596                         if (block.locals != null && block.locals.contains(sym)) {
  1597                             return currentDepth > depth ? null : block.tree;
  1599                         break;
  1600                     default:
  1601                         Assert.error("bad decl kind " + block.tree.getTag());
  1603                 currentDepth--;
  1605             return null;
  1608         private TranslationContext<?> context() {
  1609             for (Frame frame : frameStack) {
  1610                 TranslationContext<?> context = contextMap.get(frame.tree);
  1611                 if (context != null) {
  1612                     return context;
  1615             return null;
  1618         /**
  1619          *  This is used to filter out those identifiers that needs to be adjusted
  1620          *  when translating away lambda expressions
  1621          */
  1622         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1623             return (sym.kind == VAR || sym.kind == MTH)
  1624                     && !sym.isStatic()
  1625                     && sym.name != names.init;
  1628         /**
  1629          * This is used to filter out those new class expressions that need to
  1630          * be qualified with an enclosing tree
  1631          */
  1632         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1633             if (context != null
  1634                     && tree.encl == null
  1635                     && tree.def == null
  1636                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1637                 Type encl = tree.type.getEnclosingType();
  1638                 Type current = context.owner.enclClass().type;
  1639                 while (!current.hasTag(NONE)) {
  1640                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1641                         return true;
  1643                     current = current.getEnclosingType();
  1645                 return false;
  1646             } else {
  1647                 return false;
  1651         private class Frame {
  1652             final JCTree tree;
  1653             List<Symbol> locals;
  1655             public Frame(JCTree tree) {
  1656                 this.tree = tree;
  1659             void addLocal(Symbol sym) {
  1660                 if (locals == null) {
  1661                     locals = List.nil();
  1663                 locals = locals.prepend(sym);
  1667         /**
  1668          * This class is used to store important information regarding translation of
  1669          * lambda expression/method references (see subclasses).
  1670          */
  1671         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1673             /** the underlying (untranslated) tree */
  1674             final T tree;
  1676             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1677             final Symbol owner;
  1679             /** the depth of this lambda expression in the frame stack */
  1680             final int depth;
  1682             /** the enclosing translation context (set for nested lambdas/mref) */
  1683             final TranslationContext<?> prev;
  1685             /** list of methods to be bridged by the meta-factory */
  1686             final List<Symbol> bridges;
  1688             TranslationContext(T tree) {
  1689                 this.tree = tree;
  1690                 this.owner = owner();
  1691                 this.depth = frameStack.size() - 1;
  1692                 this.prev = context();
  1693                 ClassSymbol csym =
  1694                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1695                 this.bridges = types.functionalInterfaceBridges(csym);
  1698             /** does this functional expression need to be created using alternate metafactory? */
  1699             boolean needsAltMetafactory() {
  1700                 return tree.targets.length() > 1 ||
  1701                         isSerializable() ||
  1702                         bridges.length() > 1;
  1705             /** does this functional expression require serialization support? */
  1706             boolean isSerializable() {
  1707                 if (forceSerializable) {
  1708                     return true;
  1710                 for (Type target : tree.targets) {
  1711                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1712                         return true;
  1715                 return false;
  1718             /**
  1719              * @return Name of the enclosing method to be folded into synthetic
  1720              * method name
  1721              */
  1722             String enclosingMethodName() {
  1723                 return syntheticMethodNameComponent(owner.name);
  1726             /**
  1727              * @return Method name in a form that can be folded into a
  1728              * component of a synthetic method name
  1729              */
  1730             String syntheticMethodNameComponent(Name name) {
  1731                 if (name == null) {
  1732                     return "null";
  1734                 String methodName = name.toString();
  1735                 if (methodName.equals("<clinit>")) {
  1736                     methodName = "static";
  1737                 } else if (methodName.equals("<init>")) {
  1738                     methodName = "new";
  1740                 return methodName;
  1744         /**
  1745          * This class retains all the useful information about a lambda expression;
  1746          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1747          * and the used by the main translation routines in order to adjust references
  1748          * to captured locals/members, etc.
  1749          */
  1750         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1752             /** variable in the enclosing context to which this lambda is assigned */
  1753             final Symbol self;
  1755             /** variable in the enclosing context to which this lambda is assigned */
  1756             final Symbol assignedTo;
  1758             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
  1760             /** the synthetic symbol for the method hoisting the translated lambda */
  1761             Symbol translatedSym;
  1763             List<JCVariableDecl> syntheticParams;
  1765             /**
  1766              * to prevent recursion, track local classes processed
  1767              */
  1768             final Set<Symbol> freeVarProcessedLocalClasses;
  1770             /**
  1771              * For method references converted to lambdas.  The method
  1772              * reference receiver expression. Must be treated like a captured
  1773              * variable.
  1774              */
  1775             JCExpression methodReferenceReceiver;
  1777             LambdaTranslationContext(JCLambda tree) {
  1778                 super(tree);
  1779                 Frame frame = frameStack.head;
  1780                 switch (frame.tree.getTag()) {
  1781                     case VARDEF:
  1782                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
  1783                         break;
  1784                     case ASSIGN:
  1785                         self = null;
  1786                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
  1787                         break;
  1788                     default:
  1789                         assignedTo = self = null;
  1790                         break;
  1793                 // This symbol will be filled-in in complete
  1794                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
  1796                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
  1798                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
  1799                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
  1800                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
  1801                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
  1802                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
  1804                 freeVarProcessedLocalClasses = new HashSet<>();
  1807              /**
  1808              * For a serializable lambda, generate a disambiguating string
  1809              * which maximizes stability across deserialization.
  1811              * @return String to differentiate synthetic lambda method names
  1812              */
  1813             private String serializedLambdaDisambiguation() {
  1814                 StringBuilder buf = new StringBuilder();
  1815                 // Append the enclosing method signature to differentiate
  1816                 // overloaded enclosing methods.  For lambdas enclosed in
  1817                 // lambdas, the generated lambda method will not have type yet,
  1818                 // but the enclosing method's name will have been generated
  1819                 // with this same method, so it will be unique and never be
  1820                 // overloaded.
  1821                 Assert.check(
  1822                         owner.type != null ||
  1823                         directlyEnclosingLambda() != null);
  1824                 if (owner.type != null) {
  1825                     buf.append(typeSig(owner.type));
  1826                     buf.append(":");
  1829                 // Add target type info
  1830                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
  1831                 buf.append(" ");
  1833                 // Add variable assigned to
  1834                 if (assignedTo != null) {
  1835                     buf.append(assignedTo.flatName());
  1836                     buf.append("=");
  1838                 //add captured locals info: type, name, order
  1839                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
  1840                     if (fv != self) {
  1841                         buf.append(typeSig(fv.type));
  1842                         buf.append(" ");
  1843                         buf.append(fv.flatName());
  1844                         buf.append(",");
  1848                 return buf.toString();
  1851             /**
  1852              * For a non-serializable lambda, generate a simple method.
  1854              * @return Name to use for the synthetic lambda method name
  1855              */
  1856             private Name lambdaName() {
  1857                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
  1860             /**
  1861              * For a serializable lambda, generate a method name which maximizes
  1862              * name stability across deserialization.
  1864              * @return Name to use for the synthetic lambda method name
  1865              */
  1866             private Name serializedLambdaName() {
  1867                 StringBuilder buf = new StringBuilder();
  1868                 buf.append(names.lambda);
  1869                 // Append the name of the method enclosing the lambda.
  1870                 buf.append(enclosingMethodName());
  1871                 buf.append('$');
  1872                 // Append a hash of the disambiguating string : enclosing method
  1873                 // signature, etc.
  1874                 String disam = serializedLambdaDisambiguation();
  1875                 buf.append(Integer.toHexString(disam.hashCode()));
  1876                 buf.append('$');
  1877                 // The above appended name components may not be unique, append
  1878                 // a count based on the above name components.
  1879                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  1880                 String result = buf.toString();
  1881                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
  1882                 return names.fromString(result);
  1885             /**
  1886              * Translate a symbol of a given kind into something suitable for the
  1887              * synthetic lambda body
  1888              */
  1889             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1890                 Symbol ret;
  1891                 switch (skind) {
  1892                     case CAPTURED_THIS:
  1893                         ret = sym;  // self represented
  1894                         break;
  1895                     case TYPE_VAR:
  1896                         // Just erase the type var
  1897                         ret = new VarSymbol(sym.flags(), name,
  1898                                 types.erasure(sym.type), sym.owner);
  1900                         /* this information should also be kept for LVT generation at Gen
  1901                          * a Symbol with pos < startPos won't be tracked.
  1902                          */
  1903                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
  1904                         break;
  1905                     case CAPTURED_VAR:
  1906                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
  1907                             @Override
  1908                             public Symbol baseSymbol() {
  1909                                 //keep mapping with original captured symbol
  1910                                 return sym;
  1912                         };
  1913                         break;
  1914                     case LOCAL_VAR:
  1915                         ret = new VarSymbol(sym.flags() & FINAL, name, sym.type, translatedSym);
  1916                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1917                         break;
  1918                     case PARAM:
  1919                         ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, name, types.erasure(sym.type), translatedSym);
  1920                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1921                         break;
  1922                     default:
  1923                         ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1924                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1926                 if (ret != sym) {
  1927                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1928                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1930                 return ret;
  1933             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1934                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
  1935                 Name preferredName;
  1936                 switch (skind) {
  1937                     case CAPTURED_THIS:
  1938                         preferredName = names.fromString("encl$" + transMap.size());
  1939                         break;
  1940                     case CAPTURED_VAR:
  1941                         preferredName = names.fromString("cap$" + transMap.size());
  1942                         break;
  1943                     case LOCAL_VAR:
  1944                         preferredName = sym.name;
  1945                         break;
  1946                     case PARAM:
  1947                         preferredName = sym.name;
  1948                         break;
  1949                     case TYPE_VAR:
  1950                         preferredName = sym.name;
  1951                         break;
  1952                     default: throw new AssertionError();
  1954                 if (!transMap.containsKey(sym)) {
  1955                     transMap.put(sym, translate(preferredName, sym, skind));
  1959             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
  1960                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
  1961                 Assert.checkNonNull(m);
  1962                 return m;
  1965             JCTree translate(JCIdent lambdaIdent) {
  1966                 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
  1967                     if (m.containsKey(lambdaIdent.sym)) {
  1968                         Symbol tSym = m.get(lambdaIdent.sym);
  1969                         JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
  1970                         tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
  1971                         return t;
  1974                 return null;
  1977             /**
  1978              * The translatedSym is not complete/accurate until the analysis is
  1979              * finished.  Once the analysis is finished, the translatedSym is
  1980              * "completed" -- updated with type information, access modifiers,
  1981              * and full parameter list.
  1982              */
  1983             void complete() {
  1984                 if (syntheticParams != null) {
  1985                     return;
  1987                 boolean inInterface = translatedSym.owner.isInterface();
  1988                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1990                 // If instance access isn't needed, make it static.
  1991                 // Interface instance methods must be default methods.
  1992                 // Lambda methods are private synthetic.
  1993                 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
  1994                 // from the class.
  1995                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
  1996                         owner.flags_field & STRICTFP |
  1997                         owner.owner.flags_field & STRICTFP |
  1998                         PRIVATE |
  1999                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  2001                 //compute synthetic params
  2002                 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
  2004                 // The signature of the method is augmented with the following
  2005                 // synthetic parameters:
  2006                 //
  2007                 // 1) reference to enclosing contexts captured by the lambda expression
  2008                 // 2) enclosing locals captured by the lambda expression
  2009                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
  2010                     params.append(make.VarDef((VarSymbol) thisSym, null));
  2012                 if (methodReferenceReceiver != null) {
  2013                     params.append(make.VarDef(
  2014                             make.Modifiers(PARAMETER|FINAL),
  2015                             names.fromString("$rcvr$"),
  2016                             make.Type(methodReferenceReceiver.type),
  2017                             null));
  2019                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
  2020                     params.append(make.VarDef((VarSymbol) thisSym, null));
  2022                 syntheticParams = params.toList();
  2024                 // Compute and set the lambda name
  2025                 translatedSym.name = isSerializable()
  2026                         ? serializedLambdaName()
  2027                         : lambdaName();
  2029                 //prepend synthetic args to translated lambda method signature
  2030                 translatedSym.type = types.createMethodTypeWithParameters(
  2031                         generatedLambdaSig(),
  2032                         TreeInfo.types(syntheticParams));
  2035             Type generatedLambdaSig() {
  2036                 return types.erasure(tree.getDescriptorType(types));
  2040         /**
  2041          * This class retains all the useful information about a method reference;
  2042          * the contents of this class are filled by the LambdaAnalyzer visitor,
  2043          * and the used by the main translation routines in order to adjust method
  2044          * references (i.e. in case a bridge is needed)
  2045          */
  2046         private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  2048             final boolean isSuper;
  2049             final Symbol sigPolySym;
  2051             ReferenceTranslationContext(JCMemberReference tree) {
  2052                 super(tree);
  2053                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2054                 this.sigPolySym = isSignaturePolymorphic()
  2055                         ? makePrivateSyntheticMethod(tree.sym.flags(),
  2056                                               tree.sym.name,
  2057                                               bridgedRefSig(),
  2058                                               tree.sym.enclClass())
  2059                         : null;
  2062             /**
  2063              * Get the opcode associated with this method reference
  2064              */
  2065             int referenceKind() {
  2066                 return LambdaToMethod.this.referenceKind(tree.sym);
  2069             boolean needsVarArgsConversion() {
  2070                 return tree.varargsElement != null;
  2073             /**
  2074              * @return Is this an array operation like clone()
  2075              */
  2076             boolean isArrayOp() {
  2077                 return tree.sym.owner == syms.arrayClass;
  2080             boolean receiverAccessible() {
  2081                 //hack needed to workaround 292 bug (7087658)
  2082                 //when 292 issue is fixed we should remove this and change the backend
  2083                 //code to always generate a method handle to an accessible method
  2084                 return tree.ownerAccessible;
  2087             /**
  2088              * The VM does not support access across nested classes (8010319).
  2089              * Were that ever to change, this should be removed.
  2090              */
  2091             boolean isPrivateInOtherClass() {
  2092                 return  (tree.sym.flags() & PRIVATE) != 0 &&
  2093                         !types.isSameType(
  2094                               types.erasure(tree.sym.enclClass().asType()),
  2095                               types.erasure(owner.enclClass().asType()));
  2098             /**
  2099              * Signature polymorphic methods need special handling.
  2100              * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
  2101              */
  2102             final boolean isSignaturePolymorphic() {
  2103                 return  tree.sym.kind == MTH &&
  2104                         types.isSignaturePolymorphic((MethodSymbol)tree.sym);
  2107             /**
  2108              * Erasure destroys the implementation parameter subtype
  2109              * relationship for intersection types
  2110              */
  2111             boolean interfaceParameterIsIntersectionType() {
  2112                 List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
  2113                 if (tree.kind == ReferenceKind.UNBOUND) {
  2114                     tl = tl.tail;
  2116                 for (; tl.nonEmpty(); tl = tl.tail) {
  2117                     Type pt = tl.head;
  2118                     if (pt.getKind() == TypeKind.TYPEVAR) {
  2119                         TypeVar tv = (TypeVar) pt;
  2120                         if (tv.bound.getKind() == TypeKind.INTERSECTION) {
  2121                             return true;
  2125                 return false;
  2128             /**
  2129              * Does this reference need to be converted to a lambda
  2130              * (i.e. var args need to be expanded or "super" is used)
  2131              */
  2132             final boolean needsConversionToLambda() {
  2133                 return interfaceParameterIsIntersectionType() ||
  2134                         isSuper ||
  2135                         needsVarArgsConversion() ||
  2136                         isArrayOp() ||
  2137                         isPrivateInOtherClass() ||
  2138                         !receiverAccessible() ||
  2139                         (tree.getMode() == ReferenceMode.NEW &&
  2140                           tree.kind != ReferenceKind.ARRAY_CTOR &&
  2141                           (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
  2144             Type generatedRefSig() {
  2145                 return types.erasure(tree.sym.type);
  2148             Type bridgedRefSig() {
  2149                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  2153     // </editor-fold>
  2155     /*
  2156      * These keys provide mappings for various translated lambda symbols
  2157      * and the prevailing order must be maintained.
  2158      */
  2159     enum LambdaSymbolKind {
  2160         PARAM,          // original to translated lambda parameters
  2161         LOCAL_VAR,      // original to translated lambda locals
  2162         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
  2163         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
  2164         TYPE_VAR;       // original to translated lambda type variables
  2167     /**
  2168      * ****************************************************************
  2169      * Signature Generation
  2170      * ****************************************************************
  2171      */
  2173     private String typeSig(Type type) {
  2174         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2175         sg.assembleSig(type);
  2176         return sg.toString();
  2179     private String classSig(Type type) {
  2180         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2181         sg.assembleClassSig(type);
  2182         return sg.toString();
  2185     /**
  2186      * Signature Generation
  2187      */
  2188     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  2190         /**
  2191          * An output buffer for type signatures.
  2192          */
  2193         StringBuilder sb = new StringBuilder();
  2195         L2MSignatureGenerator() {
  2196             super(types);
  2199         @Override
  2200         protected void append(char ch) {
  2201             sb.append(ch);
  2204         @Override
  2205         protected void append(byte[] ba) {
  2206             sb.append(new String(ba));
  2209         @Override
  2210         protected void append(Name name) {
  2211             sb.append(name.toString());
  2214         @Override
  2215         public String toString() {
  2216             return sb.toString();

mercurial