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

Wed, 27 Apr 2016 01:34:52 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:34:52 +0800
changeset 0
959103a6100f
child 2525
2eb010b6cb22
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/langtools/
changeset: 2573:53ca196be1ae
tag: jdk8u25-b17

     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.Types;
    45 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
    46 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
    47 import com.sun.tools.javac.jvm.*;
    48 import com.sun.tools.javac.util.*;
    49 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    50 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
    52 import java.util.EnumMap;
    53 import java.util.HashMap;
    54 import java.util.HashSet;
    55 import java.util.LinkedHashMap;
    56 import java.util.Map;
    57 import java.util.Set;
    59 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
    60 import static com.sun.tools.javac.code.Flags.*;
    61 import static com.sun.tools.javac.code.Kinds.*;
    62 import static com.sun.tools.javac.code.TypeTag.*;
    63 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    65 /**
    66  * This pass desugars lambda expressions into static methods
    67  *
    68  *  <p><b>This is NOT part of any supported API.
    69  *  If you write code that depends on this, you do so at your own risk.
    70  *  This code and its internal interfaces are subject to change or
    71  *  deletion without notice.</b>
    72  */
    73 public class LambdaToMethod extends TreeTranslator {
    75     private Attr attr;
    76     private JCDiagnostic.Factory diags;
    77     private Log log;
    78     private Lower lower;
    79     private Names names;
    80     private Symtab syms;
    81     private Resolve rs;
    82     private TreeMaker make;
    83     private Types types;
    84     private TransTypes transTypes;
    85     private Env<AttrContext> attrEnv;
    87     /** the analyzer scanner */
    88     private LambdaAnalyzerPreprocessor analyzer;
    90     /** map from lambda trees to translation contexts */
    91     private Map<JCTree, TranslationContext<?>> contextMap;
    93     /** current translation context (visitor argument) */
    94     private TranslationContext<?> context;
    96     /** info about the current class being processed */
    97     private KlassInfo kInfo;
    99     /** dump statistics about lambda code generation */
   100     private boolean dumpLambdaToMethodStats;
   102     /** force serializable representation, for stress testing **/
   103     private final boolean forceSerializable;
   105     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
   106     public static final int FLAG_SERIALIZABLE = 1 << 0;
   108     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
   109     public static final int FLAG_MARKERS = 1 << 1;
   111     /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
   112     public static final int FLAG_BRIDGES = 1 << 2;
   114     // <editor-fold defaultstate="collapsed" desc="Instantiating">
   115     protected static final Context.Key<LambdaToMethod> unlambdaKey =
   116             new Context.Key<LambdaToMethod>();
   118     public static LambdaToMethod instance(Context context) {
   119         LambdaToMethod instance = context.get(unlambdaKey);
   120         if (instance == null) {
   121             instance = new LambdaToMethod(context);
   122         }
   123         return instance;
   124     }
   125     private LambdaToMethod(Context context) {
   126         context.put(unlambdaKey, this);
   127         diags = JCDiagnostic.Factory.instance(context);
   128         log = Log.instance(context);
   129         lower = Lower.instance(context);
   130         names = Names.instance(context);
   131         syms = Symtab.instance(context);
   132         rs = Resolve.instance(context);
   133         make = TreeMaker.instance(context);
   134         types = Types.instance(context);
   135         transTypes = TransTypes.instance(context);
   136         analyzer = new LambdaAnalyzerPreprocessor();
   137         Options options = Options.instance(context);
   138         dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats");
   139         attr = Attr.instance(context);
   140         forceSerializable = options.isSet("forceSerializable");
   141     }
   142     // </editor-fold>
   144     private class KlassInfo {
   146         /**
   147          * list of methods to append
   148          */
   149         private ListBuffer<JCTree> appendedMethodList;
   151         /**
   152          * list of deserialization cases
   153          */
   154         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   156        /**
   157          * deserialize method symbol
   158          */
   159         private final MethodSymbol deserMethodSym;
   161         /**
   162          * deserialize method parameter symbol
   163          */
   164         private final VarSymbol deserParamSym;
   166         private final JCClassDecl clazz;
   168         private KlassInfo(JCClassDecl clazz) {
   169             this.clazz = clazz;
   170             appendedMethodList = new ListBuffer<>();
   171             deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
   172             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
   173                     List.<Type>nil(), syms.methodClass);
   174             deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
   175             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
   176                     syms.serializedLambdaType, deserMethodSym);
   177         }
   179         private void addMethod(JCTree decl) {
   180             appendedMethodList = appendedMethodList.prepend(decl);
   181         }
   182     }
   184     // <editor-fold defaultstate="collapsed" desc="translate methods">
   185     @Override
   186     public <T extends JCTree> T translate(T tree) {
   187         TranslationContext<?> newContext = contextMap.get(tree);
   188         return translate(tree, newContext != null ? newContext : context);
   189     }
   191     <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
   192         TranslationContext<?> prevContext = context;
   193         try {
   194             context = newContext;
   195             return super.translate(tree);
   196         }
   197         finally {
   198             context = prevContext;
   199         }
   200     }
   202     <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
   203         ListBuffer<T> buf = new ListBuffer<>();
   204         for (T tree : trees) {
   205             buf.append(translate(tree, newContext));
   206         }
   207         return buf.toList();
   208     }
   210     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
   211         this.make = make;
   212         this.attrEnv = env;
   213         this.context = null;
   214         this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
   215         return translate(cdef);
   216     }
   217     // </editor-fold>
   219     // <editor-fold defaultstate="collapsed" desc="visitor methods">
   220     /**
   221      * Visit a class.
   222      * Maintain the translatedMethodList across nested classes.
   223      * Append the translatedMethodList to the class after it is translated.
   224      * @param tree
   225      */
   226     @Override
   227     public void visitClassDef(JCClassDecl tree) {
   228         if (tree.sym.owner.kind == PCK) {
   229             //analyze class
   230             tree = analyzer.analyzeAndPreprocessClass(tree);
   231         }
   232         KlassInfo prevKlassInfo = kInfo;
   233         try {
   234             kInfo = new KlassInfo(tree);
   235             super.visitClassDef(tree);
   236             if (!kInfo.deserializeCases.isEmpty()) {
   237                 int prevPos = make.pos;
   238                 try {
   239                     make.at(tree);
   240                     kInfo.addMethod(makeDeserializeMethod(tree.sym));
   241                 } finally {
   242                     make.at(prevPos);
   243                 }
   244             }
   245             //add all translated instance methods here
   246             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
   247             tree.defs = tree.defs.appendList(newMethods);
   248             for (JCTree lambda : newMethods) {
   249                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
   250             }
   251             result = tree;
   252         } finally {
   253             kInfo = prevKlassInfo;
   254         }
   255     }
   257     /**
   258      * Translate a lambda into a method to be inserted into the class.
   259      * Then replace the lambda site with an invokedynamic call of to lambda
   260      * meta-factory, which will use the lambda method.
   261      * @param tree
   262      */
   263     @Override
   264     public void visitLambda(JCLambda tree) {
   265         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
   266         MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
   267         MethodType lambdaType = (MethodType) sym.type;
   269         {
   270             Symbol owner = localContext.owner;
   271             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   272             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   274             for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
   275                 if (tc.position.onLambda == tree) {
   276                     lambdaTypeAnnos.append(tc);
   277                 } else {
   278                     ownerTypeAnnos.append(tc);
   279                 }
   280             }
   281             if (lambdaTypeAnnos.nonEmpty()) {
   282                 owner.setTypeAttributes(ownerTypeAnnos.toList());
   283                 sym.setTypeAttributes(lambdaTypeAnnos.toList());
   284             }
   285         }
   287         //create the method declaration hoisting the lambda body
   288         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
   289                 sym.name,
   290                 make.QualIdent(lambdaType.getReturnType().tsym),
   291                 List.<JCTypeParameter>nil(),
   292                 localContext.syntheticParams,
   293                 lambdaType.getThrownTypes() == null ?
   294                     List.<JCExpression>nil() :
   295                     make.Types(lambdaType.getThrownTypes()),
   296                 null,
   297                 null);
   298         lambdaDecl.sym = sym;
   299         lambdaDecl.type = lambdaType;
   301         //translate lambda body
   302         //As the lambda body is translated, all references to lambda locals,
   303         //captured variables, enclosing members are adjusted accordingly
   304         //to refer to the static method parameters (rather than i.e. acessing to
   305         //captured members directly).
   306         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
   308         //Add the method to the list of methods to be added to this class.
   309         kInfo.addMethod(lambdaDecl);
   311         //now that we have generated a method for the lambda expression,
   312         //we can translate the lambda into a method reference pointing to the newly
   313         //created method.
   314         //
   315         //Note that we need to adjust the method handle so that it will match the
   316         //signature of the SAM descriptor - this means that the method reference
   317         //should be added the following synthetic arguments:
   318         //
   319         // * the "this" argument if it is an instance method
   320         // * enclosing locals captured by the lambda expression
   322         ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
   324         if (!sym.isStatic()) {
   325             syntheticInits.append(makeThis(
   326                     sym.owner.enclClass().asType(),
   327                     localContext.owner.enclClass()));
   328         }
   330         //add captured locals
   331         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
   332             if (fv != localContext.self) {
   333                 JCTree captured_local = make.Ident(fv).setType(fv.type);
   334                 syntheticInits.append((JCExpression) captured_local);
   335             }
   336         }
   338         //then, determine the arguments to the indy call
   339         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   341         //build a sam instance using an indy call to the meta-factory
   342         int refKind = referenceKind(sym);
   344         //convert to an invokedynamic call
   345         result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
   346     }
   348     private JCIdent makeThis(Type type, Symbol owner) {
   349         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
   350                 names._this,
   351                 type,
   352                 owner);
   353         return make.Ident(_this);
   354     }
   356     /**
   357      * Translate a method reference into an invokedynamic call to the
   358      * meta-factory.
   359      * @param tree
   360      */
   361     @Override
   362     public void visitReference(JCMemberReference tree) {
   363         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   365         //first determine the method symbol to be used to generate the sam instance
   366         //this is either the method reference symbol, or the bridged reference symbol
   367         Symbol refSym = localContext.needsBridge()
   368                 ? localContext.bridgeSym
   369                 : localContext.isSignaturePolymorphic()
   370                 ? localContext.sigPolySym
   371                 : tree.sym;
   373         //build the bridge method, if needed
   374         if (localContext.needsBridge()) {
   375             bridgeMemberReference(tree, localContext);
   376         }
   378         //the qualifying expression is treated as a special captured arg
   379         JCExpression init;
   380         switch(tree.kind) {
   382             case IMPLICIT_INNER:    /** Inner :: new */
   383             case SUPER:             /** super :: instMethod */
   384                 init = makeThis(
   385                     localContext.owner.enclClass().asType(),
   386                     localContext.owner.enclClass());
   387                 break;
   389             case BOUND:             /** Expr :: instMethod */
   390                 init = tree.getQualifierExpression();
   391                 init = attr.makeNullCheck(init);
   392                 break;
   394             case UNBOUND:           /** Type :: instMethod */
   395             case STATIC:            /** Type :: staticMethod */
   396             case TOPLEVEL:          /** Top level :: new */
   397             case ARRAY_CTOR:        /** ArrayType :: new */
   398                 init = null;
   399                 break;
   401             default:
   402                 throw new InternalError("Should not have an invalid kind");
   403         }
   405         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
   408         //build a sam instance using an indy call to the meta-factory
   409         result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
   410     }
   412     /**
   413      * Translate identifiers within a lambda to the mapped identifier
   414      * @param tree
   415      */
   416     @Override
   417     public void visitIdent(JCIdent tree) {
   418         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
   419             super.visitIdent(tree);
   420         } else {
   421             int prevPos = make.pos;
   422             try {
   423                 make.at(tree);
   425                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
   426                 JCTree ltree = lambdaContext.translate(tree);
   427                 if (ltree != null) {
   428                     result = ltree;
   429                 } else {
   430                     //access to untranslated symbols (i.e. compile-time constants,
   431                     //members defined inside the lambda body, etc.) )
   432                     super.visitIdent(tree);
   433                 }
   434             } finally {
   435                 make.at(prevPos);
   436             }
   437         }
   438     }
   440     @Override
   441     public void visitVarDef(JCVariableDecl tree) {
   442         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
   443         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   444             tree.init = translate(tree.init);
   445             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
   446             result = tree;
   447         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   448             JCExpression init = translate(tree.init);
   449             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   450             int prevPos = make.pos;
   451             try {
   452                 result = make.at(tree).VarDef(xsym, init);
   453             } finally {
   454                 make.at(prevPos);
   455             }
   456             // Replace the entered symbol for this variable
   457             Scope sc = tree.sym.owner.members();
   458             if (sc != null) {
   459                 sc.remove(tree.sym);
   460                 sc.enter(xsym);
   461             }
   462         } else {
   463             super.visitVarDef(tree);
   464         }
   465     }
   467     // </editor-fold>
   469     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   471     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   472         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   473                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   474                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   475     }
   477     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   478         Type restype = lambdaMethodDecl.type.getReturnType();
   479         boolean isLambda_void = expr.type.hasTag(VOID);
   480         boolean isTarget_void = restype.hasTag(VOID);
   481         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   482         int prevPos = make.pos;
   483         try {
   484             if (isTarget_void) {
   485                 //target is void:
   486                 // BODY;
   487                 JCStatement stat = make.at(expr).Exec(expr);
   488                 return make.Block(0, List.<JCStatement>of(stat));
   489             } else if (isLambda_void && isTarget_Void) {
   490                 //void to Void conversion:
   491                 // BODY; return null;
   492                 ListBuffer<JCStatement> stats = new ListBuffer<>();
   493                 stats.append(make.at(expr).Exec(expr));
   494                 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   495                 return make.Block(0, stats.toList());
   496             } else {
   497                 //non-void to non-void conversion:
   498                 // return (TYPE)BODY;
   499                 JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   500                 return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
   501             }
   502         } finally {
   503             make.at(prevPos);
   504         }
   505     }
   507     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   508         final Type restype = lambdaMethodDecl.type.getReturnType();
   509         final boolean isTarget_void = restype.hasTag(VOID);
   510         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   512         class LambdaBodyTranslator extends TreeTranslator {
   514             @Override
   515             public void visitClassDef(JCClassDecl tree) {
   516                 //do NOT recurse on any inner classes
   517                 result = tree;
   518             }
   520             @Override
   521             public void visitLambda(JCLambda tree) {
   522                 //do NOT recurse on any nested lambdas
   523                 result = tree;
   524             }
   526             @Override
   527             public void visitReturn(JCReturn tree) {
   528                 boolean isLambda_void = tree.expr == null;
   529                 if (isTarget_void && !isLambda_void) {
   530                     //Void to void conversion:
   531                     // { TYPE $loc = RET-EXPR; return; }
   532                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   533                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   534                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   535                 } else if (!isTarget_void || !isLambda_void) {
   536                     //non-void to non-void conversion:
   537                     // return (TYPE)RET-EXPR;
   538                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   539                     result = tree;
   540                 } else {
   541                     result = tree;
   542                 }
   544             }
   545         }
   547         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   548         if (completeNormally && isTarget_Void) {
   549             //there's no return statement and the lambda (possibly inferred)
   550             //return type is java.lang.Void; emit a synthetic return statement
   551             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   552         }
   553         return trans_block;
   554     }
   556     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   557         ListBuffer<JCCase> cases = new ListBuffer<>();
   558         ListBuffer<JCBreak> breaks = new ListBuffer<>();
   559         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   560             JCBreak br = make.Break(null);
   561             breaks.add(br);
   562             List<JCStatement> stmts = entry.getValue().append(br).toList();
   563             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   564         }
   565         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   566         for (JCBreak br : breaks) {
   567             br.target = sw;
   568         }
   569         JCBlock body = make.Block(0L, List.<JCStatement>of(
   570                 sw,
   571                 make.Throw(makeNewClass(
   572                     syms.illegalArgumentExceptionType,
   573                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   574         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   575                         names.deserializeLambda,
   576                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   577                         List.<JCTypeParameter>nil(),
   578                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   579                         List.<JCExpression>nil(),
   580                         body,
   581                         null);
   582         deser.sym = kInfo.deserMethodSym;
   583         deser.type = kInfo.deserMethodSym.type;
   584         //System.err.printf("DESER: '%s'\n", deser);
   585         return deser;
   586     }
   588     /** Make an attributed class instance creation expression.
   589      *  @param ctype    The class type.
   590      *  @param args     The constructor arguments.
   591      *  @param cons     The constructor symbol
   592      */
   593     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
   594         JCNewClass tree = make.NewClass(null,
   595             null, make.QualIdent(ctype.tsym), args, null);
   596         tree.constructor = cons;
   597         tree.type = ctype;
   598         return tree;
   599     }
   601     /** Make an attributed class instance creation expression.
   602      *  @param ctype    The class type.
   603      *  @param args     The constructor arguments.
   604      */
   605     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   606         return makeNewClass(ctype, args,
   607                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
   608      }
   610     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   611             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   612         String functionalInterfaceClass = classSig(targetType);
   613         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   614         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
   615         String implClass = classSig(types.erasure(refSym.owner.type));
   616         String implMethodName = refSym.getQualifiedName().toString();
   617         String implMethodSignature = typeSig(types.erasure(refSym.type));
   619         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   620         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
   621         int i = 0;
   622         for (Type t : indyType.getParameterTypes()) {
   623             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
   624             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
   625             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   626             ++i;
   627         }
   628         JCStatement stmt = make.If(
   629                 deserTest(deserTest(deserTest(deserTest(deserTest(
   630                     kindTest,
   631                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   632                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   633                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   634                     "getImplClass", implClass),
   635                     "getImplMethodSignature", implMethodSignature),
   636                 make.Return(makeIndyCall(
   637                     pos,
   638                     syms.lambdaMetafactory,
   639                     names.altMetafactory,
   640                     staticArgs, indyType, serArgs.toList(), samSym.name)),
   641                 null);
   642         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   643         if (stmts == null) {
   644             stmts = new ListBuffer<>();
   645             kInfo.deserializeCases.put(implMethodName, stmts);
   646         }
   647         /****
   648         System.err.printf("+++++++++++++++++\n");
   649         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   650         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   651         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   652         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   653         System.err.printf("*implClass: '%s'\n", implClass);
   654         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   655         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   656         ****/
   657         stmts.append(stmt);
   658     }
   660     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   661         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   662         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   663         testExpr.setType(syms.booleanType);
   664         return testExpr;
   665     }
   667     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   668         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   669         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   670         JCMethodInvocation eqtest = make.Apply(
   671                 List.<JCExpression>nil(),
   672                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   673                 List.<JCExpression>of(make.Literal(lit)));
   674         eqtest.setType(syms.booleanType);
   675         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   676         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   677         compound.setType(syms.booleanType);
   678         return compound;
   679     }
   681     private JCExpression deserGetter(String func, Type type) {
   682         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   683     }
   685     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   686         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   687         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   688         return make.Apply(
   689                     List.<JCExpression>nil(),
   690                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   691                     args).setType(type);
   692     }
   694     /**
   695      * Create new synthetic method with given flags, name, type, owner
   696      */
   697     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   698         return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
   699     }
   701     /**
   702      * Create new synthetic variable with given flags, name, type, owner
   703      */
   704     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   705         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   706     }
   708     /**
   709      * Create new synthetic variable with given flags, name, type, owner
   710      */
   711     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   712         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   713     }
   715     /**
   716      * Set varargsElement field on a given tree (must be either a new class tree
   717      * or a method call tree)
   718      */
   719     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   720         if (varargsElement != null) {
   721             switch (tree.getTag()) {
   722                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   723                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   724                 default: throw new AssertionError();
   725             }
   726         }
   727     }
   729     /**
   730      * Convert method/constructor arguments by inserting appropriate cast
   731      * as required by type-erasure - this is needed when bridging a lambda/method
   732      * reference, as the bridged signature might require downcast to be compatible
   733      * with the generated signature.
   734      */
   735     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   736        Assert.check(meth.kind == Kinds.MTH);
   737        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   738        if (varargsElement != null) {
   739            Assert.check((meth.flags() & VARARGS) != 0);
   740        }
   741        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   742     }
   744     // </editor-fold>
   746     /**
   747      * Generate an adapter method "bridge" for a method reference which cannot
   748      * be used directly.
   749      */
   750     private class MemberReferenceBridger {
   752         private final JCMemberReference tree;
   753         private final ReferenceTranslationContext localContext;
   754         private final ListBuffer<JCExpression> args = new ListBuffer<>();
   755         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
   757         MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
   758             this.tree = tree;
   759             this.localContext = localContext;
   760         }
   762         /**
   763          * Generate the bridge
   764          */
   765         JCMethodDecl bridge() {
   766             int prevPos = make.pos;
   767             try {
   768                 make.at(tree);
   769                 Type samDesc = localContext.bridgedRefSig();
   770                 List<Type> samPTypes = samDesc.getParameterTypes();
   772                 //an extra argument is prepended to the signature of the bridge in case
   773                 //the member reference is an instance method reference (in which case
   774                 //the receiver expression is passed to the bridge itself).
   775                 Type recType = null;
   776                 switch (tree.kind) {
   777                     case IMPLICIT_INNER:
   778                         recType = tree.sym.owner.type.getEnclosingType();
   779                         break;
   780                     case BOUND:
   781                         recType = tree.getQualifierExpression().type;
   782                         break;
   783                     case UNBOUND:
   784                         recType = samPTypes.head;
   785                         samPTypes = samPTypes.tail;
   786                         break;
   787                 }
   789                 //generate the parameter list for the bridged member reference - the
   790                 //bridge signature will match the signature of the target sam descriptor
   792                 VarSymbol rcvr = (recType == null)
   793                         ? null
   794                         : addParameter("rec$", recType, false);
   796                 List<Type> refPTypes = tree.sym.type.getParameterTypes();
   797                 int refSize = refPTypes.size();
   798                 int samSize = samPTypes.size();
   799                 // Last parameter to copy from referenced method
   800                 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
   802                 List<Type> l = refPTypes;
   803                 // Use parameter types of the referenced method, excluding final var args
   804                 for (int i = 0; l.nonEmpty() && i < last; ++i) {
   805                     addParameter("x$" + i, l.head, true);
   806                     l = l.tail;
   807                 }
   808                 // Flatten out the var args
   809                 for (int i = last; i < samSize; ++i) {
   810                     addParameter("xva$" + i, tree.varargsElement, true);
   811                 }
   813                 //generate the bridge method declaration
   814                 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
   815                         localContext.bridgeSym.name,
   816                         make.QualIdent(samDesc.getReturnType().tsym),
   817                         List.<JCTypeParameter>nil(),
   818                         params.toList(),
   819                         tree.sym.type.getThrownTypes() == null
   820                         ? List.<JCExpression>nil()
   821                         : make.Types(tree.sym.type.getThrownTypes()),
   822                         null,
   823                         null);
   824                 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
   825                 bridgeDecl.type = localContext.bridgeSym.type =
   826                         types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
   828                 //bridge method body generation - this can be either a method call or a
   829                 //new instance creation expression, depending on the member reference kind
   830                 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
   831                         ? bridgeExpressionInvoke(makeReceiver(rcvr))
   832                         : bridgeExpressionNew();
   834                 //the body is either a return expression containing a method call,
   835                 //or the method call itself, depending on whether the return type of
   836                 //the bridge is non-void/void.
   837                 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
   839                 return bridgeDecl;
   840             } finally {
   841                 make.at(prevPos);
   842             }
   843         }
   844         //where
   845             private JCExpression makeReceiver(VarSymbol rcvr) {
   846                 if (rcvr == null) return null;
   847                 JCExpression rcvrExpr = make.Ident(rcvr);
   848                 Type rcvrType = tree.sym.enclClass().type;
   849                 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   850                     rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   851                 }
   852                 return rcvrExpr;
   853             }
   855         /**
   856          * determine the receiver of the bridged method call - the receiver can
   857          * be either the synthetic receiver parameter or a type qualifier; the
   858          * original qualifier expression is never used here, as it might refer
   859          * to symbols not available in the static context of the bridge
   860          */
   861         private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
   862             JCExpression qualifier =
   863                     tree.sym.isStatic() ?
   864                         make.Type(tree.sym.owner.type) :
   865                         (rcvr != null) ?
   866                             rcvr :
   867                             tree.getQualifierExpression();
   869             //create the qualifier expression
   870             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   871             select.sym = tree.sym;
   872             select.type = tree.sym.erasure(types);
   874             //create the method call expression
   875             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   876                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   877                     setType(tree.sym.erasure(types).getReturnType());
   879             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   880             setVarargsIfNeeded(apply, tree.varargsElement);
   881             return apply;
   882         }
   884         /**
   885          * the enclosing expression is either 'null' (no enclosing type) or set
   886          * to the first bridge synthetic parameter
   887          */
   888         private JCExpression bridgeExpressionNew() {
   889             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   890                 //create the array creation expression
   891                 JCNewArray newArr = make.NewArray(
   892                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   893                         List.of(make.Ident(params.first())),
   894                         null);
   895                 newArr.type = tree.getQualifierExpression().type;
   896                 return newArr;
   897             } else {
   898                 JCExpression encl = null;
   899                 switch (tree.kind) {
   900                     case UNBOUND:
   901                     case IMPLICIT_INNER:
   902                         encl = make.Ident(params.first());
   903                 }
   905                 //create the instance creation expression
   906                 JCNewClass newClass = make.NewClass(encl,
   907                         List.<JCExpression>nil(),
   908                         make.Type(tree.getQualifierExpression().type),
   909                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   910                         null);
   911                 newClass.constructor = tree.sym;
   912                 newClass.constructorType = tree.sym.erasure(types);
   913                 newClass.type = tree.getQualifierExpression().type;
   914                 setVarargsIfNeeded(newClass, tree.varargsElement);
   915                 return newClass;
   916             }
   917         }
   919         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   920             VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
   921             params.append(make.VarDef(vsym, null));
   922             if (genArg) {
   923                 args.append(make.Ident(vsym));
   924             }
   925             return vsym;
   926         }
   927     }
   929     /**
   930      * Bridges a member reference - this is needed when:
   931      * * Var args in the referenced method need to be flattened away
   932      * * super is used
   933      */
   934     private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
   935         kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
   936     }
   938     private MethodType typeToMethodType(Type mt) {
   939         Type type = types.erasure(mt);
   940         return new MethodType(type.getParameterTypes(),
   941                         type.getReturnType(),
   942                         type.getThrownTypes(),
   943                         syms.methodClass);
   944     }
   946     /**
   947      * Generate an indy method call to the meta factory
   948      */
   949     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
   950             int refKind, Symbol refSym, List<JCExpression> indy_args) {
   951         JCFunctionalExpression tree = context.tree;
   952         //determine the static bsm args
   953         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   954         List<Object> staticArgs = List.<Object>of(
   955                 typeToMethodType(samSym.type),
   956                 new Pool.MethodHandle(refKind, refSym, types),
   957                 typeToMethodType(tree.getDescriptorType(types)));
   959         //computed indy arg types
   960         ListBuffer<Type> indy_args_types = new ListBuffer<>();
   961         for (JCExpression arg : indy_args) {
   962             indy_args_types.append(arg.type);
   963         }
   965         //finally, compute the type of the indy call
   966         MethodType indyType = new MethodType(indy_args_types.toList(),
   967                 tree.type,
   968                 List.<Type>nil(),
   969                 syms.methodClass);
   971         Name metafactoryName = context.needsAltMetafactory() ?
   972                 names.altMetafactory : names.metafactory;
   974         if (context.needsAltMetafactory()) {
   975             ListBuffer<Object> markers = new ListBuffer<>();
   976             for (Type t : tree.targets.tail) {
   977                 if (t.tsym != syms.serializableType.tsym) {
   978                     markers.append(t.tsym);
   979                 }
   980             }
   981             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
   982             boolean hasMarkers = markers.nonEmpty();
   983             boolean hasBridges = context.bridges.nonEmpty();
   984             if (hasMarkers) {
   985                 flags |= FLAG_MARKERS;
   986             }
   987             if (hasBridges) {
   988                 flags |= FLAG_BRIDGES;
   989             }
   990             staticArgs = staticArgs.append(flags);
   991             if (hasMarkers) {
   992                 staticArgs = staticArgs.append(markers.length());
   993                 staticArgs = staticArgs.appendList(markers.toList());
   994             }
   995             if (hasBridges) {
   996                 staticArgs = staticArgs.append(context.bridges.length() - 1);
   997                 for (Symbol s : context.bridges) {
   998                     Type s_erasure = s.erasure(types);
   999                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
  1000                         staticArgs = staticArgs.append(s.erasure(types));
  1004             if (context.isSerializable()) {
  1005                 int prevPos = make.pos;
  1006                 try {
  1007                     make.at(kInfo.clazz);
  1008                     addDeserializationCase(refKind, refSym, tree.type, samSym,
  1009                             tree, staticArgs, indyType);
  1010                 } finally {
  1011                     make.at(prevPos);
  1016         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
  1019     /**
  1020      * Generate an indy method call with given name, type and static bootstrap
  1021      * arguments types
  1022      */
  1023     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
  1024             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
  1025             Name methName) {
  1026         int prevPos = make.pos;
  1027         try {
  1028             make.at(pos);
  1029             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
  1030                     syms.stringType,
  1031                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
  1033             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
  1034                     bsmName, bsm_staticArgs, List.<Type>nil());
  1036             DynamicMethodSymbol dynSym =
  1037                     new DynamicMethodSymbol(methName,
  1038                                             syms.noSymbol,
  1039                                             bsm.isStatic() ?
  1040                                                 ClassFile.REF_invokeStatic :
  1041                                                 ClassFile.REF_invokeVirtual,
  1042                                             (MethodSymbol)bsm,
  1043                                             indyType,
  1044                                             staticArgs.toArray());
  1046             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1047             qualifier.sym = dynSym;
  1048             qualifier.type = indyType.getReturnType();
  1050             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
  1051             proxyCall.type = indyType.getReturnType();
  1052             return proxyCall;
  1053         } finally {
  1054             make.at(prevPos);
  1057     //where
  1058     private List<Type> bsmStaticArgToTypes(List<Object> args) {
  1059         ListBuffer<Type> argtypes = new ListBuffer<>();
  1060         for (Object arg : args) {
  1061             argtypes.append(bsmStaticArgToType(arg));
  1063         return argtypes.toList();
  1066     private Type bsmStaticArgToType(Object arg) {
  1067         Assert.checkNonNull(arg);
  1068         if (arg instanceof ClassSymbol) {
  1069             return syms.classType;
  1070         } else if (arg instanceof Integer) {
  1071             return syms.intType;
  1072         } else if (arg instanceof Long) {
  1073             return syms.longType;
  1074         } else if (arg instanceof Float) {
  1075             return syms.floatType;
  1076         } else if (arg instanceof Double) {
  1077             return syms.doubleType;
  1078         } else if (arg instanceof String) {
  1079             return syms.stringType;
  1080         } else if (arg instanceof Pool.MethodHandle) {
  1081             return syms.methodHandleType;
  1082         } else if (arg instanceof MethodType) {
  1083             return syms.methodTypeType;
  1084         } else {
  1085             Assert.error("bad static arg " + arg.getClass());
  1086             return null;
  1090     /**
  1091      * Get the opcode associated with this method reference
  1092      */
  1093     private int referenceKind(Symbol refSym) {
  1094         if (refSym.isConstructor()) {
  1095             return ClassFile.REF_newInvokeSpecial;
  1096         } else {
  1097             if (refSym.isStatic()) {
  1098                 return ClassFile.REF_invokeStatic;
  1099             } else if ((refSym.flags() & PRIVATE) != 0) {
  1100                 return ClassFile.REF_invokeSpecial;
  1101             } else if (refSym.enclClass().isInterface()) {
  1102                 return ClassFile.REF_invokeInterface;
  1103             } else {
  1104                 return ClassFile.REF_invokeVirtual;
  1109     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1110     /**
  1111      * This visitor collects information about translation of a lambda expression.
  1112      * More specifically, it keeps track of the enclosing contexts and captured locals
  1113      * accessed by the lambda being translated (as well as other useful info).
  1114      * It also translates away problems for LambdaToMethod.
  1115      */
  1116     class LambdaAnalyzerPreprocessor extends TreeTranslator {
  1118         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1119         private List<Frame> frameStack;
  1121         /**
  1122          * keep the count of lambda expression (used to generate unambiguous
  1123          * names)
  1124          */
  1125         private int lambdaCount = 0;
  1127         /**
  1128          * keep the count of lambda expression defined in given context (used to
  1129          * generate unambiguous names for serializable lambdas)
  1130          */
  1131         private class SyntheticMethodNameCounter {
  1132             private Map<String, Integer> map = new HashMap<>();
  1133             int getIndex(StringBuilder buf) {
  1134                 String temp = buf.toString();
  1135                 Integer count = map.get(temp);
  1136                 if (count == null) {
  1137                     count = 0;
  1139                 ++count;
  1140                 map.put(temp, count);
  1141                 return count;
  1144         private SyntheticMethodNameCounter syntheticMethodNameCounts =
  1145                 new SyntheticMethodNameCounter();
  1147         private Map<Symbol, JCClassDecl> localClassDefs;
  1149         /**
  1150          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1151          * a static var init context
  1152          */
  1153         private Map<ClassSymbol, Symbol> clinits =
  1154                 new HashMap<ClassSymbol, Symbol>();
  1156         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
  1157             frameStack = List.nil();
  1158             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1159             return translate(tree);
  1162         @Override
  1163         public void visitBlock(JCBlock tree) {
  1164             List<Frame> prevStack = frameStack;
  1165             try {
  1166                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1167                     frameStack = frameStack.prepend(new Frame(tree));
  1169                 super.visitBlock(tree);
  1171             finally {
  1172                 frameStack = prevStack;
  1176         @Override
  1177         public void visitClassDef(JCClassDecl tree) {
  1178             List<Frame> prevStack = frameStack;
  1179             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
  1180                     syntheticMethodNameCounts;
  1181             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1182             DiagnosticSource prevSource = log.currentSource();
  1183             try {
  1184                 log.useSource(tree.sym.sourcefile);
  1185                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
  1186                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1187                 if (tree.sym.owner.kind == MTH) {
  1188                     localClassDefs.put(tree.sym, tree);
  1190                 if (directlyEnclosingLambda() != null) {
  1191                     tree.sym.owner = owner();
  1192                     if (tree.sym.hasOuterInstance()) {
  1193                         //if a class is defined within a lambda, the lambda must capture
  1194                         //its enclosing instance (if any)
  1195                         TranslationContext<?> localContext = context();
  1196                         while (localContext != null) {
  1197                             if (localContext.tree.getTag() == LAMBDA) {
  1198                                 ((LambdaTranslationContext)localContext)
  1199                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1201                             localContext = localContext.prev;
  1205                 frameStack = frameStack.prepend(new Frame(tree));
  1206                 super.visitClassDef(tree);
  1208             finally {
  1209                 log.useSource(prevSource.getFile());
  1210                 frameStack = prevStack;
  1211                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
  1212                 clinits = prevClinits;
  1216         @Override
  1217         public void visitIdent(JCIdent tree) {
  1218             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1219                 if (tree.sym.kind == VAR &&
  1220                         tree.sym.owner.kind == MTH &&
  1221                         tree.type.constValue() == null) {
  1222                     TranslationContext<?> localContext = context();
  1223                     while (localContext != null) {
  1224                         if (localContext.tree.getTag() == LAMBDA) {
  1225                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1226                             if (block == null) break;
  1227                             ((LambdaTranslationContext)localContext)
  1228                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1230                         localContext = localContext.prev;
  1232                 } else if (tree.sym.owner.kind == TYP) {
  1233                     TranslationContext<?> localContext = context();
  1234                     while (localContext != null) {
  1235                         if (localContext.tree.hasTag(LAMBDA)) {
  1236                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1237                             if (block == null) break;
  1238                             switch (block.getTag()) {
  1239                                 case CLASSDEF:
  1240                                     JCClassDecl cdecl = (JCClassDecl)block;
  1241                                     ((LambdaTranslationContext)localContext)
  1242                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1243                                     break;
  1244                                 default:
  1245                                     Assert.error("bad block kind");
  1248                         localContext = localContext.prev;
  1252             super.visitIdent(tree);
  1255         @Override
  1256         public void visitLambda(JCLambda tree) {
  1257             List<Frame> prevStack = frameStack;
  1258             try {
  1259                 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
  1260                 frameStack = frameStack.prepend(new Frame(tree));
  1261                 for (JCVariableDecl param : tree.params) {
  1262                     context.addSymbol(param.sym, PARAM);
  1263                     frameStack.head.addLocal(param.sym);
  1265                 contextMap.put(tree, context);
  1266                 super.visitLambda(tree);
  1267                 context.complete();
  1269             finally {
  1270                 frameStack = prevStack;
  1274         @Override
  1275         public void visitMethodDef(JCMethodDecl tree) {
  1276             List<Frame> prevStack = frameStack;
  1277             try {
  1278                 frameStack = frameStack.prepend(new Frame(tree));
  1279                 super.visitMethodDef(tree);
  1281             finally {
  1282                 frameStack = prevStack;
  1286         @Override
  1287         public void visitNewClass(JCNewClass tree) {
  1288             TypeSymbol def = tree.type.tsym;
  1289             boolean inReferencedClass = currentlyInClass(def);
  1290             boolean isLocal = def.isLocal();
  1291             if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
  1292                 TranslationContext<?> localContext = context();
  1293                 while (localContext != null) {
  1294                     if (localContext.tree.getTag() == LAMBDA) {
  1295                         ((LambdaTranslationContext)localContext)
  1296                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1298                     localContext = localContext.prev;
  1301             if (context() != null && !inReferencedClass && isLocal) {
  1302                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1303                 captureLocalClassDefs(def, lambdaContext);
  1305             super.visitNewClass(tree);
  1307         //where
  1308             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1309                 JCClassDecl localCDef = localClassDefs.get(csym);
  1310                 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
  1311                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1312                         @Override
  1313                         void addFreeVars(ClassSymbol c) {
  1314                             captureLocalClassDefs(c, lambdaContext);
  1316                         @Override
  1317                         void visitSymbol(Symbol sym) {
  1318                             if (sym.kind == VAR &&
  1319                                     sym.owner.kind == MTH &&
  1320                                     ((VarSymbol)sym).getConstValue() == null) {
  1321                                 TranslationContext<?> localContext = context();
  1322                                 while (localContext != null) {
  1323                                     if (localContext.tree.getTag() == LAMBDA) {
  1324                                         JCTree block = capturedDecl(localContext.depth, sym);
  1325                                         if (block == null) break;
  1326                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1328                                     localContext = localContext.prev;
  1332                     };
  1333                     fvc.scan(localCDef);
  1336         //where
  1337         boolean currentlyInClass(Symbol csym) {
  1338             for (Frame frame : frameStack) {
  1339                 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
  1340                     JCClassDecl cdef = (JCClassDecl) frame.tree;
  1341                     if (cdef.sym == csym) {
  1342                         return true;
  1346             return false;
  1349         /**
  1350          * Method references to local class constructors, may, if the local
  1351          * class references local variables, have implicit constructor
  1352          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1353          * information added in the LambdaToMethod pass will have the wrong
  1354          * signature. Hooks between Lower and LambdaToMethod have been added to
  1355          * handle normal "new" in this case. This visitor converts potentially
  1356          * effected method references into a lambda containing a normal "new" of
  1357          * the class.
  1359          * @param tree
  1360          */
  1361         @Override
  1362         public void visitReference(JCMemberReference tree) {
  1363             if (tree.getMode() == ReferenceMode.NEW
  1364                     && tree.kind != ReferenceKind.ARRAY_CTOR
  1365                     && tree.sym.owner.isLocal()) {
  1366                 MethodSymbol consSym = (MethodSymbol) tree.sym;
  1367                 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
  1368                 Type classType = consSym.owner.type;
  1370                 // Build lambda parameters
  1371                 // partially cloned from TreeMaker.Params until 8014021 is fixed
  1372                 Symbol owner = owner();
  1373                 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
  1374                 int i = 0;
  1375                 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
  1376                     JCVariableDecl param = make.Param(make.paramName(i++), l.head, owner);
  1377                     param.sym.pos = tree.pos;
  1378                     paramBuff.append(param);
  1380                 List<JCVariableDecl> params = paramBuff.toList();
  1382                 // Make new-class call
  1383                 JCNewClass nc = makeNewClass(classType, make.Idents(params));
  1384                 nc.pos = tree.pos;
  1386                 // Make lambda holding the new-class call
  1387                 JCLambda slam = make.Lambda(params, nc);
  1388                 slam.targets = tree.targets;
  1389                 slam.type = tree.type;
  1390                 slam.pos = tree.pos;
  1392                 // Now it is a lambda, process as such
  1393                 visitLambda(slam);
  1394             } else {
  1395                 super.visitReference(tree);
  1396                 contextMap.put(tree, makeReferenceContext(tree));
  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 TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
  1652             return new LambdaTranslationContext(tree);
  1655         private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
  1656             return new ReferenceTranslationContext(tree);
  1659         private class Frame {
  1660             final JCTree tree;
  1661             List<Symbol> locals;
  1663             public Frame(JCTree tree) {
  1664                 this.tree = tree;
  1667             void addLocal(Symbol sym) {
  1668                 if (locals == null) {
  1669                     locals = List.nil();
  1671                 locals = locals.prepend(sym);
  1675         /**
  1676          * This class is used to store important information regarding translation of
  1677          * lambda expression/method references (see subclasses).
  1678          */
  1679         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1681             /** the underlying (untranslated) tree */
  1682             final T tree;
  1684             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1685             final Symbol owner;
  1687             /** the depth of this lambda expression in the frame stack */
  1688             final int depth;
  1690             /** the enclosing translation context (set for nested lambdas/mref) */
  1691             final TranslationContext<?> prev;
  1693             /** list of methods to be bridged by the meta-factory */
  1694             final List<Symbol> bridges;
  1696             TranslationContext(T tree) {
  1697                 this.tree = tree;
  1698                 this.owner = owner();
  1699                 this.depth = frameStack.size() - 1;
  1700                 this.prev = context();
  1701                 ClassSymbol csym =
  1702                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1703                 this.bridges = types.functionalInterfaceBridges(csym);
  1706             /** does this functional expression need to be created using alternate metafactory? */
  1707             boolean needsAltMetafactory() {
  1708                 return tree.targets.length() > 1 ||
  1709                         isSerializable() ||
  1710                         bridges.length() > 1;
  1713             /** does this functional expression require serialization support? */
  1714             boolean isSerializable() {
  1715                 if (forceSerializable) {
  1716                     return true;
  1718                 for (Type target : tree.targets) {
  1719                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1720                         return true;
  1723                 return false;
  1726             /**
  1727              * @return Name of the enclosing method to be folded into synthetic
  1728              * method name
  1729              */
  1730             String enclosingMethodName() {
  1731                 return syntheticMethodNameComponent(owner.name);
  1734             /**
  1735              * @return Method name in a form that can be folded into a
  1736              * component of a synthetic method name
  1737              */
  1738             String syntheticMethodNameComponent(Name name) {
  1739                 if (name == null) {
  1740                     return "null";
  1742                 String methodName = name.toString();
  1743                 if (methodName.equals("<clinit>")) {
  1744                     methodName = "static";
  1745                 } else if (methodName.equals("<init>")) {
  1746                     methodName = "new";
  1748                 return methodName;
  1752         /**
  1753          * This class retains all the useful information about a lambda expression;
  1754          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1755          * and the used by the main translation routines in order to adjust references
  1756          * to captured locals/members, etc.
  1757          */
  1758         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1760             /** variable in the enclosing context to which this lambda is assigned */
  1761             final Symbol self;
  1763             /** variable in the enclosing context to which this lambda is assigned */
  1764             final Symbol assignedTo;
  1766             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
  1768             /** the synthetic symbol for the method hoisting the translated lambda */
  1769             Symbol translatedSym;
  1771             List<JCVariableDecl> syntheticParams;
  1773             /**
  1774              * to prevent recursion, track local classes processed
  1775              */
  1776             final Set<Symbol> freeVarProcessedLocalClasses;
  1778             LambdaTranslationContext(JCLambda tree) {
  1779                 super(tree);
  1780                 Frame frame = frameStack.head;
  1781                 switch (frame.tree.getTag()) {
  1782                     case VARDEF:
  1783                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
  1784                         break;
  1785                     case ASSIGN:
  1786                         self = null;
  1787                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
  1788                         break;
  1789                     default:
  1790                         assignedTo = self = null;
  1791                         break;
  1794                 // This symbol will be filled-in in complete
  1795                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
  1797                 if (dumpLambdaToMethodStats) {
  1798                     log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym);
  1800                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
  1802                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
  1803                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
  1804                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
  1805                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
  1806                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
  1808                 freeVarProcessedLocalClasses = new HashSet<>();
  1811              /**
  1812              * For a serializable lambda, generate a disambiguating string
  1813              * which maximizes stability across deserialization.
  1815              * @return String to differentiate synthetic lambda method names
  1816              */
  1817             private String serializedLambdaDisambiguation() {
  1818                 StringBuilder buf = new StringBuilder();
  1819                 // Append the enclosing method signature to differentiate
  1820                 // overloaded enclosing methods.  For lambdas enclosed in
  1821                 // lambdas, the generated lambda method will not have type yet,
  1822                 // but the enclosing method's name will have been generated
  1823                 // with this same method, so it will be unique and never be
  1824                 // overloaded.
  1825                 Assert.check(
  1826                         owner.type != null ||
  1827                         directlyEnclosingLambda() != null);
  1828                 if (owner.type != null) {
  1829                     buf.append(typeSig(owner.type));
  1830                     buf.append(":");
  1833                 // Add target type info
  1834                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
  1835                 buf.append(" ");
  1837                 // Add variable assigned to
  1838                 if (assignedTo != null) {
  1839                     buf.append(assignedTo.flatName());
  1840                     buf.append("=");
  1842                 //add captured locals info: type, name, order
  1843                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
  1844                     if (fv != self) {
  1845                         buf.append(typeSig(fv.type));
  1846                         buf.append(" ");
  1847                         buf.append(fv.flatName());
  1848                         buf.append(",");
  1852                 return buf.toString();
  1855             /**
  1856              * For a non-serializable lambda, generate a simple method.
  1858              * @return Name to use for the synthetic lambda method name
  1859              */
  1860             private Name lambdaName() {
  1861                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
  1864             /**
  1865              * For a serializable lambda, generate a method name which maximizes
  1866              * name stability across deserialization.
  1868              * @return Name to use for the synthetic lambda method name
  1869              */
  1870             private Name serializedLambdaName() {
  1871                 StringBuilder buf = new StringBuilder();
  1872                 buf.append(names.lambda);
  1873                 // Append the name of the method enclosing the lambda.
  1874                 buf.append(enclosingMethodName());
  1875                 buf.append('$');
  1876                 // Append a hash of the disambiguating string : enclosing method
  1877                 // signature, etc.
  1878                 String disam = serializedLambdaDisambiguation();
  1879                 buf.append(Integer.toHexString(disam.hashCode()));
  1880                 buf.append('$');
  1881                 // The above appended name components may not be unique, append
  1882                 // a count based on the above name components.
  1883                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  1884                 String result = buf.toString();
  1885                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
  1886                 return names.fromString(result);
  1889             /**
  1890              * Translate a symbol of a given kind into something suitable for the
  1891              * synthetic lambda body
  1892              */
  1893             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1894                 Symbol ret;
  1895                 switch (skind) {
  1896                     case CAPTURED_THIS:
  1897                         ret = sym;  // self represented
  1898                         break;
  1899                     case TYPE_VAR:
  1900                         // Just erase the type var
  1901                         ret = new VarSymbol(sym.flags(), name,
  1902                                 types.erasure(sym.type), sym.owner);
  1904                         /* this information should also be kept for LVT generation at Gen
  1905                          * a Symbol with pos < startPos won't be tracked.
  1906                          */
  1907                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
  1908                         break;
  1909                     case CAPTURED_VAR:
  1910                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
  1911                             @Override
  1912                             public Symbol baseSymbol() {
  1913                                 //keep mapping with original captured symbol
  1914                                 return sym;
  1916                         };
  1917                         break;
  1918                     case LOCAL_VAR:
  1919                         ret = new VarSymbol(sym.flags() & FINAL, name, sym.type, translatedSym);
  1920                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1921                         break;
  1922                     case PARAM:
  1923                         ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, name, types.erasure(sym.type), translatedSym);
  1924                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1925                         break;
  1926                     default:
  1927                         ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1928                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1930                 if (ret != sym) {
  1931                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1932                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1934                 return ret;
  1937             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1938                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
  1939                 Name preferredName;
  1940                 switch (skind) {
  1941                     case CAPTURED_THIS:
  1942                         preferredName = names.fromString("encl$" + transMap.size());
  1943                         break;
  1944                     case CAPTURED_VAR:
  1945                         preferredName = names.fromString("cap$" + transMap.size());
  1946                         break;
  1947                     case LOCAL_VAR:
  1948                         preferredName = sym.name;
  1949                         break;
  1950                     case PARAM:
  1951                         preferredName = sym.name;
  1952                         break;
  1953                     case TYPE_VAR:
  1954                         preferredName = sym.name;
  1955                         break;
  1956                     default: throw new AssertionError();
  1958                 if (!transMap.containsKey(sym)) {
  1959                     transMap.put(sym, translate(preferredName, sym, skind));
  1963             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
  1964                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
  1965                 Assert.checkNonNull(m);
  1966                 return m;
  1969             JCTree translate(JCIdent lambdaIdent) {
  1970                 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
  1971                     if (m.containsKey(lambdaIdent.sym)) {
  1972                         Symbol tSym = m.get(lambdaIdent.sym);
  1973                         JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
  1974                         tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
  1975                         return t;
  1978                 return null;
  1981             /**
  1982              * The translatedSym is not complete/accurate until the analysis is
  1983              * finished.  Once the analysis is finished, the translatedSym is
  1984              * "completed" -- updated with type information, access modifiers,
  1985              * and full parameter list.
  1986              */
  1987             void complete() {
  1988                 if (syntheticParams != null) {
  1989                     return;
  1991                 boolean inInterface = translatedSym.owner.isInterface();
  1992                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1994                 // If instance access isn't needed, make it static.
  1995                 // Interface instance methods must be default methods.
  1996                 // Lambda methods are private synthetic.
  1997                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
  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                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
  2013                     params.append(make.VarDef((VarSymbol) thisSym, null));
  2015                 syntheticParams = params.toList();
  2017                 // Compute and set the lambda name
  2018                 translatedSym.name = isSerializable()
  2019                         ? serializedLambdaName()
  2020                         : lambdaName();
  2022                 //prepend synthetic args to translated lambda method signature
  2023                 translatedSym.type = types.createMethodTypeWithParameters(
  2024                         generatedLambdaSig(),
  2025                         TreeInfo.types(syntheticParams));
  2028             Type generatedLambdaSig() {
  2029                 return types.erasure(tree.getDescriptorType(types));
  2033         /**
  2034          * This class retains all the useful information about a method reference;
  2035          * the contents of this class are filled by the LambdaAnalyzer visitor,
  2036          * and the used by the main translation routines in order to adjust method
  2037          * references (i.e. in case a bridge is needed)
  2038          */
  2039         private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  2041             final boolean isSuper;
  2042             final Symbol bridgeSym;
  2043             final Symbol sigPolySym;
  2045             ReferenceTranslationContext(JCMemberReference tree) {
  2046                 super(tree);
  2047                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2048                 this.bridgeSym = needsBridge()
  2049                         ? makePrivateSyntheticMethod(isSuper ? 0 : STATIC,
  2050                                               referenceBridgeName(), null,
  2051                                               owner.enclClass())
  2052                         : null;
  2053                 this.sigPolySym = isSignaturePolymorphic()
  2054                         ? makePrivateSyntheticMethod(tree.sym.flags(),
  2055                                               tree.sym.name,
  2056                                               bridgedRefSig(),
  2057                                               tree.sym.enclClass())
  2058                         : null;
  2059                 if (dumpLambdaToMethodStats) {
  2060                     String key = bridgeSym == null ?
  2061                             "mref.stat" : "mref.stat.1";
  2062                     log.note(tree, key, needsAltMetafactory(), bridgeSym);
  2066             /**
  2067              * Get the opcode associated with this method reference
  2068              */
  2069             int referenceKind() {
  2070                 return LambdaToMethod.this.referenceKind(needsBridge()
  2071                         ? bridgeSym
  2072                         : tree.sym);
  2075             boolean needsVarArgsConversion() {
  2076                 return tree.varargsElement != null;
  2079             /**
  2080              * Generate a disambiguating string to increase stability (important
  2081              * if serialized)
  2083              * @return String to differentiate synthetic lambda method names
  2084              */
  2085             private String referenceBridgeDisambiguation() {
  2086                 StringBuilder buf = new StringBuilder();
  2087                 // Append the enclosing method signature to differentiate
  2088                 // overloaded enclosing methods.
  2089                 if (owner.type != null) {
  2090                     buf.append(typeSig(owner.type));
  2091                     buf.append(":");
  2094                 // Append qualifier type
  2095                 buf.append(classSig(tree.sym.owner.type));
  2097                 // Note static/instance
  2098                 buf.append(tree.sym.isStatic()? " S " : " I ");
  2100                 // Append referenced signature
  2101                 buf.append(typeSig(tree.sym.erasure(types)));
  2103                 return buf.toString();
  2106             /**
  2107              * Construct a unique stable name for the method reference bridge
  2109              * @return Name to use for the synthetic method name
  2110              */
  2111             private Name referenceBridgeName() {
  2112                 StringBuilder buf = new StringBuilder();
  2113                 // Append lambda ID, this is semantically significant
  2114                 buf.append(names.lambda);
  2115                 // Note that it is a method reference bridge
  2116                 buf.append("MR$");
  2117                 // Append the enclosing method name
  2118                 buf.append(enclosingMethodName());
  2119                 buf.append('$');
  2120                 // Append the referenced method name
  2121                 buf.append(syntheticMethodNameComponent(tree.sym.name));
  2122                 buf.append('$');
  2123                 // Append a hash of the disambiguating string : enclosing method
  2124                 // signature, etc.
  2125                 String disam = referenceBridgeDisambiguation();
  2126                 buf.append(Integer.toHexString(disam.hashCode()));
  2127                 buf.append('$');
  2128                 // The above appended name components may not be unique, append
  2129                 // a count based on the above name components.
  2130                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  2131                 String result = buf.toString();
  2132                 return names.fromString(result);
  2135             /**
  2136              * @return Is this an array operation like clone()
  2137              */
  2138             boolean isArrayOp() {
  2139                 return tree.sym.owner == syms.arrayClass;
  2142             boolean receiverAccessible() {
  2143                 //hack needed to workaround 292 bug (7087658)
  2144                 //when 292 issue is fixed we should remove this and change the backend
  2145                 //code to always generate a method handle to an accessible method
  2146                 return tree.ownerAccessible;
  2149             /**
  2150              * The VM does not support access across nested classes (8010319).
  2151              * Were that ever to change, this should be removed.
  2152              */
  2153             boolean isPrivateInOtherClass() {
  2154                 return  (tree.sym.flags() & PRIVATE) != 0 &&
  2155                         !types.isSameType(
  2156                               types.erasure(tree.sym.enclClass().asType()),
  2157                               types.erasure(owner.enclClass().asType()));
  2160             /**
  2161              * Signature polymorphic methods need special handling.
  2162              * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
  2163              */
  2164             final boolean isSignaturePolymorphic() {
  2165                 return  tree.sym.kind == MTH &&
  2166                         types.isSignaturePolymorphic((MethodSymbol)tree.sym);
  2169             /**
  2170              * Does this reference needs a bridge (i.e. var args need to be
  2171              * expanded or "super" is used)
  2172              */
  2173             final boolean needsBridge() {
  2174                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  2175                         isPrivateInOtherClass() ||
  2176                         !receiverAccessible();
  2179             Type generatedRefSig() {
  2180                 return types.erasure(tree.sym.type);
  2183             Type bridgedRefSig() {
  2184                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  2188     // </editor-fold>
  2190     /*
  2191      * These keys provide mappings for various translated lambda symbols
  2192      * and the prevailing order must be maintained.
  2193      */
  2194     enum LambdaSymbolKind {
  2195         PARAM,          // original to translated lambda parameters
  2196         LOCAL_VAR,      // original to translated lambda locals
  2197         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
  2198         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
  2199         TYPE_VAR;       // original to translated lambda type variables
  2202     /**
  2203      * ****************************************************************
  2204      * Signature Generation
  2205      * ****************************************************************
  2206      */
  2208     private String typeSig(Type type) {
  2209         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2210         sg.assembleSig(type);
  2211         return sg.toString();
  2214     private String classSig(Type type) {
  2215         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2216         sg.assembleClassSig(type);
  2217         return sg.toString();
  2220     /**
  2221      * Signature Generation
  2222      */
  2223     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  2225         /**
  2226          * An output buffer for type signatures.
  2227          */
  2228         StringBuilder sb = new StringBuilder();
  2230         L2MSignatureGenerator() {
  2231             super(types);
  2234         @Override
  2235         protected void append(char ch) {
  2236             sb.append(ch);
  2239         @Override
  2240         protected void append(byte[] ba) {
  2241             sb.append(new String(ba));
  2244         @Override
  2245         protected void append(Name name) {
  2246             sb.append(name.toString());
  2249         @Override
  2250         public String toString() {
  2251             return sb.toString();

mercurial