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

Fri, 13 Dec 2013 14:13:03 +0000

author
vromero
date
Fri, 13 Dec 2013 14:13:03 +0000
changeset 2222
8832b6048e65
parent 2202
4fa835472e3c
child 2251
bbbef54e3b30
permissions
-rw-r--r--

8029721: javac crash for annotated parameter type of lambda in a field
Reviewed-by: rfield, jfranck

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

mercurial