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

Fri, 01 Nov 2013 21:43:27 +0100

author
jlahoda
date
Fri, 01 Nov 2013 21:43:27 +0100
changeset 2179
8b4e1421a9b7
parent 2165
864dafc5ab7a
child 2202
4fa835472e3c
permissions
-rw-r--r--

8027310: Annotation Processor crashes with NPE
Summary: JCAnnotation.attribute is null when annotation type is unavailable
Reviewed-by: jjg, 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             tree.sym;
   364         //build the bridge method, if needed
   365         if (localContext.needsBridge()) {
   366             bridgeMemberReference(tree, localContext);
   367         }
   369         //the qualifying expression is treated as a special captured arg
   370         JCExpression init;
   371         switch(tree.kind) {
   373             case IMPLICIT_INNER:    /** Inner :: new */
   374             case SUPER:             /** super :: instMethod */
   375                 init = makeThis(
   376                     localContext.owner.enclClass().asType(),
   377                     localContext.owner.enclClass());
   378                 break;
   380             case BOUND:             /** Expr :: instMethod */
   381                 init = tree.getQualifierExpression();
   382                 init = attr.makeNullCheck(init);
   383                 break;
   385             case UNBOUND:           /** Type :: instMethod */
   386             case STATIC:            /** Type :: staticMethod */
   387             case TOPLEVEL:          /** Top level :: new */
   388             case ARRAY_CTOR:        /** ArrayType :: new */
   389                 init = null;
   390                 break;
   392             default:
   393                 throw new InternalError("Should not have an invalid kind");
   394         }
   396         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
   399         //build a sam instance using an indy call to the meta-factory
   400         result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
   401     }
   403     /**
   404      * Translate identifiers within a lambda to the mapped identifier
   405      * @param tree
   406      */
   407     @Override
   408     public void visitIdent(JCIdent tree) {
   409         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
   410             super.visitIdent(tree);
   411         } else {
   412             int prevPos = make.pos;
   413             try {
   414                 make.at(tree);
   416                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
   417                 JCTree ltree = lambdaContext.translate(tree);
   418                 if (ltree != null) {
   419                     result = ltree;
   420                 } else {
   421                     //access to untranslated symbols (i.e. compile-time constants,
   422                     //members defined inside the lambda body, etc.) )
   423                     super.visitIdent(tree);
   424                 }
   425             } finally {
   426                 make.at(prevPos);
   427             }
   428         }
   429     }
   431     @Override
   432     public void visitVarDef(JCVariableDecl tree) {
   433         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
   434         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   435             JCExpression init = translate(tree.init);
   436             int prevPos = make.pos;
   437             try {
   438                 result = make.at(tree).VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
   439             } finally {
   440                 make.at(prevPos);
   441             }
   442         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   443             JCExpression init = translate(tree.init);
   444             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   445             int prevPos = make.pos;
   446             try {
   447                 result = make.at(tree).VarDef(xsym, init);
   448             } finally {
   449                 make.at(prevPos);
   450             }
   451             // Replace the entered symbol for this variable
   452             Scope sc = tree.sym.owner.members();
   453             if (sc != null) {
   454                 sc.remove(tree.sym);
   455                 sc.enter(xsym);
   456             }
   457         } else {
   458             super.visitVarDef(tree);
   459         }
   460     }
   462     // </editor-fold>
   464     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   466     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   467         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   468                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   469                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   470     }
   472     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   473         Type restype = lambdaMethodDecl.type.getReturnType();
   474         boolean isLambda_void = expr.type.hasTag(VOID);
   475         boolean isTarget_void = restype.hasTag(VOID);
   476         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   477         int prevPos = make.pos;
   478         try {
   479             if (isTarget_void) {
   480                 //target is void:
   481                 // BODY;
   482                 JCStatement stat = make.at(expr).Exec(expr);
   483                 return make.Block(0, List.<JCStatement>of(stat));
   484             } else if (isLambda_void && isTarget_Void) {
   485                 //void to Void conversion:
   486                 // BODY; return null;
   487                 ListBuffer<JCStatement> stats = new ListBuffer<>();
   488                 stats.append(make.at(expr).Exec(expr));
   489                 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   490                 return make.Block(0, stats.toList());
   491             } else {
   492                 //non-void to non-void conversion:
   493                 // return (TYPE)BODY;
   494                 JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   495                 return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
   496             }
   497         } finally {
   498             make.at(prevPos);
   499         }
   500     }
   502     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   503         final Type restype = lambdaMethodDecl.type.getReturnType();
   504         final boolean isTarget_void = restype.hasTag(VOID);
   505         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   507         class LambdaBodyTranslator extends TreeTranslator {
   509             @Override
   510             public void visitClassDef(JCClassDecl tree) {
   511                 //do NOT recurse on any inner classes
   512                 result = tree;
   513             }
   515             @Override
   516             public void visitLambda(JCLambda tree) {
   517                 //do NOT recurse on any nested lambdas
   518                 result = tree;
   519             }
   521             @Override
   522             public void visitReturn(JCReturn tree) {
   523                 boolean isLambda_void = tree.expr == null;
   524                 if (isTarget_void && !isLambda_void) {
   525                     //Void to void conversion:
   526                     // { TYPE $loc = RET-EXPR; return; }
   527                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   528                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   529                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   530                 } else if (!isTarget_void || !isLambda_void) {
   531                     //non-void to non-void conversion:
   532                     // return (TYPE)RET-EXPR;
   533                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   534                     result = tree;
   535                 } else {
   536                     result = tree;
   537                 }
   539             }
   540         }
   542         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   543         if (completeNormally && isTarget_Void) {
   544             //there's no return statement and the lambda (possibly inferred)
   545             //return type is java.lang.Void; emit a synthetic return statement
   546             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   547         }
   548         return trans_block;
   549     }
   551     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   552         ListBuffer<JCCase> cases = new ListBuffer<>();
   553         ListBuffer<JCBreak> breaks = new ListBuffer<>();
   554         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   555             JCBreak br = make.Break(null);
   556             breaks.add(br);
   557             List<JCStatement> stmts = entry.getValue().append(br).toList();
   558             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   559         }
   560         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   561         for (JCBreak br : breaks) {
   562             br.target = sw;
   563         }
   564         JCBlock body = make.Block(0L, List.<JCStatement>of(
   565                 sw,
   566                 make.Throw(makeNewClass(
   567                     syms.illegalArgumentExceptionType,
   568                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   569         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   570                         names.deserializeLambda,
   571                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   572                         List.<JCTypeParameter>nil(),
   573                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   574                         List.<JCExpression>nil(),
   575                         body,
   576                         null);
   577         deser.sym = kInfo.deserMethodSym;
   578         deser.type = kInfo.deserMethodSym.type;
   579         //System.err.printf("DESER: '%s'\n", deser);
   580         return deser;
   581     }
   583     /** Make an attributed class instance creation expression.
   584      *  @param ctype    The class type.
   585      *  @param args     The constructor arguments.
   586      *  @param cons     The constructor symbol
   587      */
   588     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
   589         JCNewClass tree = make.NewClass(null,
   590             null, make.QualIdent(ctype.tsym), args, null);
   591         tree.constructor = cons;
   592         tree.type = ctype;
   593         return tree;
   594     }
   596     /** Make an attributed class instance creation expression.
   597      *  @param ctype    The class type.
   598      *  @param args     The constructor arguments.
   599      */
   600     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   601         return makeNewClass(ctype, args,
   602                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
   603      }
   605     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   606             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   607         String functionalInterfaceClass = classSig(targetType);
   608         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   609         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
   610         String implClass = classSig(types.erasure(refSym.owner.type));
   611         String implMethodName = refSym.getQualifiedName().toString();
   612         String implMethodSignature = typeSig(types.erasure(refSym.type));
   614         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   615         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
   616         int i = 0;
   617         for (Type t : indyType.getParameterTypes()) {
   618             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
   619             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
   620             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   621             ++i;
   622         }
   623         JCStatement stmt = make.If(
   624                 deserTest(deserTest(deserTest(deserTest(deserTest(
   625                     kindTest,
   626                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   627                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   628                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   629                     "getImplClass", implClass),
   630                     "getImplMethodSignature", implMethodSignature),
   631                 make.Return(makeIndyCall(
   632                     pos,
   633                     syms.lambdaMetafactory,
   634                     names.altMetafactory,
   635                     staticArgs, indyType, serArgs.toList(), samSym.name)),
   636                 null);
   637         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   638         if (stmts == null) {
   639             stmts = new ListBuffer<>();
   640             kInfo.deserializeCases.put(implMethodName, stmts);
   641         }
   642         /****
   643         System.err.printf("+++++++++++++++++\n");
   644         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   645         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   646         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   647         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   648         System.err.printf("*implClass: '%s'\n", implClass);
   649         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   650         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   651         ****/
   652         stmts.append(stmt);
   653     }
   655     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   656         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   657         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   658         testExpr.setType(syms.booleanType);
   659         return testExpr;
   660     }
   662     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   663         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   664         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   665         JCMethodInvocation eqtest = make.Apply(
   666                 List.<JCExpression>nil(),
   667                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   668                 List.<JCExpression>of(make.Literal(lit)));
   669         eqtest.setType(syms.booleanType);
   670         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   671         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   672         compound.setType(syms.booleanType);
   673         return compound;
   674     }
   676     private JCExpression deserGetter(String func, Type type) {
   677         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   678     }
   680     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   681         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   682         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   683         return make.Apply(
   684                     List.<JCExpression>nil(),
   685                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   686                     args).setType(type);
   687     }
   689     /**
   690      * Create new synthetic method with given flags, name, type, owner
   691      */
   692     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   693         return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
   694     }
   696     /**
   697      * Create new synthetic variable with given flags, name, type, owner
   698      */
   699     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   700         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   701     }
   703     /**
   704      * Create new synthetic variable with given flags, name, type, owner
   705      */
   706     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   707         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   708     }
   710     /**
   711      * Set varargsElement field on a given tree (must be either a new class tree
   712      * or a method call tree)
   713      */
   714     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   715         if (varargsElement != null) {
   716             switch (tree.getTag()) {
   717                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   718                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   719                 default: throw new AssertionError();
   720             }
   721         }
   722     }
   724     /**
   725      * Convert method/constructor arguments by inserting appropriate cast
   726      * as required by type-erasure - this is needed when bridging a lambda/method
   727      * reference, as the bridged signature might require downcast to be compatible
   728      * with the generated signature.
   729      */
   730     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   731        Assert.check(meth.kind == Kinds.MTH);
   732        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   733        if (varargsElement != null) {
   734            Assert.check((meth.flags() & VARARGS) != 0);
   735        }
   736        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   737     }
   739     // </editor-fold>
   741     /**
   742      * Generate an adapter method "bridge" for a method reference which cannot
   743      * be used directly.
   744      */
   745     private class MemberReferenceBridger {
   747         private final JCMemberReference tree;
   748         private final ReferenceTranslationContext localContext;
   749         private final ListBuffer<JCExpression> args = new ListBuffer<>();
   750         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
   752         MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
   753             this.tree = tree;
   754             this.localContext = localContext;
   755         }
   757         /**
   758          * Generate the bridge
   759          */
   760         JCMethodDecl bridge() {
   761             int prevPos = make.pos;
   762             try {
   763                 make.at(tree);
   764                 Type samDesc = localContext.bridgedRefSig();
   765                 List<Type> samPTypes = samDesc.getParameterTypes();
   767                 //an extra argument is prepended to the signature of the bridge in case
   768                 //the member reference is an instance method reference (in which case
   769                 //the receiver expression is passed to the bridge itself).
   770                 Type recType = null;
   771                 switch (tree.kind) {
   772                     case IMPLICIT_INNER:
   773                         recType = tree.sym.owner.type.getEnclosingType();
   774                         break;
   775                     case BOUND:
   776                         recType = tree.getQualifierExpression().type;
   777                         break;
   778                     case UNBOUND:
   779                         recType = samPTypes.head;
   780                         samPTypes = samPTypes.tail;
   781                         break;
   782                 }
   784                 //generate the parameter list for the bridged member reference - the
   785                 //bridge signature will match the signature of the target sam descriptor
   787                 VarSymbol rcvr = (recType == null)
   788                         ? null
   789                         : addParameter("rec$", recType, false);
   791                 List<Type> refPTypes = tree.sym.type.getParameterTypes();
   792                 int refSize = refPTypes.size();
   793                 int samSize = samPTypes.size();
   794                 // Last parameter to copy from referenced method
   795                 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
   797                 List<Type> l = refPTypes;
   798                 // Use parameter types of the referenced method, excluding final var args
   799                 for (int i = 0; l.nonEmpty() && i < last; ++i) {
   800                     addParameter("x$" + i, l.head, true);
   801                     l = l.tail;
   802                 }
   803                 // Flatten out the var args
   804                 for (int i = last; i < samSize; ++i) {
   805                     addParameter("xva$" + i, tree.varargsElement, true);
   806                 }
   808                 //generate the bridge method declaration
   809                 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
   810                         localContext.bridgeSym.name,
   811                         make.QualIdent(samDesc.getReturnType().tsym),
   812                         List.<JCTypeParameter>nil(),
   813                         params.toList(),
   814                         tree.sym.type.getThrownTypes() == null
   815                         ? List.<JCExpression>nil()
   816                         : make.Types(tree.sym.type.getThrownTypes()),
   817                         null,
   818                         null);
   819                 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
   820                 bridgeDecl.type = localContext.bridgeSym.type =
   821                         types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
   823                 //bridge method body generation - this can be either a method call or a
   824                 //new instance creation expression, depending on the member reference kind
   825                 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
   826                         ? bridgeExpressionInvoke(makeReceiver(rcvr))
   827                         : bridgeExpressionNew();
   829                 //the body is either a return expression containing a method call,
   830                 //or the method call itself, depending on whether the return type of
   831                 //the bridge is non-void/void.
   832                 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
   834                 return bridgeDecl;
   835             } finally {
   836                 make.at(prevPos);
   837             }
   838         }
   839         //where
   840             private JCExpression makeReceiver(VarSymbol rcvr) {
   841                 if (rcvr == null) return null;
   842                 JCExpression rcvrExpr = make.Ident(rcvr);
   843                 Type rcvrType = tree.sym.enclClass().type;
   844                 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   845                     rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   846                 }
   847                 return rcvrExpr;
   848             }
   850         /**
   851          * determine the receiver of the bridged method call - the receiver can
   852          * be either the synthetic receiver parameter or a type qualifier; the
   853          * original qualifier expression is never used here, as it might refer
   854          * to symbols not available in the static context of the bridge
   855          */
   856         private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
   857             JCExpression qualifier =
   858                     tree.sym.isStatic() ?
   859                         make.Type(tree.sym.owner.type) :
   860                         (rcvr != null) ?
   861                             rcvr :
   862                             tree.getQualifierExpression();
   864             //create the qualifier expression
   865             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   866             select.sym = tree.sym;
   867             select.type = tree.sym.erasure(types);
   869             //create the method call expression
   870             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   871                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   872                     setType(tree.sym.erasure(types).getReturnType());
   874             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   875             setVarargsIfNeeded(apply, tree.varargsElement);
   876             return apply;
   877         }
   879         /**
   880          * the enclosing expression is either 'null' (no enclosing type) or set
   881          * to the first bridge synthetic parameter
   882          */
   883         private JCExpression bridgeExpressionNew() {
   884             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   885                 //create the array creation expression
   886                 JCNewArray newArr = make.NewArray(
   887                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   888                         List.of(make.Ident(params.first())),
   889                         null);
   890                 newArr.type = tree.getQualifierExpression().type;
   891                 return newArr;
   892             } else {
   893                 JCExpression encl = null;
   894                 switch (tree.kind) {
   895                     case UNBOUND:
   896                     case IMPLICIT_INNER:
   897                         encl = make.Ident(params.first());
   898                 }
   900                 //create the instance creation expression
   901                 JCNewClass newClass = make.NewClass(encl,
   902                         List.<JCExpression>nil(),
   903                         make.Type(tree.getQualifierExpression().type),
   904                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   905                         null);
   906                 newClass.constructor = tree.sym;
   907                 newClass.constructorType = tree.sym.erasure(types);
   908                 newClass.type = tree.getQualifierExpression().type;
   909                 setVarargsIfNeeded(newClass, tree.varargsElement);
   910                 return newClass;
   911             }
   912         }
   914         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   915             VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
   916             params.append(make.VarDef(vsym, null));
   917             if (genArg) {
   918                 args.append(make.Ident(vsym));
   919             }
   920             return vsym;
   921         }
   922     }
   924     /**
   925      * Bridges a member reference - this is needed when:
   926      * * Var args in the referenced method need to be flattened away
   927      * * super is used
   928      */
   929     private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
   930         kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
   931     }
   933     private MethodType typeToMethodType(Type mt) {
   934         Type type = types.erasure(mt);
   935         return new MethodType(type.getParameterTypes(),
   936                         type.getReturnType(),
   937                         type.getThrownTypes(),
   938                         syms.methodClass);
   939     }
   941     /**
   942      * Generate an indy method call to the meta factory
   943      */
   944     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
   945             int refKind, Symbol refSym, List<JCExpression> indy_args) {
   946         JCFunctionalExpression tree = context.tree;
   947         //determine the static bsm args
   948         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   949         List<Object> staticArgs = List.<Object>of(
   950                 typeToMethodType(samSym.type),
   951                 new Pool.MethodHandle(refKind, refSym, types),
   952                 typeToMethodType(tree.getDescriptorType(types)));
   954         //computed indy arg types
   955         ListBuffer<Type> indy_args_types = new ListBuffer<>();
   956         for (JCExpression arg : indy_args) {
   957             indy_args_types.append(arg.type);
   958         }
   960         //finally, compute the type of the indy call
   961         MethodType indyType = new MethodType(indy_args_types.toList(),
   962                 tree.type,
   963                 List.<Type>nil(),
   964                 syms.methodClass);
   966         Name metafactoryName = context.needsAltMetafactory() ?
   967                 names.altMetafactory : names.metafactory;
   969         if (context.needsAltMetafactory()) {
   970             ListBuffer<Object> markers = new ListBuffer<>();
   971             for (Type t : tree.targets.tail) {
   972                 if (t.tsym != syms.serializableType.tsym) {
   973                     markers.append(t.tsym);
   974                 }
   975             }
   976             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
   977             boolean hasMarkers = markers.nonEmpty();
   978             boolean hasBridges = context.bridges.nonEmpty();
   979             if (hasMarkers) {
   980                 flags |= FLAG_MARKERS;
   981             }
   982             if (hasBridges) {
   983                 flags |= FLAG_BRIDGES;
   984             }
   985             staticArgs = staticArgs.append(flags);
   986             if (hasMarkers) {
   987                 staticArgs = staticArgs.append(markers.length());
   988                 staticArgs = staticArgs.appendList(markers.toList());
   989             }
   990             if (hasBridges) {
   991                 staticArgs = staticArgs.append(context.bridges.length() - 1);
   992                 for (Symbol s : context.bridges) {
   993                     Type s_erasure = s.erasure(types);
   994                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
   995                         staticArgs = staticArgs.append(s.erasure(types));
   996                     }
   997                 }
   998             }
   999             if (context.isSerializable()) {
  1000                 int prevPos = make.pos;
  1001                 try {
  1002                     make.at(kInfo.clazz);
  1003                     addDeserializationCase(refKind, refSym, tree.type, samSym,
  1004                             tree, staticArgs, indyType);
  1005                 } finally {
  1006                     make.at(prevPos);
  1011         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
  1014     /**
  1015      * Generate an indy method call with given name, type and static bootstrap
  1016      * arguments types
  1017      */
  1018     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
  1019             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
  1020             Name methName) {
  1021         int prevPos = make.pos;
  1022         try {
  1023             make.at(pos);
  1024             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
  1025                     syms.stringType,
  1026                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
  1028             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
  1029                     bsmName, bsm_staticArgs, List.<Type>nil());
  1031             DynamicMethodSymbol dynSym =
  1032                     new DynamicMethodSymbol(methName,
  1033                                             syms.noSymbol,
  1034                                             bsm.isStatic() ?
  1035                                                 ClassFile.REF_invokeStatic :
  1036                                                 ClassFile.REF_invokeVirtual,
  1037                                             (MethodSymbol)bsm,
  1038                                             indyType,
  1039                                             staticArgs.toArray());
  1041             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1042             qualifier.sym = dynSym;
  1043             qualifier.type = indyType.getReturnType();
  1045             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
  1046             proxyCall.type = indyType.getReturnType();
  1047             return proxyCall;
  1048         } finally {
  1049             make.at(prevPos);
  1052     //where
  1053     private List<Type> bsmStaticArgToTypes(List<Object> args) {
  1054         ListBuffer<Type> argtypes = new ListBuffer<>();
  1055         for (Object arg : args) {
  1056             argtypes.append(bsmStaticArgToType(arg));
  1058         return argtypes.toList();
  1061     private Type bsmStaticArgToType(Object arg) {
  1062         Assert.checkNonNull(arg);
  1063         if (arg instanceof ClassSymbol) {
  1064             return syms.classType;
  1065         } else if (arg instanceof Integer) {
  1066             return syms.intType;
  1067         } else if (arg instanceof Long) {
  1068             return syms.longType;
  1069         } else if (arg instanceof Float) {
  1070             return syms.floatType;
  1071         } else if (arg instanceof Double) {
  1072             return syms.doubleType;
  1073         } else if (arg instanceof String) {
  1074             return syms.stringType;
  1075         } else if (arg instanceof Pool.MethodHandle) {
  1076             return syms.methodHandleType;
  1077         } else if (arg instanceof MethodType) {
  1078             return syms.methodTypeType;
  1079         } else {
  1080             Assert.error("bad static arg " + arg.getClass());
  1081             return null;
  1085     /**
  1086      * Get the opcode associated with this method reference
  1087      */
  1088     private int referenceKind(Symbol refSym) {
  1089         if (refSym.isConstructor()) {
  1090             return ClassFile.REF_newInvokeSpecial;
  1091         } else {
  1092             if (refSym.isStatic()) {
  1093                 return ClassFile.REF_invokeStatic;
  1094             } else if ((refSym.flags() & PRIVATE) != 0) {
  1095                 return ClassFile.REF_invokeSpecial;
  1096             } else if (refSym.enclClass().isInterface()) {
  1097                 return ClassFile.REF_invokeInterface;
  1098             } else {
  1099                 return ClassFile.REF_invokeVirtual;
  1104     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1105     /**
  1106      * This visitor collects information about translation of a lambda expression.
  1107      * More specifically, it keeps track of the enclosing contexts and captured locals
  1108      * accessed by the lambda being translated (as well as other useful info).
  1109      * It also translates away problems for LambdaToMethod.
  1110      */
  1111     class LambdaAnalyzerPreprocessor extends TreeTranslator {
  1113         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1114         private List<Frame> frameStack;
  1116         /**
  1117          * keep the count of lambda expression (used to generate unambiguous
  1118          * names)
  1119          */
  1120         private int lambdaCount = 0;
  1122         /**
  1123          * keep the count of lambda expression defined in given context (used to
  1124          * generate unambiguous names for serializable lambdas)
  1125          */
  1126         private class SyntheticMethodNameCounter {
  1127             private Map<String, Integer> map = new HashMap<>();
  1128             int getIndex(StringBuilder buf) {
  1129                 String temp = buf.toString();
  1130                 Integer count = map.get(temp);
  1131                 if (count == null) {
  1132                     count = 0;
  1134                 ++count;
  1135                 map.put(temp, count);
  1136                 return count;
  1139         private SyntheticMethodNameCounter syntheticMethodNameCounts =
  1140                 new SyntheticMethodNameCounter();
  1142         private Map<Symbol, JCClassDecl> localClassDefs;
  1144         /**
  1145          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1146          * a static var init context
  1147          */
  1148         private Map<ClassSymbol, Symbol> clinits =
  1149                 new HashMap<ClassSymbol, Symbol>();
  1151         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
  1152             frameStack = List.nil();
  1153             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1154             return translate(tree);
  1157         @Override
  1158         public void visitBlock(JCBlock tree) {
  1159             List<Frame> prevStack = frameStack;
  1160             try {
  1161                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1162                     frameStack = frameStack.prepend(new Frame(tree));
  1164                 super.visitBlock(tree);
  1166             finally {
  1167                 frameStack = prevStack;
  1171         @Override
  1172         public void visitClassDef(JCClassDecl tree) {
  1173             List<Frame> prevStack = frameStack;
  1174             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
  1175                     syntheticMethodNameCounts;
  1176             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1177             DiagnosticSource prevSource = log.currentSource();
  1178             try {
  1179                 log.useSource(tree.sym.sourcefile);
  1180                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
  1181                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1182                 if (tree.sym.owner.kind == MTH) {
  1183                     localClassDefs.put(tree.sym, tree);
  1185                 if (directlyEnclosingLambda() != null) {
  1186                     tree.sym.owner = owner();
  1187                     if (tree.sym.hasOuterInstance()) {
  1188                         //if a class is defined within a lambda, the lambda must capture
  1189                         //its enclosing instance (if any)
  1190                         TranslationContext<?> localContext = context();
  1191                         while (localContext != null) {
  1192                             if (localContext.tree.getTag() == LAMBDA) {
  1193                                 ((LambdaTranslationContext)localContext)
  1194                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1196                             localContext = localContext.prev;
  1200                 frameStack = frameStack.prepend(new Frame(tree));
  1201                 super.visitClassDef(tree);
  1203             finally {
  1204                 log.useSource(prevSource.getFile());
  1205                 frameStack = prevStack;
  1206                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
  1207                 clinits = prevClinits;
  1211         @Override
  1212         public void visitIdent(JCIdent tree) {
  1213             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1214                 if (tree.sym.kind == VAR &&
  1215                         tree.sym.owner.kind == MTH &&
  1216                         tree.type.constValue() == null) {
  1217                     TranslationContext<?> localContext = context();
  1218                     while (localContext != null) {
  1219                         if (localContext.tree.getTag() == LAMBDA) {
  1220                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1221                             if (block == null) break;
  1222                             ((LambdaTranslationContext)localContext)
  1223                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1225                         localContext = localContext.prev;
  1227                 } else if (tree.sym.owner.kind == TYP) {
  1228                     TranslationContext<?> localContext = context();
  1229                     while (localContext != null) {
  1230                         if (localContext.tree.hasTag(LAMBDA)) {
  1231                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1232                             if (block == null) break;
  1233                             switch (block.getTag()) {
  1234                                 case CLASSDEF:
  1235                                     JCClassDecl cdecl = (JCClassDecl)block;
  1236                                     ((LambdaTranslationContext)localContext)
  1237                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1238                                     break;
  1239                                 default:
  1240                                     Assert.error("bad block kind");
  1243                         localContext = localContext.prev;
  1247             super.visitIdent(tree);
  1250         @Override
  1251         public void visitLambda(JCLambda tree) {
  1252             List<Frame> prevStack = frameStack;
  1253             try {
  1254                 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
  1255                 frameStack = frameStack.prepend(new Frame(tree));
  1256                 for (JCVariableDecl param : tree.params) {
  1257                     context.addSymbol(param.sym, PARAM);
  1258                     frameStack.head.addLocal(param.sym);
  1260                 contextMap.put(tree, context);
  1261                 super.visitLambda(tree);
  1262                 context.complete();
  1264             finally {
  1265                 frameStack = prevStack;
  1269         @Override
  1270         public void visitMethodDef(JCMethodDecl tree) {
  1271             List<Frame> prevStack = frameStack;
  1272             try {
  1273                 frameStack = frameStack.prepend(new Frame(tree));
  1274                 super.visitMethodDef(tree);
  1276             finally {
  1277                 frameStack = prevStack;
  1281         @Override
  1282         public void visitNewClass(JCNewClass tree) {
  1283             if (lambdaNewClassFilter(context(), tree)) {
  1284                 TranslationContext<?> localContext = context();
  1285                 while (localContext != null) {
  1286                     if (localContext.tree.getTag() == LAMBDA) {
  1287                         ((LambdaTranslationContext)localContext)
  1288                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1290                     localContext = localContext.prev;
  1293             if (context() != null && tree.type.tsym.owner.kind == MTH) {
  1294                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1295                 captureLocalClassDefs(tree.type.tsym, lambdaContext);
  1297             super.visitNewClass(tree);
  1299         //where
  1300             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1301                 JCClassDecl localCDef = localClassDefs.get(csym);
  1302                 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
  1303                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1304                         @Override
  1305                         void addFreeVars(ClassSymbol c) {
  1306                             captureLocalClassDefs(c, lambdaContext);
  1308                         @Override
  1309                         void visitSymbol(Symbol sym) {
  1310                             if (sym.kind == VAR &&
  1311                                     sym.owner.kind == MTH &&
  1312                                     ((VarSymbol)sym).getConstValue() == null) {
  1313                                 TranslationContext<?> localContext = context();
  1314                                 while (localContext != null) {
  1315                                     if (localContext.tree.getTag() == LAMBDA) {
  1316                                         JCTree block = capturedDecl(localContext.depth, sym);
  1317                                         if (block == null) break;
  1318                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1320                                     localContext = localContext.prev;
  1324                     };
  1325                     fvc.scan(localCDef);
  1329         /**
  1330          * Method references to local class constructors, may, if the local
  1331          * class references local variables, have implicit constructor
  1332          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1333          * information added in the LambdaToMethod pass will have the wrong
  1334          * signature. Hooks between Lower and LambdaToMethod have been added to
  1335          * handle normal "new" in this case. This visitor converts potentially
  1336          * effected method references into a lambda containing a normal "new" of
  1337          * the class.
  1339          * @param tree
  1340          */
  1341         @Override
  1342         public void visitReference(JCMemberReference tree) {
  1343             if (tree.getMode() == ReferenceMode.NEW
  1344                     && tree.kind != ReferenceKind.ARRAY_CTOR
  1345                     && tree.sym.owner.isLocal()) {
  1346                 MethodSymbol consSym = (MethodSymbol) tree.sym;
  1347                 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
  1348                 Type classType = consSym.owner.type;
  1350                 // Build lambda parameters
  1351                 // partially cloned from TreeMaker.Params until 8014021 is fixed
  1352                 Symbol owner = owner();
  1353                 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
  1354                 int i = 0;
  1355                 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
  1356                     JCVariableDecl param = make.Param(make.paramName(i++), l.head, owner);
  1357                     param.sym.pos = tree.pos;
  1358                     paramBuff.append(param);
  1360                 List<JCVariableDecl> params = paramBuff.toList();
  1362                 // Make new-class call
  1363                 JCNewClass nc = makeNewClass(classType, make.Idents(params));
  1364                 nc.pos = tree.pos;
  1366                 // Make lambda holding the new-class call
  1367                 JCLambda slam = make.Lambda(params, nc);
  1368                 slam.targets = tree.targets;
  1369                 slam.type = tree.type;
  1370                 slam.pos = tree.pos;
  1372                 // Now it is a lambda, process as such
  1373                 visitLambda(slam);
  1374             } else {
  1375                 super.visitReference(tree);
  1376                 contextMap.put(tree, makeReferenceContext(tree));
  1380         @Override
  1381         public void visitSelect(JCFieldAccess tree) {
  1382             if (context() != null && tree.sym.kind == VAR &&
  1383                         (tree.sym.name == names._this ||
  1384                          tree.sym.name == names._super)) {
  1385                 // A select of this or super means, if we are in a lambda,
  1386                 // we much have an instance context
  1387                 TranslationContext<?> localContext = context();
  1388                 while (localContext != null) {
  1389                     if (localContext.tree.hasTag(LAMBDA)) {
  1390                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1391                         if (clazz == null) break;
  1392                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1394                     localContext = localContext.prev;
  1397             super.visitSelect(tree);
  1400         @Override
  1401         public void visitVarDef(JCVariableDecl tree) {
  1402             TranslationContext<?> context = context();
  1403             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1404                     (LambdaTranslationContext)context :
  1405                     null;
  1406             if (ltc != null) {
  1407                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1408                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1410                 // Check for type variables (including as type arguments).
  1411                 // If they occur within class nested in a lambda, mark for erasure
  1412                 Type type = tree.sym.asType();
  1413                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1414                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1418             List<Frame> prevStack = frameStack;
  1419             try {
  1420                 if (tree.sym.owner.kind == MTH) {
  1421                     frameStack.head.addLocal(tree.sym);
  1423                 frameStack = frameStack.prepend(new Frame(tree));
  1424                 super.visitVarDef(tree);
  1426             finally {
  1427                 frameStack = prevStack;
  1431         /**
  1432          * Return a valid owner given the current declaration stack
  1433          * (required to skip synthetic lambda symbols)
  1434          */
  1435         private Symbol owner() {
  1436             return owner(false);
  1439         @SuppressWarnings("fallthrough")
  1440         private Symbol owner(boolean skipLambda) {
  1441             List<Frame> frameStack2 = frameStack;
  1442             while (frameStack2.nonEmpty()) {
  1443                 switch (frameStack2.head.tree.getTag()) {
  1444                     case VARDEF:
  1445                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1446                             frameStack2 = frameStack2.tail;
  1447                             break;
  1449                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1450                         return initSym(cdecl.sym,
  1451                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1452                     case BLOCK:
  1453                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1454                         return initSym(cdecl2.sym,
  1455                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1456                     case CLASSDEF:
  1457                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1458                     case METHODDEF:
  1459                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1460                     case LAMBDA:
  1461                         if (!skipLambda)
  1462                             return ((LambdaTranslationContext)contextMap
  1463                                     .get(frameStack2.head.tree)).translatedSym;
  1464                     default:
  1465                         frameStack2 = frameStack2.tail;
  1468             Assert.error();
  1469             return null;
  1472         private Symbol initSym(ClassSymbol csym, long flags) {
  1473             boolean isStatic = (flags & STATIC) != 0;
  1474             if (isStatic) {
  1475                 //static clinits are generated in Gen - so we need to fake them
  1476                 Symbol clinit = clinits.get(csym);
  1477                 if (clinit == null) {
  1478                     clinit = makePrivateSyntheticMethod(STATIC,
  1479                             names.clinit,
  1480                             new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
  1481                             csym);
  1482                     clinits.put(csym, clinit);
  1484                 return clinit;
  1485             } else {
  1486                 //get the first constructor and treat it as the instance init sym
  1487                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1488                     return s;
  1491             Assert.error("init not found");
  1492             return null;
  1495         private JCTree directlyEnclosingLambda() {
  1496             if (frameStack.isEmpty()) {
  1497                 return null;
  1499             List<Frame> frameStack2 = frameStack;
  1500             while (frameStack2.nonEmpty()) {
  1501                 switch (frameStack2.head.tree.getTag()) {
  1502                     case CLASSDEF:
  1503                     case METHODDEF:
  1504                         return null;
  1505                     case LAMBDA:
  1506                         return frameStack2.head.tree;
  1507                     default:
  1508                         frameStack2 = frameStack2.tail;
  1511             Assert.error();
  1512             return null;
  1515         private boolean inClassWithinLambda() {
  1516             if (frameStack.isEmpty()) {
  1517                 return false;
  1519             List<Frame> frameStack2 = frameStack;
  1520             boolean classFound = false;
  1521             while (frameStack2.nonEmpty()) {
  1522                 switch (frameStack2.head.tree.getTag()) {
  1523                     case LAMBDA:
  1524                         return classFound;
  1525                     case CLASSDEF:
  1526                         classFound = true;
  1527                         frameStack2 = frameStack2.tail;
  1528                         break;
  1529                     default:
  1530                         frameStack2 = frameStack2.tail;
  1533             // No lambda
  1534             return false;
  1537         /**
  1538          * Return the declaration corresponding to a symbol in the enclosing
  1539          * scope; the depth parameter is used to filter out symbols defined
  1540          * in nested scopes (which do not need to undergo capture).
  1541          */
  1542         private JCTree capturedDecl(int depth, Symbol sym) {
  1543             int currentDepth = frameStack.size() - 1;
  1544             for (Frame block : frameStack) {
  1545                 switch (block.tree.getTag()) {
  1546                     case CLASSDEF:
  1547                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1548                         if (sym.isMemberOf(clazz, types)) {
  1549                             return currentDepth > depth ? null : block.tree;
  1551                         break;
  1552                     case VARDEF:
  1553                         if (((JCVariableDecl)block.tree).sym == sym &&
  1554                                 sym.owner.kind == MTH) { //only locals are captured
  1555                             return currentDepth > depth ? null : block.tree;
  1557                         break;
  1558                     case BLOCK:
  1559                     case METHODDEF:
  1560                     case LAMBDA:
  1561                         if (block.locals != null && block.locals.contains(sym)) {
  1562                             return currentDepth > depth ? null : block.tree;
  1564                         break;
  1565                     default:
  1566                         Assert.error("bad decl kind " + block.tree.getTag());
  1568                 currentDepth--;
  1570             return null;
  1573         private TranslationContext<?> context() {
  1574             for (Frame frame : frameStack) {
  1575                 TranslationContext<?> context = contextMap.get(frame.tree);
  1576                 if (context != null) {
  1577                     return context;
  1580             return null;
  1583         /**
  1584          *  This is used to filter out those identifiers that needs to be adjusted
  1585          *  when translating away lambda expressions
  1586          */
  1587         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1588             return (sym.kind == VAR || sym.kind == MTH)
  1589                     && !sym.isStatic()
  1590                     && sym.name != names.init;
  1593         /**
  1594          * This is used to filter out those new class expressions that need to
  1595          * be qualified with an enclosing tree
  1596          */
  1597         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1598             if (context != null
  1599                     && tree.encl == null
  1600                     && tree.def == null
  1601                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1602                 Type encl = tree.type.getEnclosingType();
  1603                 Type current = context.owner.enclClass().type;
  1604                 while (!current.hasTag(NONE)) {
  1605                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1606                         return true;
  1608                     current = current.getEnclosingType();
  1610                 return false;
  1611             } else {
  1612                 return false;
  1616         private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
  1617             return new LambdaTranslationContext(tree);
  1620         private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
  1621             return new ReferenceTranslationContext(tree);
  1624         private class Frame {
  1625             final JCTree tree;
  1626             List<Symbol> locals;
  1628             public Frame(JCTree tree) {
  1629                 this.tree = tree;
  1632             void addLocal(Symbol sym) {
  1633                 if (locals == null) {
  1634                     locals = List.nil();
  1636                 locals = locals.prepend(sym);
  1640         /**
  1641          * This class is used to store important information regarding translation of
  1642          * lambda expression/method references (see subclasses).
  1643          */
  1644         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1646             /** the underlying (untranslated) tree */
  1647             final T tree;
  1649             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1650             final Symbol owner;
  1652             /** the depth of this lambda expression in the frame stack */
  1653             final int depth;
  1655             /** the enclosing translation context (set for nested lambdas/mref) */
  1656             final TranslationContext<?> prev;
  1658             /** list of methods to be bridged by the meta-factory */
  1659             final List<Symbol> bridges;
  1661             TranslationContext(T tree) {
  1662                 this.tree = tree;
  1663                 this.owner = owner();
  1664                 this.depth = frameStack.size() - 1;
  1665                 this.prev = context();
  1666                 ClassSymbol csym =
  1667                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1668                 this.bridges = types.functionalInterfaceBridges(csym);
  1671             /** does this functional expression need to be created using alternate metafactory? */
  1672             boolean needsAltMetafactory() {
  1673                 return tree.targets.length() > 1 ||
  1674                         isSerializable() ||
  1675                         bridges.length() > 1;
  1678             /** does this functional expression require serialization support? */
  1679             boolean isSerializable() {
  1680                 for (Type target : tree.targets) {
  1681                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1682                         return true;
  1685                 return false;
  1688             /**
  1689              * @return Name of the enclosing method to be folded into synthetic
  1690              * method name
  1691              */
  1692             String enclosingMethodName() {
  1693                 return syntheticMethodNameComponent(owner.name);
  1696             /**
  1697              * @return Method name in a form that can be folded into a
  1698              * component of a synthetic method name
  1699              */
  1700             String syntheticMethodNameComponent(Name name) {
  1701                 if (name == null) {
  1702                     return "null";
  1704                 String methodName = name.toString();
  1705                 if (methodName.equals("<clinit>")) {
  1706                     methodName = "static";
  1707                 } else if (methodName.equals("<init>")) {
  1708                     methodName = "new";
  1710                 return methodName;
  1714         /**
  1715          * This class retains all the useful information about a lambda expression;
  1716          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1717          * and the used by the main translation routines in order to adjust references
  1718          * to captured locals/members, etc.
  1719          */
  1720         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1722             /** variable in the enclosing context to which this lambda is assigned */
  1723             final Symbol self;
  1725             /** variable in the enclosing context to which this lambda is assigned */
  1726             final Symbol assignedTo;
  1728             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
  1730             /** the synthetic symbol for the method hoisting the translated lambda */
  1731             Symbol translatedSym;
  1733             List<JCVariableDecl> syntheticParams;
  1735             LambdaTranslationContext(JCLambda tree) {
  1736                 super(tree);
  1737                 Frame frame = frameStack.head;
  1738                 switch (frame.tree.getTag()) {
  1739                     case VARDEF:
  1740                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
  1741                         break;
  1742                     case ASSIGN:
  1743                         self = null;
  1744                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
  1745                         break;
  1746                     default:
  1747                         assignedTo = self = null;
  1748                         break;
  1751                 // This symbol will be filled-in in complete
  1752                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
  1754                 if (dumpLambdaToMethodStats) {
  1755                     log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym);
  1757                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
  1759                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
  1760                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
  1761                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
  1762                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
  1763                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
  1766              /**
  1767              * For a serializable lambda, generate a disambiguating string
  1768              * which maximizes stability across deserialization.
  1770              * @return String to differentiate synthetic lambda method names
  1771              */
  1772             private String serializedLambdaDisambiguation() {
  1773                 StringBuilder buf = new StringBuilder();
  1774                 // Append the enclosing method signature to differentiate
  1775                 // overloaded enclosing methods.  For lambdas enclosed in
  1776                 // lambdas, the generated lambda method will not have type yet,
  1777                 // but the enclosing method's name will have been generated
  1778                 // with this same method, so it will be unique and never be
  1779                 // overloaded.
  1780                 Assert.check(
  1781                         owner.type != null ||
  1782                         directlyEnclosingLambda() != null);
  1783                 if (owner.type != null) {
  1784                     buf.append(typeSig(owner.type));
  1785                     buf.append(":");
  1788                 // Add target type info
  1789                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
  1790                 buf.append(" ");
  1792                 // Add variable assigned to
  1793                 if (assignedTo != null) {
  1794                     buf.append(assignedTo.flatName());
  1795                     buf.append("=");
  1797                 //add captured locals info: type, name, order
  1798                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
  1799                     if (fv != self) {
  1800                         buf.append(typeSig(fv.type));
  1801                         buf.append(" ");
  1802                         buf.append(fv.flatName());
  1803                         buf.append(",");
  1807                 return buf.toString();
  1810             /**
  1811              * For a non-serializable lambda, generate a simple method.
  1813              * @return Name to use for the synthetic lambda method name
  1814              */
  1815             private Name lambdaName() {
  1816                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
  1819             /**
  1820              * For a serializable lambda, generate a method name which maximizes
  1821              * name stability across deserialization.
  1823              * @return Name to use for the synthetic lambda method name
  1824              */
  1825             private Name serializedLambdaName() {
  1826                 StringBuilder buf = new StringBuilder();
  1827                 buf.append(names.lambda);
  1828                 // Append the name of the method enclosing the lambda.
  1829                 buf.append(enclosingMethodName());
  1830                 buf.append('$');
  1831                 // Append a hash of the disambiguating string : enclosing method
  1832                 // signature, etc.
  1833                 String disam = serializedLambdaDisambiguation();
  1834                 buf.append(Integer.toHexString(disam.hashCode()));
  1835                 buf.append('$');
  1836                 // The above appended name components may not be unique, append
  1837                 // a count based on the above name components.
  1838                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  1839                 String result = buf.toString();
  1840                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
  1841                 return names.fromString(result);
  1844             /**
  1845              * Translate a symbol of a given kind into something suitable for the
  1846              * synthetic lambda body
  1847              */
  1848             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1849                 Symbol ret;
  1850                 switch (skind) {
  1851                     case CAPTURED_THIS:
  1852                         ret = sym;  // self represented
  1853                         break;
  1854                     case TYPE_VAR:
  1855                         // Just erase the type var
  1856                         ret = new VarSymbol(sym.flags(), name,
  1857                                 types.erasure(sym.type), sym.owner);
  1859                         /* this information should also be kept for LVT generation at Gen
  1860                          * a Symbol with pos < startPos won't be tracked.
  1861                          */
  1862                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
  1863                         break;
  1864                     case CAPTURED_VAR:
  1865                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
  1866                             @Override
  1867                             public Symbol baseSymbol() {
  1868                                 //keep mapping with original captured symbol
  1869                                 return sym;
  1871                         };
  1872                         break;
  1873                     case LOCAL_VAR:
  1874                         ret = new VarSymbol(FINAL, name, types.erasure(sym.type), translatedSym);
  1875                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1876                         break;
  1877                     case PARAM:
  1878                         ret = new VarSymbol(FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym);
  1879                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1880                         break;
  1881                     default:
  1882                         ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1883                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1885                 if (ret != sym) {
  1886                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1887                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1889                 return ret;
  1892             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1893                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
  1894                 Name preferredName;
  1895                 switch (skind) {
  1896                     case CAPTURED_THIS:
  1897                         preferredName = names.fromString("encl$" + transMap.size());
  1898                         break;
  1899                     case CAPTURED_VAR:
  1900                         preferredName = names.fromString("cap$" + transMap.size());
  1901                         break;
  1902                     case LOCAL_VAR:
  1903                         preferredName = sym.name;
  1904                         break;
  1905                     case PARAM:
  1906                         preferredName = sym.name;
  1907                         break;
  1908                     case TYPE_VAR:
  1909                         preferredName = sym.name;
  1910                         break;
  1911                     default: throw new AssertionError();
  1913                 if (!transMap.containsKey(sym)) {
  1914                     transMap.put(sym, translate(preferredName, sym, skind));
  1918             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
  1919                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
  1920                 Assert.checkNonNull(m);
  1921                 return m;
  1924             JCTree translate(JCIdent lambdaIdent) {
  1925                 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
  1926                     if (m.containsKey(lambdaIdent.sym)) {
  1927                         Symbol tSym = m.get(lambdaIdent.sym);
  1928                         JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
  1929                         tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
  1930                         return t;
  1933                 return null;
  1936             /**
  1937              * The translatedSym is not complete/accurate until the analysis is
  1938              * finished.  Once the analysis is finished, the translatedSym is
  1939              * "completed" -- updated with type information, access modifiers,
  1940              * and full parameter list.
  1941              */
  1942             void complete() {
  1943                 if (syntheticParams != null) {
  1944                     return;
  1946                 boolean inInterface = translatedSym.owner.isInterface();
  1947                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1949                 // If instance access isn't needed, make it static.
  1950                 // Interface instance methods must be default methods.
  1951                 // Lambda methods are private synthetic.
  1952                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
  1953                         PRIVATE |
  1954                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  1956                 //compute synthetic params
  1957                 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
  1959                 // The signature of the method is augmented with the following
  1960                 // synthetic parameters:
  1961                 //
  1962                 // 1) reference to enclosing contexts captured by the lambda expression
  1963                 // 2) enclosing locals captured by the lambda expression
  1964                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
  1965                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1967                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
  1968                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1970                 syntheticParams = params.toList();
  1972                 // Compute and set the lambda name
  1973                 translatedSym.name = isSerializable()
  1974                         ? serializedLambdaName()
  1975                         : lambdaName();
  1977                 //prepend synthetic args to translated lambda method signature
  1978                 translatedSym.type = types.createMethodTypeWithParameters(
  1979                         generatedLambdaSig(),
  1980                         TreeInfo.types(syntheticParams));
  1983             Type generatedLambdaSig() {
  1984                 return types.erasure(tree.getDescriptorType(types));
  1988         /**
  1989          * This class retains all the useful information about a method reference;
  1990          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1991          * and the used by the main translation routines in order to adjust method
  1992          * references (i.e. in case a bridge is needed)
  1993          */
  1994         private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  1996             final boolean isSuper;
  1997             final Symbol bridgeSym;
  1999             ReferenceTranslationContext(JCMemberReference tree) {
  2000                 super(tree);
  2001                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2002                 this.bridgeSym = needsBridge()
  2003                         ? makePrivateSyntheticMethod(isSuper ? 0 : STATIC,
  2004                                               referenceBridgeName(), null,
  2005                                               owner.enclClass())
  2006                         : null;
  2007                 if (dumpLambdaToMethodStats) {
  2008                     String key = bridgeSym == null ?
  2009                             "mref.stat" : "mref.stat.1";
  2010                     log.note(tree, key, needsAltMetafactory(), bridgeSym);
  2014             /**
  2015              * Get the opcode associated with this method reference
  2016              */
  2017             int referenceKind() {
  2018                 return LambdaToMethod.this.referenceKind(needsBridge()
  2019                         ? bridgeSym
  2020                         : tree.sym);
  2023             boolean needsVarArgsConversion() {
  2024                 return tree.varargsElement != null;
  2027             /**
  2028              * Generate a disambiguating string to increase stability (important
  2029              * if serialized)
  2031              * @return String to differentiate synthetic lambda method names
  2032              */
  2033             private String referenceBridgeDisambiguation() {
  2034                 StringBuilder buf = new StringBuilder();
  2035                 // Append the enclosing method signature to differentiate
  2036                 // overloaded enclosing methods.
  2037                 if (owner.type != null) {
  2038                     buf.append(typeSig(owner.type));
  2039                     buf.append(":");
  2042                 // Append qualifier type
  2043                 buf.append(classSig(tree.sym.owner.type));
  2045                 // Note static/instance
  2046                 buf.append(tree.sym.isStatic()? " S " : " I ");
  2048                 // Append referenced signature
  2049                 buf.append(typeSig(tree.sym.erasure(types)));
  2051                 return buf.toString();
  2054             /**
  2055              * Construct a unique stable name for the method reference bridge
  2057              * @return Name to use for the synthetic method name
  2058              */
  2059             private Name referenceBridgeName() {
  2060                 StringBuilder buf = new StringBuilder();
  2061                 // Append lambda ID, this is semantically significant
  2062                 buf.append(names.lambda);
  2063                 // Note that it is a method reference bridge
  2064                 buf.append("MR$");
  2065                 // Append the enclosing method name
  2066                 buf.append(enclosingMethodName());
  2067                 buf.append('$');
  2068                 // Append the referenced method name
  2069                 buf.append(syntheticMethodNameComponent(tree.sym.name));
  2070                 buf.append('$');
  2071                 // Append a hash of the disambiguating string : enclosing method
  2072                 // signature, etc.
  2073                 String disam = referenceBridgeDisambiguation();
  2074                 buf.append(Integer.toHexString(disam.hashCode()));
  2075                 buf.append('$');
  2076                 // The above appended name components may not be unique, append
  2077                 // a count based on the above name components.
  2078                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  2079                 String result = buf.toString();
  2080                 return names.fromString(result);
  2083             /**
  2084              * @return Is this an array operation like clone()
  2085              */
  2086             boolean isArrayOp() {
  2087                 return tree.sym.owner == syms.arrayClass;
  2090             boolean receiverAccessible() {
  2091                 //hack needed to workaround 292 bug (7087658)
  2092                 //when 292 issue is fixed we should remove this and change the backend
  2093                 //code to always generate a method handle to an accessible method
  2094                 return tree.ownerAccessible;
  2097             /**
  2098              * The VM does not support access across nested classes (8010319).
  2099              * Were that ever to change, this should be removed.
  2100              */
  2101             boolean isPrivateInOtherClass() {
  2102                 return  (tree.sym.flags() & PRIVATE) != 0 &&
  2103                         !types.isSameType(
  2104                               types.erasure(tree.sym.enclClass().asType()),
  2105                               types.erasure(owner.enclClass().asType()));
  2108             /**
  2109              * Does this reference needs a bridge (i.e. var args need to be
  2110              * expanded or "super" is used)
  2111              */
  2112             final boolean needsBridge() {
  2113                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  2114                         isPrivateInOtherClass() ||
  2115                         !receiverAccessible();
  2118             Type generatedRefSig() {
  2119                 return types.erasure(tree.sym.type);
  2122             Type bridgedRefSig() {
  2123                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  2127     // </editor-fold>
  2129     /*
  2130      * These keys provide mappings for various translated lambda symbols
  2131      * and the prevailing order must be maintained.
  2132      */
  2133     enum LambdaSymbolKind {
  2134         PARAM,          // original to translated lambda parameters
  2135         LOCAL_VAR,      // original to translated lambda locals
  2136         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
  2137         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
  2138         TYPE_VAR;       // original to translated lambda type variables
  2141     /**
  2142      * ****************************************************************
  2143      * Signature Generation
  2144      * ****************************************************************
  2145      */
  2147     private String typeSig(Type type) {
  2148         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2149         sg.assembleSig(type);
  2150         return sg.toString();
  2153     private String classSig(Type type) {
  2154         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2155         sg.assembleClassSig(type);
  2156         return sg.toString();
  2159     /**
  2160      * Signature Generation
  2161      */
  2162     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  2164         /**
  2165          * An output buffer for type signatures.
  2166          */
  2167         StringBuilder sb = new StringBuilder();
  2169         L2MSignatureGenerator() {
  2170             super(types);
  2173         @Override
  2174         protected void append(char ch) {
  2175             sb.append(ch);
  2178         @Override
  2179         protected void append(byte[] ba) {
  2180             sb.append(new String(ba));
  2183         @Override
  2184         protected void append(Name name) {
  2185             sb.append(name.toString());
  2188         @Override
  2189         public String toString() {
  2190             return sb.toString();

mercurial