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

Mon, 24 Nov 2014 14:55:38 -0800

author
vromero
date
Mon, 24 Nov 2014 14:55:38 -0800
changeset 2610
f4df97bf5392
parent 2607
10e9228e77b0
child 2614
b5c8adb2206a
permissions
-rw-r--r--

8059921: Missing compile error in Java 8 mode for Interface.super.field access
Reviewed-by: mcimadamore, jlahoda

     1 /*
     2  * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 package com.sun.tools.javac.comp;
    27 import com.sun.tools.javac.tree.*;
    28 import com.sun.tools.javac.tree.JCTree.*;
    29 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
    30 import com.sun.tools.javac.tree.TreeMaker;
    31 import com.sun.tools.javac.tree.TreeTranslator;
    32 import com.sun.tools.javac.code.Attribute;
    33 import com.sun.tools.javac.code.Kinds;
    34 import com.sun.tools.javac.code.Scope;
    35 import com.sun.tools.javac.code.Symbol;
    36 import com.sun.tools.javac.code.Symbol.ClassSymbol;
    37 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
    38 import com.sun.tools.javac.code.Symbol.MethodSymbol;
    39 import com.sun.tools.javac.code.Symbol.TypeSymbol;
    40 import com.sun.tools.javac.code.Symbol.VarSymbol;
    41 import com.sun.tools.javac.code.Symtab;
    42 import com.sun.tools.javac.code.Type;
    43 import com.sun.tools.javac.code.Type.MethodType;
    44 import com.sun.tools.javac.code.Types;
    45 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
    46 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
    47 import com.sun.tools.javac.jvm.*;
    48 import com.sun.tools.javac.util.*;
    49 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    50 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
    52 import java.util.EnumMap;
    53 import java.util.HashMap;
    54 import java.util.HashSet;
    55 import java.util.LinkedHashMap;
    56 import java.util.Map;
    57 import java.util.Set;
    59 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
    60 import static com.sun.tools.javac.code.Flags.*;
    61 import static com.sun.tools.javac.code.Kinds.*;
    62 import static com.sun.tools.javac.code.TypeTag.*;
    63 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    65 /**
    66  * This pass desugars lambda expressions into static methods
    67  *
    68  *  <p><b>This is NOT part of any supported API.
    69  *  If you write code that depends on this, you do so at your own risk.
    70  *  This code and its internal interfaces are subject to change or
    71  *  deletion without notice.</b>
    72  */
    73 public class LambdaToMethod extends TreeTranslator {
    75     private Attr attr;
    76     private JCDiagnostic.Factory diags;
    77     private Log log;
    78     private Lower lower;
    79     private Names names;
    80     private Symtab syms;
    81     private Resolve rs;
    82     private TreeMaker make;
    83     private Types types;
    84     private TransTypes transTypes;
    85     private Env<AttrContext> attrEnv;
    87     /** the analyzer scanner */
    88     private LambdaAnalyzerPreprocessor analyzer;
    90     /** map from lambda trees to translation contexts */
    91     private Map<JCTree, TranslationContext<?>> contextMap;
    93     /** current translation context (visitor argument) */
    94     private TranslationContext<?> context;
    96     /** info about the current class being processed */
    97     private KlassInfo kInfo;
    99     /** dump statistics about lambda code generation */
   100     private boolean dumpLambdaToMethodStats;
   102     /** force serializable representation, for stress testing **/
   103     private final boolean forceSerializable;
   105     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
   106     public static final int FLAG_SERIALIZABLE = 1 << 0;
   108     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
   109     public static final int FLAG_MARKERS = 1 << 1;
   111     /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
   112     public static final int FLAG_BRIDGES = 1 << 2;
   114     // <editor-fold defaultstate="collapsed" desc="Instantiating">
   115     protected static final Context.Key<LambdaToMethod> unlambdaKey =
   116             new Context.Key<LambdaToMethod>();
   118     public static LambdaToMethod instance(Context context) {
   119         LambdaToMethod instance = context.get(unlambdaKey);
   120         if (instance == null) {
   121             instance = new LambdaToMethod(context);
   122         }
   123         return instance;
   124     }
   125     private LambdaToMethod(Context context) {
   126         context.put(unlambdaKey, this);
   127         diags = JCDiagnostic.Factory.instance(context);
   128         log = Log.instance(context);
   129         lower = Lower.instance(context);
   130         names = Names.instance(context);
   131         syms = Symtab.instance(context);
   132         rs = Resolve.instance(context);
   133         make = TreeMaker.instance(context);
   134         types = Types.instance(context);
   135         transTypes = TransTypes.instance(context);
   136         analyzer = new LambdaAnalyzerPreprocessor();
   137         Options options = Options.instance(context);
   138         dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats");
   139         attr = Attr.instance(context);
   140         forceSerializable = options.isSet("forceSerializable");
   141     }
   142     // </editor-fold>
   144     private class KlassInfo {
   146         /**
   147          * list of methods to append
   148          */
   149         private ListBuffer<JCTree> appendedMethodList;
   151         /**
   152          * list of deserialization cases
   153          */
   154         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   156        /**
   157          * deserialize method symbol
   158          */
   159         private final MethodSymbol deserMethodSym;
   161         /**
   162          * deserialize method parameter symbol
   163          */
   164         private final VarSymbol deserParamSym;
   166         private final JCClassDecl clazz;
   168         private KlassInfo(JCClassDecl clazz) {
   169             this.clazz = clazz;
   170             appendedMethodList = new ListBuffer<>();
   171             deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
   172             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
   173                     List.<Type>nil(), syms.methodClass);
   174             deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
   175             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
   176                     syms.serializedLambdaType, deserMethodSym);
   177         }
   179         private void addMethod(JCTree decl) {
   180             appendedMethodList = appendedMethodList.prepend(decl);
   181         }
   182     }
   184     // <editor-fold defaultstate="collapsed" desc="translate methods">
   185     @Override
   186     public <T extends JCTree> T translate(T tree) {
   187         TranslationContext<?> newContext = contextMap.get(tree);
   188         return translate(tree, newContext != null ? newContext : context);
   189     }
   191     <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
   192         TranslationContext<?> prevContext = context;
   193         try {
   194             context = newContext;
   195             return super.translate(tree);
   196         }
   197         finally {
   198             context = prevContext;
   199         }
   200     }
   202     <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
   203         ListBuffer<T> buf = new ListBuffer<>();
   204         for (T tree : trees) {
   205             buf.append(translate(tree, newContext));
   206         }
   207         return buf.toList();
   208     }
   210     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
   211         this.make = make;
   212         this.attrEnv = env;
   213         this.context = null;
   214         this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
   215         return translate(cdef);
   216     }
   217     // </editor-fold>
   219     // <editor-fold defaultstate="collapsed" desc="visitor methods">
   220     /**
   221      * Visit a class.
   222      * Maintain the translatedMethodList across nested classes.
   223      * Append the translatedMethodList to the class after it is translated.
   224      * @param tree
   225      */
   226     @Override
   227     public void visitClassDef(JCClassDecl tree) {
   228         if (tree.sym.owner.kind == PCK) {
   229             //analyze class
   230             tree = analyzer.analyzeAndPreprocessClass(tree);
   231         }
   232         KlassInfo prevKlassInfo = kInfo;
   233         try {
   234             kInfo = new KlassInfo(tree);
   235             super.visitClassDef(tree);
   236             if (!kInfo.deserializeCases.isEmpty()) {
   237                 int prevPos = make.pos;
   238                 try {
   239                     make.at(tree);
   240                     kInfo.addMethod(makeDeserializeMethod(tree.sym));
   241                 } finally {
   242                     make.at(prevPos);
   243                 }
   244             }
   245             //add all translated instance methods here
   246             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
   247             tree.defs = tree.defs.appendList(newMethods);
   248             for (JCTree lambda : newMethods) {
   249                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
   250             }
   251             result = tree;
   252         } finally {
   253             kInfo = prevKlassInfo;
   254         }
   255     }
   257     /**
   258      * Translate a lambda into a method to be inserted into the class.
   259      * Then replace the lambda site with an invokedynamic call of to lambda
   260      * meta-factory, which will use the lambda method.
   261      * @param tree
   262      */
   263     @Override
   264     public void visitLambda(JCLambda tree) {
   265         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
   266         MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
   267         MethodType lambdaType = (MethodType) sym.type;
   269         {
   270             Symbol owner = localContext.owner;
   271             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   272             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   274             for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
   275                 if (tc.position.onLambda == tree) {
   276                     lambdaTypeAnnos.append(tc);
   277                 } else {
   278                     ownerTypeAnnos.append(tc);
   279                 }
   280             }
   281             if (lambdaTypeAnnos.nonEmpty()) {
   282                 owner.setTypeAttributes(ownerTypeAnnos.toList());
   283                 sym.setTypeAttributes(lambdaTypeAnnos.toList());
   284             }
   285         }
   287         //create the method declaration hoisting the lambda body
   288         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
   289                 sym.name,
   290                 make.QualIdent(lambdaType.getReturnType().tsym),
   291                 List.<JCTypeParameter>nil(),
   292                 localContext.syntheticParams,
   293                 lambdaType.getThrownTypes() == null ?
   294                     List.<JCExpression>nil() :
   295                     make.Types(lambdaType.getThrownTypes()),
   296                 null,
   297                 null);
   298         lambdaDecl.sym = sym;
   299         lambdaDecl.type = lambdaType;
   301         //translate lambda body
   302         //As the lambda body is translated, all references to lambda locals,
   303         //captured variables, enclosing members are adjusted accordingly
   304         //to refer to the static method parameters (rather than i.e. acessing to
   305         //captured members directly).
   306         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
   308         //Add the method to the list of methods to be added to this class.
   309         kInfo.addMethod(lambdaDecl);
   311         //now that we have generated a method for the lambda expression,
   312         //we can translate the lambda into a method reference pointing to the newly
   313         //created method.
   314         //
   315         //Note that we need to adjust the method handle so that it will match the
   316         //signature of the SAM descriptor - this means that the method reference
   317         //should be added the following synthetic arguments:
   318         //
   319         // * the "this" argument if it is an instance method
   320         // * enclosing locals captured by the lambda expression
   322         ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
   324         if (localContext.methodReferenceReceiver != null) {
   325             syntheticInits.append(localContext.methodReferenceReceiver);
   326         } else if (!sym.isStatic()) {
   327             syntheticInits.append(makeThis(
   328                     sym.owner.enclClass().asType(),
   329                     localContext.owner.enclClass()));
   330         }
   332         //add captured locals
   333         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
   334             if (fv != localContext.self) {
   335                 JCTree captured_local = make.Ident(fv).setType(fv.type);
   336                 syntheticInits.append((JCExpression) captured_local);
   337             }
   338         }
   340         //then, determine the arguments to the indy call
   341         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   343         //build a sam instance using an indy call to the meta-factory
   344         int refKind = referenceKind(sym);
   346         //convert to an invokedynamic call
   347         result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
   348     }
   350     private JCIdent makeThis(Type type, Symbol owner) {
   351         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
   352                 names._this,
   353                 type,
   354                 owner);
   355         return make.Ident(_this);
   356     }
   358     /**
   359      * Translate a method reference into an invokedynamic call to the
   360      * meta-factory.
   361      * @param tree
   362      */
   363     @Override
   364     public void visitReference(JCMemberReference tree) {
   365         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   367         //first determine the method symbol to be used to generate the sam instance
   368         //this is either the method reference symbol, or the bridged reference symbol
   369         Symbol refSym = localContext.isSignaturePolymorphic()
   370                 ? localContext.sigPolySym
   371                 : tree.sym;
   373         //the qualifying expression is treated as a special captured arg
   374         JCExpression init;
   375         switch(tree.kind) {
   377             case IMPLICIT_INNER:    /** Inner :: new */
   378             case SUPER:             /** super :: instMethod */
   379                 init = makeThis(
   380                     localContext.owner.enclClass().asType(),
   381                     localContext.owner.enclClass());
   382                 break;
   384             case BOUND:             /** Expr :: instMethod */
   385                 init = tree.getQualifierExpression();
   386                 init = attr.makeNullCheck(init);
   387                 break;
   389             case UNBOUND:           /** Type :: instMethod */
   390             case STATIC:            /** Type :: staticMethod */
   391             case TOPLEVEL:          /** Top level :: new */
   392             case ARRAY_CTOR:        /** ArrayType :: new */
   393                 init = null;
   394                 break;
   396             default:
   397                 throw new InternalError("Should not have an invalid kind");
   398         }
   400         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
   403         //build a sam instance using an indy call to the meta-factory
   404         result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
   405     }
   407     /**
   408      * Translate identifiers within a lambda to the mapped identifier
   409      * @param tree
   410      */
   411     @Override
   412     public void visitIdent(JCIdent tree) {
   413         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
   414             super.visitIdent(tree);
   415         } else {
   416             int prevPos = make.pos;
   417             try {
   418                 make.at(tree);
   420                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
   421                 JCTree ltree = lambdaContext.translate(tree);
   422                 if (ltree != null) {
   423                     result = ltree;
   424                 } else {
   425                     //access to untranslated symbols (i.e. compile-time constants,
   426                     //members defined inside the lambda body, etc.) )
   427                     super.visitIdent(tree);
   428                 }
   429             } finally {
   430                 make.at(prevPos);
   431             }
   432         }
   433     }
   435     @Override
   436     public void visitVarDef(JCVariableDecl tree) {
   437         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
   438         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   439             tree.init = translate(tree.init);
   440             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
   441             result = tree;
   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      * Converts a method reference which cannot be used directly into a lambda
   743      */
   744     private class MemberReferenceToLambda {
   746         private final JCMemberReference tree;
   747         private final ReferenceTranslationContext localContext;
   748         private final Symbol owner;
   749         private final ListBuffer<JCExpression> args = new ListBuffer<>();
   750         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
   752         private JCExpression receiverExpression = null;
   754         MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) {
   755             this.tree = tree;
   756             this.localContext = localContext;
   757             this.owner = owner;
   758         }
   760         JCLambda lambda() {
   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 in the case where the member
   768                 // reference is an unbound instance method reference (in which
   769                 // case the receiver expression in passed.
   770                 VarSymbol rcvr;
   771                 switch (tree.kind) {
   772                     case BOUND:
   773                         rcvr = addParameter("rec$", tree.getQualifierExpression().type, false);
   774                         receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
   775                         break;
   776                     case UNBOUND:
   777                         rcvr = addParameter("rec$", samPTypes.head, false);
   778                         samPTypes = samPTypes.tail;
   779                         break;
   780                     default:
   781                         rcvr = null;
   782                         break;
   783                 }
   785                 // generate the parameter list for the coverted member reference.
   786                 // the signature will match the signature of the target sam descriptor
   788                 List<Type> refPTypes = tree.sym.type.getParameterTypes();
   789                 int refSize = refPTypes.size();
   790                 int samSize = samPTypes.size();
   791                 // Last parameter to copy from referenced method
   792                 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
   794                 List<Type> l = refPTypes;
   795                 // Use parameter types of the referenced method, excluding final var args
   796                 for (int i = 0; l.nonEmpty() && i < last; ++i) {
   797                     addParameter("x$" + i, l.head, true);
   798                     l = l.tail;
   799                 }
   800                 // Flatten out the var args
   801                 for (int i = last; i < samSize; ++i) {
   802                     addParameter("xva$" + i, tree.varargsElement, true);
   803                 }
   805                 //body generation - this can be either a method call or a
   806                 //new instance creation expression, depending on the member reference kind
   807                 JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
   808                         ? expressionInvoke(rcvr)
   809                         : expressionNew();
   811                 JCLambda slam = make.Lambda(params.toList(), expr);
   812                 slam.targets = tree.targets;
   813                 slam.type = tree.type;
   814                 slam.pos = tree.pos;
   815                 return slam;
   816             } finally {
   817                 make.at(prevPos);
   818             }
   819         }
   821         JCExpression getReceiverExpression() {
   822             return receiverExpression;
   823         }
   825         private JCExpression makeReceiver(VarSymbol rcvr) {
   826             if (rcvr == null) return null;
   827             JCExpression rcvrExpr = make.Ident(rcvr);
   828             Type rcvrType = tree.sym.enclClass().type;
   829             if (rcvrType == syms.arrayClass.type) {
   830                 // Map the receiver type to the actually type, not just "array"
   831                 rcvrType = tree.getQualifierExpression().type;
   832             }
   833             if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   834                 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   835             }
   836             return rcvrExpr;
   837         }
   839         /**
   840          * determine the receiver of the method call - the receiver can
   841          * be a type qualifier, the synthetic receiver parameter or 'super'.
   842          */
   843         private JCExpression expressionInvoke(VarSymbol rcvr) {
   844             JCExpression qualifier =
   845                     tree.sym.isStatic() ?
   846                         make.Type(tree.sym.owner.type) :
   847                         (rcvr != null) ?
   848                             makeReceiver(rcvr) :
   849                             tree.getQualifierExpression();
   851             //create the qualifier expression
   852             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   853             select.sym = tree.sym;
   854             select.type = tree.sym.erasure(types);
   856             //create the method call expression
   857             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   858                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   859                     setType(tree.sym.erasure(types).getReturnType());
   861             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   862             setVarargsIfNeeded(apply, tree.varargsElement);
   863             return apply;
   864         }
   866         /**
   867          * Lambda body to use for a 'new'.
   868          */
   869         private JCExpression expressionNew() {
   870             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   871                 //create the array creation expression
   872                 JCNewArray newArr = make.NewArray(
   873                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   874                         List.of(make.Ident(params.first())),
   875                         null);
   876                 newArr.type = tree.getQualifierExpression().type;
   877                 return newArr;
   878             } else {
   879                 //create the instance creation expression
   880                 //note that method reference syntax does not allow an explicit
   881                 //enclosing class (so the enclosing class is null)
   882                 JCNewClass newClass = make.NewClass(null,
   883                         List.<JCExpression>nil(),
   884                         make.Type(tree.getQualifierExpression().type),
   885                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   886                         null);
   887                 newClass.constructor = tree.sym;
   888                 newClass.constructorType = tree.sym.erasure(types);
   889                 newClass.type = tree.getQualifierExpression().type;
   890                 setVarargsIfNeeded(newClass, tree.varargsElement);
   891                 return newClass;
   892             }
   893         }
   895         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   896             VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
   897             vsym.pos = tree.pos;
   898             params.append(make.VarDef(vsym, null));
   899             if (genArg) {
   900                 args.append(make.Ident(vsym));
   901             }
   902             return vsym;
   903         }
   904     }
   906     private MethodType typeToMethodType(Type mt) {
   907         Type type = types.erasure(mt);
   908         return new MethodType(type.getParameterTypes(),
   909                         type.getReturnType(),
   910                         type.getThrownTypes(),
   911                         syms.methodClass);
   912     }
   914     /**
   915      * Generate an indy method call to the meta factory
   916      */
   917     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
   918             int refKind, Symbol refSym, List<JCExpression> indy_args) {
   919         JCFunctionalExpression tree = context.tree;
   920         //determine the static bsm args
   921         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   922         List<Object> staticArgs = List.<Object>of(
   923                 typeToMethodType(samSym.type),
   924                 new Pool.MethodHandle(refKind, refSym, types),
   925                 typeToMethodType(tree.getDescriptorType(types)));
   927         //computed indy arg types
   928         ListBuffer<Type> indy_args_types = new ListBuffer<>();
   929         for (JCExpression arg : indy_args) {
   930             indy_args_types.append(arg.type);
   931         }
   933         //finally, compute the type of the indy call
   934         MethodType indyType = new MethodType(indy_args_types.toList(),
   935                 tree.type,
   936                 List.<Type>nil(),
   937                 syms.methodClass);
   939         Name metafactoryName = context.needsAltMetafactory() ?
   940                 names.altMetafactory : names.metafactory;
   942         if (context.needsAltMetafactory()) {
   943             ListBuffer<Object> markers = new ListBuffer<>();
   944             for (Type t : tree.targets.tail) {
   945                 if (t.tsym != syms.serializableType.tsym) {
   946                     markers.append(t.tsym);
   947                 }
   948             }
   949             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
   950             boolean hasMarkers = markers.nonEmpty();
   951             boolean hasBridges = context.bridges.nonEmpty();
   952             if (hasMarkers) {
   953                 flags |= FLAG_MARKERS;
   954             }
   955             if (hasBridges) {
   956                 flags |= FLAG_BRIDGES;
   957             }
   958             staticArgs = staticArgs.append(flags);
   959             if (hasMarkers) {
   960                 staticArgs = staticArgs.append(markers.length());
   961                 staticArgs = staticArgs.appendList(markers.toList());
   962             }
   963             if (hasBridges) {
   964                 staticArgs = staticArgs.append(context.bridges.length() - 1);
   965                 for (Symbol s : context.bridges) {
   966                     Type s_erasure = s.erasure(types);
   967                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
   968                         staticArgs = staticArgs.append(s.erasure(types));
   969                     }
   970                 }
   971             }
   972             if (context.isSerializable()) {
   973                 int prevPos = make.pos;
   974                 try {
   975                     make.at(kInfo.clazz);
   976                     addDeserializationCase(refKind, refSym, tree.type, samSym,
   977                             tree, staticArgs, indyType);
   978                 } finally {
   979                     make.at(prevPos);
   980                 }
   981             }
   982         }
   984         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
   985     }
   987     /**
   988      * Generate an indy method call with given name, type and static bootstrap
   989      * arguments types
   990      */
   991     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
   992             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
   993             Name methName) {
   994         int prevPos = make.pos;
   995         try {
   996             make.at(pos);
   997             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
   998                     syms.stringType,
   999                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
  1001             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
  1002                     bsmName, bsm_staticArgs, List.<Type>nil());
  1004             DynamicMethodSymbol dynSym =
  1005                     new DynamicMethodSymbol(methName,
  1006                                             syms.noSymbol,
  1007                                             bsm.isStatic() ?
  1008                                                 ClassFile.REF_invokeStatic :
  1009                                                 ClassFile.REF_invokeVirtual,
  1010                                             (MethodSymbol)bsm,
  1011                                             indyType,
  1012                                             staticArgs.toArray());
  1014             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1015             qualifier.sym = dynSym;
  1016             qualifier.type = indyType.getReturnType();
  1018             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
  1019             proxyCall.type = indyType.getReturnType();
  1020             return proxyCall;
  1021         } finally {
  1022             make.at(prevPos);
  1025     //where
  1026     private List<Type> bsmStaticArgToTypes(List<Object> args) {
  1027         ListBuffer<Type> argtypes = new ListBuffer<>();
  1028         for (Object arg : args) {
  1029             argtypes.append(bsmStaticArgToType(arg));
  1031         return argtypes.toList();
  1034     private Type bsmStaticArgToType(Object arg) {
  1035         Assert.checkNonNull(arg);
  1036         if (arg instanceof ClassSymbol) {
  1037             return syms.classType;
  1038         } else if (arg instanceof Integer) {
  1039             return syms.intType;
  1040         } else if (arg instanceof Long) {
  1041             return syms.longType;
  1042         } else if (arg instanceof Float) {
  1043             return syms.floatType;
  1044         } else if (arg instanceof Double) {
  1045             return syms.doubleType;
  1046         } else if (arg instanceof String) {
  1047             return syms.stringType;
  1048         } else if (arg instanceof Pool.MethodHandle) {
  1049             return syms.methodHandleType;
  1050         } else if (arg instanceof MethodType) {
  1051             return syms.methodTypeType;
  1052         } else {
  1053             Assert.error("bad static arg " + arg.getClass());
  1054             return null;
  1058     /**
  1059      * Get the opcode associated with this method reference
  1060      */
  1061     private int referenceKind(Symbol refSym) {
  1062         if (refSym.isConstructor()) {
  1063             return ClassFile.REF_newInvokeSpecial;
  1064         } else {
  1065             if (refSym.isStatic()) {
  1066                 return ClassFile.REF_invokeStatic;
  1067             } else if ((refSym.flags() & PRIVATE) != 0) {
  1068                 return ClassFile.REF_invokeSpecial;
  1069             } else if (refSym.enclClass().isInterface()) {
  1070                 return ClassFile.REF_invokeInterface;
  1071             } else {
  1072                 return ClassFile.REF_invokeVirtual;
  1077     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1078     /**
  1079      * This visitor collects information about translation of a lambda expression.
  1080      * More specifically, it keeps track of the enclosing contexts and captured locals
  1081      * accessed by the lambda being translated (as well as other useful info).
  1082      * It also translates away problems for LambdaToMethod.
  1083      */
  1084     class LambdaAnalyzerPreprocessor extends TreeTranslator {
  1086         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1087         private List<Frame> frameStack;
  1089         /**
  1090          * keep the count of lambda expression (used to generate unambiguous
  1091          * names)
  1092          */
  1093         private int lambdaCount = 0;
  1095         /**
  1096          * keep the count of lambda expression defined in given context (used to
  1097          * generate unambiguous names for serializable lambdas)
  1098          */
  1099         private class SyntheticMethodNameCounter {
  1100             private Map<String, Integer> map = new HashMap<>();
  1101             int getIndex(StringBuilder buf) {
  1102                 String temp = buf.toString();
  1103                 Integer count = map.get(temp);
  1104                 if (count == null) {
  1105                     count = 0;
  1107                 ++count;
  1108                 map.put(temp, count);
  1109                 return count;
  1112         private SyntheticMethodNameCounter syntheticMethodNameCounts =
  1113                 new SyntheticMethodNameCounter();
  1115         private Map<Symbol, JCClassDecl> localClassDefs;
  1117         /**
  1118          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1119          * a static var init context
  1120          */
  1121         private Map<ClassSymbol, Symbol> clinits =
  1122                 new HashMap<ClassSymbol, Symbol>();
  1124         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
  1125             frameStack = List.nil();
  1126             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1127             return translate(tree);
  1130         @Override
  1131         public void visitBlock(JCBlock tree) {
  1132             List<Frame> prevStack = frameStack;
  1133             try {
  1134                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1135                     frameStack = frameStack.prepend(new Frame(tree));
  1137                 super.visitBlock(tree);
  1139             finally {
  1140                 frameStack = prevStack;
  1144         @Override
  1145         public void visitClassDef(JCClassDecl tree) {
  1146             List<Frame> prevStack = frameStack;
  1147             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
  1148                     syntheticMethodNameCounts;
  1149             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1150             DiagnosticSource prevSource = log.currentSource();
  1151             try {
  1152                 log.useSource(tree.sym.sourcefile);
  1153                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
  1154                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1155                 if (tree.sym.owner.kind == MTH) {
  1156                     localClassDefs.put(tree.sym, tree);
  1158                 if (directlyEnclosingLambda() != null) {
  1159                     tree.sym.owner = owner();
  1160                     if (tree.sym.hasOuterInstance()) {
  1161                         //if a class is defined within a lambda, the lambda must capture
  1162                         //its enclosing instance (if any)
  1163                         TranslationContext<?> localContext = context();
  1164                         while (localContext != null) {
  1165                             if (localContext.tree.getTag() == LAMBDA) {
  1166                                 ((LambdaTranslationContext)localContext)
  1167                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1169                             localContext = localContext.prev;
  1173                 frameStack = frameStack.prepend(new Frame(tree));
  1174                 super.visitClassDef(tree);
  1176             finally {
  1177                 log.useSource(prevSource.getFile());
  1178                 frameStack = prevStack;
  1179                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
  1180                 clinits = prevClinits;
  1184         @Override
  1185         public void visitIdent(JCIdent tree) {
  1186             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1187                 if (tree.sym.kind == VAR &&
  1188                         tree.sym.owner.kind == MTH &&
  1189                         tree.type.constValue() == null) {
  1190                     TranslationContext<?> localContext = context();
  1191                     while (localContext != null) {
  1192                         if (localContext.tree.getTag() == LAMBDA) {
  1193                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1194                             if (block == null) break;
  1195                             ((LambdaTranslationContext)localContext)
  1196                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1198                         localContext = localContext.prev;
  1200                 } else if (tree.sym.owner.kind == TYP) {
  1201                     TranslationContext<?> localContext = context();
  1202                     while (localContext != null) {
  1203                         if (localContext.tree.hasTag(LAMBDA)) {
  1204                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1205                             if (block == null) break;
  1206                             switch (block.getTag()) {
  1207                                 case CLASSDEF:
  1208                                     JCClassDecl cdecl = (JCClassDecl)block;
  1209                                     ((LambdaTranslationContext)localContext)
  1210                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1211                                     break;
  1212                                 default:
  1213                                     Assert.error("bad block kind");
  1216                         localContext = localContext.prev;
  1220             super.visitIdent(tree);
  1223         @Override
  1224         public void visitLambda(JCLambda tree) {
  1225             analyzeLambda(tree, "lambda.stat");
  1228         private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) {
  1229             // Translation of the receiver expression must occur first
  1230             JCExpression rcvr = translate(methodReferenceReceiver);
  1231             LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1");
  1232             if (rcvr != null) {
  1233                 context.methodReferenceReceiver = rcvr;
  1237         private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) {
  1238             List<Frame> prevStack = frameStack;
  1239             try {
  1240                 LambdaTranslationContext context = new LambdaTranslationContext(tree);
  1241                 if (dumpLambdaToMethodStats) {
  1242                     log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym);
  1244                 frameStack = frameStack.prepend(new Frame(tree));
  1245                 for (JCVariableDecl param : tree.params) {
  1246                     context.addSymbol(param.sym, PARAM);
  1247                     frameStack.head.addLocal(param.sym);
  1249                 contextMap.put(tree, context);
  1250                 super.visitLambda(tree);
  1251                 context.complete();
  1252                 return context;
  1254             finally {
  1255                 frameStack = prevStack;
  1259         @Override
  1260         public void visitMethodDef(JCMethodDecl tree) {
  1261             List<Frame> prevStack = frameStack;
  1262             try {
  1263                 frameStack = frameStack.prepend(new Frame(tree));
  1264                 super.visitMethodDef(tree);
  1266             finally {
  1267                 frameStack = prevStack;
  1271         @Override
  1272         public void visitNewClass(JCNewClass tree) {
  1273             TypeSymbol def = tree.type.tsym;
  1274             boolean inReferencedClass = currentlyInClass(def);
  1275             boolean isLocal = def.isLocal();
  1276             if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
  1277                 TranslationContext<?> localContext = context();
  1278                 while (localContext != null) {
  1279                     if (localContext.tree.getTag() == LAMBDA) {
  1280                         ((LambdaTranslationContext)localContext)
  1281                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1283                     localContext = localContext.prev;
  1286             if (context() != null && !inReferencedClass && isLocal) {
  1287                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1288                 captureLocalClassDefs(def, lambdaContext);
  1290             super.visitNewClass(tree);
  1292         //where
  1293             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1294                 JCClassDecl localCDef = localClassDefs.get(csym);
  1295                 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
  1296                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1297                         @Override
  1298                         void addFreeVars(ClassSymbol c) {
  1299                             captureLocalClassDefs(c, lambdaContext);
  1301                         @Override
  1302                         void visitSymbol(Symbol sym) {
  1303                             if (sym.kind == VAR &&
  1304                                     sym.owner.kind == MTH &&
  1305                                     ((VarSymbol)sym).getConstValue() == null) {
  1306                                 TranslationContext<?> localContext = context();
  1307                                 while (localContext != null) {
  1308                                     if (localContext.tree.getTag() == LAMBDA) {
  1309                                         JCTree block = capturedDecl(localContext.depth, sym);
  1310                                         if (block == null) break;
  1311                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1313                                     localContext = localContext.prev;
  1317                     };
  1318                     fvc.scan(localCDef);
  1321         //where
  1322         boolean currentlyInClass(Symbol csym) {
  1323             for (Frame frame : frameStack) {
  1324                 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
  1325                     JCClassDecl cdef = (JCClassDecl) frame.tree;
  1326                     if (cdef.sym == csym) {
  1327                         return true;
  1331             return false;
  1334         /**
  1335          * Method references to local class constructors, may, if the local
  1336          * class references local variables, have implicit constructor
  1337          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1338          * information added in the LambdaToMethod pass will have the wrong
  1339          * signature. Hooks between Lower and LambdaToMethod have been added to
  1340          * handle normal "new" in this case. This visitor converts potentially
  1341          * affected method references into a lambda containing a normal
  1342          * expression.
  1344          * @param tree
  1345          */
  1346         @Override
  1347         public void visitReference(JCMemberReference tree) {
  1348             ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree);
  1349             contextMap.put(tree, rcontext);
  1350             if (rcontext.needsConversionToLambda()) {
  1351                  // Convert to a lambda, and process as such
  1352                 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner());
  1353                 analyzeLambda(conv.lambda(), conv.getReceiverExpression());
  1354             } else {
  1355                 super.visitReference(tree);
  1356                 if (dumpLambdaToMethodStats) {
  1357                     log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null);
  1362         @Override
  1363         public void visitSelect(JCFieldAccess tree) {
  1364             if (context() != null && tree.sym.kind == VAR &&
  1365                         (tree.sym.name == names._this ||
  1366                          tree.sym.name == names._super)) {
  1367                 // A select of this or super means, if we are in a lambda,
  1368                 // we much have an instance context
  1369                 TranslationContext<?> localContext = context();
  1370                 while (localContext != null) {
  1371                     if (localContext.tree.hasTag(LAMBDA)) {
  1372                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1373                         if (clazz == null) break;
  1374                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1376                     localContext = localContext.prev;
  1379             super.visitSelect(tree);
  1382         @Override
  1383         public void visitVarDef(JCVariableDecl tree) {
  1384             TranslationContext<?> context = context();
  1385             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1386                     (LambdaTranslationContext)context :
  1387                     null;
  1388             if (ltc != null) {
  1389                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1390                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1392                 // Check for type variables (including as type arguments).
  1393                 // If they occur within class nested in a lambda, mark for erasure
  1394                 Type type = tree.sym.asType();
  1395                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1396                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1400             List<Frame> prevStack = frameStack;
  1401             try {
  1402                 if (tree.sym.owner.kind == MTH) {
  1403                     frameStack.head.addLocal(tree.sym);
  1405                 frameStack = frameStack.prepend(new Frame(tree));
  1406                 super.visitVarDef(tree);
  1408             finally {
  1409                 frameStack = prevStack;
  1413         /**
  1414          * Return a valid owner given the current declaration stack
  1415          * (required to skip synthetic lambda symbols)
  1416          */
  1417         private Symbol owner() {
  1418             return owner(false);
  1421         @SuppressWarnings("fallthrough")
  1422         private Symbol owner(boolean skipLambda) {
  1423             List<Frame> frameStack2 = frameStack;
  1424             while (frameStack2.nonEmpty()) {
  1425                 switch (frameStack2.head.tree.getTag()) {
  1426                     case VARDEF:
  1427                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1428                             frameStack2 = frameStack2.tail;
  1429                             break;
  1431                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1432                         return initSym(cdecl.sym,
  1433                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1434                     case BLOCK:
  1435                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1436                         return initSym(cdecl2.sym,
  1437                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1438                     case CLASSDEF:
  1439                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1440                     case METHODDEF:
  1441                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1442                     case LAMBDA:
  1443                         if (!skipLambda)
  1444                             return ((LambdaTranslationContext)contextMap
  1445                                     .get(frameStack2.head.tree)).translatedSym;
  1446                     default:
  1447                         frameStack2 = frameStack2.tail;
  1450             Assert.error();
  1451             return null;
  1454         private Symbol initSym(ClassSymbol csym, long flags) {
  1455             boolean isStatic = (flags & STATIC) != 0;
  1456             if (isStatic) {
  1457                 /* static clinits are generated in Gen, so we need to use a fake
  1458                  * one. Attr creates a fake clinit method while attributing
  1459                  * lambda expressions used as initializers of static fields, so
  1460                  * let's use that one.
  1461                  */
  1462                 MethodSymbol clinit = attr.removeClinit(csym);
  1463                 if (clinit != null) {
  1464                     clinits.put(csym, clinit);
  1465                     return clinit;
  1468                 /* if no clinit is found at Attr, then let's try at clinits.
  1469                  */
  1470                 clinit = (MethodSymbol)clinits.get(csym);
  1471                 if (clinit == null) {
  1472                     /* no luck, let's create a new one
  1473                      */
  1474                     clinit = makePrivateSyntheticMethod(STATIC,
  1475                             names.clinit,
  1476                             new MethodType(List.<Type>nil(), syms.voidType,
  1477                                 List.<Type>nil(), syms.methodClass),
  1478                             csym);
  1479                     clinits.put(csym, clinit);
  1481                 return clinit;
  1482             } else {
  1483                 //get the first constructor and treat it as the instance init sym
  1484                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1485                     return s;
  1488             Assert.error("init not found");
  1489             return null;
  1492         private JCTree directlyEnclosingLambda() {
  1493             if (frameStack.isEmpty()) {
  1494                 return null;
  1496             List<Frame> frameStack2 = frameStack;
  1497             while (frameStack2.nonEmpty()) {
  1498                 switch (frameStack2.head.tree.getTag()) {
  1499                     case CLASSDEF:
  1500                     case METHODDEF:
  1501                         return null;
  1502                     case LAMBDA:
  1503                         return frameStack2.head.tree;
  1504                     default:
  1505                         frameStack2 = frameStack2.tail;
  1508             Assert.error();
  1509             return null;
  1512         private boolean inClassWithinLambda() {
  1513             if (frameStack.isEmpty()) {
  1514                 return false;
  1516             List<Frame> frameStack2 = frameStack;
  1517             boolean classFound = false;
  1518             while (frameStack2.nonEmpty()) {
  1519                 switch (frameStack2.head.tree.getTag()) {
  1520                     case LAMBDA:
  1521                         return classFound;
  1522                     case CLASSDEF:
  1523                         classFound = true;
  1524                         frameStack2 = frameStack2.tail;
  1525                         break;
  1526                     default:
  1527                         frameStack2 = frameStack2.tail;
  1530             // No lambda
  1531             return false;
  1534         /**
  1535          * Return the declaration corresponding to a symbol in the enclosing
  1536          * scope; the depth parameter is used to filter out symbols defined
  1537          * in nested scopes (which do not need to undergo capture).
  1538          */
  1539         private JCTree capturedDecl(int depth, Symbol sym) {
  1540             int currentDepth = frameStack.size() - 1;
  1541             for (Frame block : frameStack) {
  1542                 switch (block.tree.getTag()) {
  1543                     case CLASSDEF:
  1544                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1545                         if (sym.isMemberOf(clazz, types)) {
  1546                             return currentDepth > depth ? null : block.tree;
  1548                         break;
  1549                     case VARDEF:
  1550                         if (((JCVariableDecl)block.tree).sym == sym &&
  1551                                 sym.owner.kind == MTH) { //only locals are captured
  1552                             return currentDepth > depth ? null : block.tree;
  1554                         break;
  1555                     case BLOCK:
  1556                     case METHODDEF:
  1557                     case LAMBDA:
  1558                         if (block.locals != null && block.locals.contains(sym)) {
  1559                             return currentDepth > depth ? null : block.tree;
  1561                         break;
  1562                     default:
  1563                         Assert.error("bad decl kind " + block.tree.getTag());
  1565                 currentDepth--;
  1567             return null;
  1570         private TranslationContext<?> context() {
  1571             for (Frame frame : frameStack) {
  1572                 TranslationContext<?> context = contextMap.get(frame.tree);
  1573                 if (context != null) {
  1574                     return context;
  1577             return null;
  1580         /**
  1581          *  This is used to filter out those identifiers that needs to be adjusted
  1582          *  when translating away lambda expressions
  1583          */
  1584         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1585             return (sym.kind == VAR || sym.kind == MTH)
  1586                     && !sym.isStatic()
  1587                     && sym.name != names.init;
  1590         /**
  1591          * This is used to filter out those new class expressions that need to
  1592          * be qualified with an enclosing tree
  1593          */
  1594         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1595             if (context != null
  1596                     && tree.encl == null
  1597                     && tree.def == null
  1598                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1599                 Type encl = tree.type.getEnclosingType();
  1600                 Type current = context.owner.enclClass().type;
  1601                 while (!current.hasTag(NONE)) {
  1602                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1603                         return true;
  1605                     current = current.getEnclosingType();
  1607                 return false;
  1608             } else {
  1609                 return false;
  1613         private class Frame {
  1614             final JCTree tree;
  1615             List<Symbol> locals;
  1617             public Frame(JCTree tree) {
  1618                 this.tree = tree;
  1621             void addLocal(Symbol sym) {
  1622                 if (locals == null) {
  1623                     locals = List.nil();
  1625                 locals = locals.prepend(sym);
  1629         /**
  1630          * This class is used to store important information regarding translation of
  1631          * lambda expression/method references (see subclasses).
  1632          */
  1633         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1635             /** the underlying (untranslated) tree */
  1636             final T tree;
  1638             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1639             final Symbol owner;
  1641             /** the depth of this lambda expression in the frame stack */
  1642             final int depth;
  1644             /** the enclosing translation context (set for nested lambdas/mref) */
  1645             final TranslationContext<?> prev;
  1647             /** list of methods to be bridged by the meta-factory */
  1648             final List<Symbol> bridges;
  1650             TranslationContext(T tree) {
  1651                 this.tree = tree;
  1652                 this.owner = owner();
  1653                 this.depth = frameStack.size() - 1;
  1654                 this.prev = context();
  1655                 ClassSymbol csym =
  1656                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1657                 this.bridges = types.functionalInterfaceBridges(csym);
  1660             /** does this functional expression need to be created using alternate metafactory? */
  1661             boolean needsAltMetafactory() {
  1662                 return tree.targets.length() > 1 ||
  1663                         isSerializable() ||
  1664                         bridges.length() > 1;
  1667             /** does this functional expression require serialization support? */
  1668             boolean isSerializable() {
  1669                 if (forceSerializable) {
  1670                     return true;
  1672                 for (Type target : tree.targets) {
  1673                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1674                         return true;
  1677                 return false;
  1680             /**
  1681              * @return Name of the enclosing method to be folded into synthetic
  1682              * method name
  1683              */
  1684             String enclosingMethodName() {
  1685                 return syntheticMethodNameComponent(owner.name);
  1688             /**
  1689              * @return Method name in a form that can be folded into a
  1690              * component of a synthetic method name
  1691              */
  1692             String syntheticMethodNameComponent(Name name) {
  1693                 if (name == null) {
  1694                     return "null";
  1696                 String methodName = name.toString();
  1697                 if (methodName.equals("<clinit>")) {
  1698                     methodName = "static";
  1699                 } else if (methodName.equals("<init>")) {
  1700                     methodName = "new";
  1702                 return methodName;
  1706         /**
  1707          * This class retains all the useful information about a lambda expression;
  1708          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1709          * and the used by the main translation routines in order to adjust references
  1710          * to captured locals/members, etc.
  1711          */
  1712         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1714             /** variable in the enclosing context to which this lambda is assigned */
  1715             final Symbol self;
  1717             /** variable in the enclosing context to which this lambda is assigned */
  1718             final Symbol assignedTo;
  1720             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
  1722             /** the synthetic symbol for the method hoisting the translated lambda */
  1723             Symbol translatedSym;
  1725             List<JCVariableDecl> syntheticParams;
  1727             /**
  1728              * to prevent recursion, track local classes processed
  1729              */
  1730             final Set<Symbol> freeVarProcessedLocalClasses;
  1732             /**
  1733              * For method references converted to lambdas.  The method
  1734              * reference receiver expression. Must be treated like a captured
  1735              * variable.
  1736              */
  1737             JCExpression methodReferenceReceiver;
  1739             LambdaTranslationContext(JCLambda tree) {
  1740                 super(tree);
  1741                 Frame frame = frameStack.head;
  1742                 switch (frame.tree.getTag()) {
  1743                     case VARDEF:
  1744                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
  1745                         break;
  1746                     case ASSIGN:
  1747                         self = null;
  1748                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
  1749                         break;
  1750                     default:
  1751                         assignedTo = self = null;
  1752                         break;
  1755                 // This symbol will be filled-in in complete
  1756                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
  1758                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
  1760                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
  1761                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
  1762                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
  1763                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
  1764                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
  1766                 freeVarProcessedLocalClasses = new HashSet<>();
  1769              /**
  1770              * For a serializable lambda, generate a disambiguating string
  1771              * which maximizes stability across deserialization.
  1773              * @return String to differentiate synthetic lambda method names
  1774              */
  1775             private String serializedLambdaDisambiguation() {
  1776                 StringBuilder buf = new StringBuilder();
  1777                 // Append the enclosing method signature to differentiate
  1778                 // overloaded enclosing methods.  For lambdas enclosed in
  1779                 // lambdas, the generated lambda method will not have type yet,
  1780                 // but the enclosing method's name will have been generated
  1781                 // with this same method, so it will be unique and never be
  1782                 // overloaded.
  1783                 Assert.check(
  1784                         owner.type != null ||
  1785                         directlyEnclosingLambda() != null);
  1786                 if (owner.type != null) {
  1787                     buf.append(typeSig(owner.type));
  1788                     buf.append(":");
  1791                 // Add target type info
  1792                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
  1793                 buf.append(" ");
  1795                 // Add variable assigned to
  1796                 if (assignedTo != null) {
  1797                     buf.append(assignedTo.flatName());
  1798                     buf.append("=");
  1800                 //add captured locals info: type, name, order
  1801                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
  1802                     if (fv != self) {
  1803                         buf.append(typeSig(fv.type));
  1804                         buf.append(" ");
  1805                         buf.append(fv.flatName());
  1806                         buf.append(",");
  1810                 return buf.toString();
  1813             /**
  1814              * For a non-serializable lambda, generate a simple method.
  1816              * @return Name to use for the synthetic lambda method name
  1817              */
  1818             private Name lambdaName() {
  1819                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
  1822             /**
  1823              * For a serializable lambda, generate a method name which maximizes
  1824              * name stability across deserialization.
  1826              * @return Name to use for the synthetic lambda method name
  1827              */
  1828             private Name serializedLambdaName() {
  1829                 StringBuilder buf = new StringBuilder();
  1830                 buf.append(names.lambda);
  1831                 // Append the name of the method enclosing the lambda.
  1832                 buf.append(enclosingMethodName());
  1833                 buf.append('$');
  1834                 // Append a hash of the disambiguating string : enclosing method
  1835                 // signature, etc.
  1836                 String disam = serializedLambdaDisambiguation();
  1837                 buf.append(Integer.toHexString(disam.hashCode()));
  1838                 buf.append('$');
  1839                 // The above appended name components may not be unique, append
  1840                 // a count based on the above name components.
  1841                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  1842                 String result = buf.toString();
  1843                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
  1844                 return names.fromString(result);
  1847             /**
  1848              * Translate a symbol of a given kind into something suitable for the
  1849              * synthetic lambda body
  1850              */
  1851             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1852                 Symbol ret;
  1853                 switch (skind) {
  1854                     case CAPTURED_THIS:
  1855                         ret = sym;  // self represented
  1856                         break;
  1857                     case TYPE_VAR:
  1858                         // Just erase the type var
  1859                         ret = new VarSymbol(sym.flags(), name,
  1860                                 types.erasure(sym.type), sym.owner);
  1862                         /* this information should also be kept for LVT generation at Gen
  1863                          * a Symbol with pos < startPos won't be tracked.
  1864                          */
  1865                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
  1866                         break;
  1867                     case CAPTURED_VAR:
  1868                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
  1869                             @Override
  1870                             public Symbol baseSymbol() {
  1871                                 //keep mapping with original captured symbol
  1872                                 return sym;
  1874                         };
  1875                         break;
  1876                     case LOCAL_VAR:
  1877                         ret = new VarSymbol(sym.flags() & FINAL, name, sym.type, translatedSym);
  1878                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1879                         break;
  1880                     case PARAM:
  1881                         ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, name, types.erasure(sym.type), translatedSym);
  1882                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1883                         break;
  1884                     default:
  1885                         ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1886                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1888                 if (ret != sym) {
  1889                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1890                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1892                 return ret;
  1895             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1896                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
  1897                 Name preferredName;
  1898                 switch (skind) {
  1899                     case CAPTURED_THIS:
  1900                         preferredName = names.fromString("encl$" + transMap.size());
  1901                         break;
  1902                     case CAPTURED_VAR:
  1903                         preferredName = names.fromString("cap$" + transMap.size());
  1904                         break;
  1905                     case LOCAL_VAR:
  1906                         preferredName = sym.name;
  1907                         break;
  1908                     case PARAM:
  1909                         preferredName = sym.name;
  1910                         break;
  1911                     case TYPE_VAR:
  1912                         preferredName = sym.name;
  1913                         break;
  1914                     default: throw new AssertionError();
  1916                 if (!transMap.containsKey(sym)) {
  1917                     transMap.put(sym, translate(preferredName, sym, skind));
  1921             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
  1922                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
  1923                 Assert.checkNonNull(m);
  1924                 return m;
  1927             JCTree translate(JCIdent lambdaIdent) {
  1928                 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
  1929                     if (m.containsKey(lambdaIdent.sym)) {
  1930                         Symbol tSym = m.get(lambdaIdent.sym);
  1931                         JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
  1932                         tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
  1933                         return t;
  1936                 return null;
  1939             /**
  1940              * The translatedSym is not complete/accurate until the analysis is
  1941              * finished.  Once the analysis is finished, the translatedSym is
  1942              * "completed" -- updated with type information, access modifiers,
  1943              * and full parameter list.
  1944              */
  1945             void complete() {
  1946                 if (syntheticParams != null) {
  1947                     return;
  1949                 boolean inInterface = translatedSym.owner.isInterface();
  1950                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1952                 // If instance access isn't needed, make it static.
  1953                 // Interface instance methods must be default methods.
  1954                 // Lambda methods are private synthetic.
  1955                 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
  1956                 // from the class.
  1957                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
  1958                         owner.flags_field & STRICTFP |
  1959                         owner.owner.flags_field & STRICTFP |
  1960                         PRIVATE |
  1961                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  1963                 //compute synthetic params
  1964                 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
  1966                 // The signature of the method is augmented with the following
  1967                 // synthetic parameters:
  1968                 //
  1969                 // 1) reference to enclosing contexts captured by the lambda expression
  1970                 // 2) enclosing locals captured by the lambda expression
  1971                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
  1972                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1974                 if (methodReferenceReceiver != null) {
  1975                     params.append(make.VarDef(
  1976                             make.Modifiers(PARAMETER|FINAL),
  1977                             names.fromString("$rcvr$"),
  1978                             make.Type(methodReferenceReceiver.type),
  1979                             null));
  1981                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
  1982                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1984                 syntheticParams = params.toList();
  1986                 // Compute and set the lambda name
  1987                 translatedSym.name = isSerializable()
  1988                         ? serializedLambdaName()
  1989                         : lambdaName();
  1991                 //prepend synthetic args to translated lambda method signature
  1992                 translatedSym.type = types.createMethodTypeWithParameters(
  1993                         generatedLambdaSig(),
  1994                         TreeInfo.types(syntheticParams));
  1997             Type generatedLambdaSig() {
  1998                 return types.erasure(tree.getDescriptorType(types));
  2002         /**
  2003          * This class retains all the useful information about a method reference;
  2004          * the contents of this class are filled by the LambdaAnalyzer visitor,
  2005          * and the used by the main translation routines in order to adjust method
  2006          * references (i.e. in case a bridge is needed)
  2007          */
  2008         private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  2010             final boolean isSuper;
  2011             final Symbol sigPolySym;
  2013             ReferenceTranslationContext(JCMemberReference tree) {
  2014                 super(tree);
  2015                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2016                 this.sigPolySym = isSignaturePolymorphic()
  2017                         ? makePrivateSyntheticMethod(tree.sym.flags(),
  2018                                               tree.sym.name,
  2019                                               bridgedRefSig(),
  2020                                               tree.sym.enclClass())
  2021                         : null;
  2024             /**
  2025              * Get the opcode associated with this method reference
  2026              */
  2027             int referenceKind() {
  2028                 return LambdaToMethod.this.referenceKind(tree.sym);
  2031             boolean needsVarArgsConversion() {
  2032                 return tree.varargsElement != null;
  2035             /**
  2036              * @return Is this an array operation like clone()
  2037              */
  2038             boolean isArrayOp() {
  2039                 return tree.sym.owner == syms.arrayClass;
  2042             boolean receiverAccessible() {
  2043                 //hack needed to workaround 292 bug (7087658)
  2044                 //when 292 issue is fixed we should remove this and change the backend
  2045                 //code to always generate a method handle to an accessible method
  2046                 return tree.ownerAccessible;
  2049             /**
  2050              * The VM does not support access across nested classes (8010319).
  2051              * Were that ever to change, this should be removed.
  2052              */
  2053             boolean isPrivateInOtherClass() {
  2054                 return  (tree.sym.flags() & PRIVATE) != 0 &&
  2055                         !types.isSameType(
  2056                               types.erasure(tree.sym.enclClass().asType()),
  2057                               types.erasure(owner.enclClass().asType()));
  2060             /**
  2061              * Signature polymorphic methods need special handling.
  2062              * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
  2063              */
  2064             final boolean isSignaturePolymorphic() {
  2065                 return  tree.sym.kind == MTH &&
  2066                         types.isSignaturePolymorphic((MethodSymbol)tree.sym);
  2069             /**
  2070              * Does this reference need to be converted to a lambda
  2071              * (i.e. var args need to be expanded or "super" is used)
  2072              */
  2073             final boolean needsConversionToLambda() {
  2074                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  2075                         isPrivateInOtherClass() ||
  2076                         !receiverAccessible() ||
  2077                         (tree.getMode() == ReferenceMode.NEW &&
  2078                           tree.kind != ReferenceKind.ARRAY_CTOR &&
  2079                           (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
  2082             Type generatedRefSig() {
  2083                 return types.erasure(tree.sym.type);
  2086             Type bridgedRefSig() {
  2087                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  2091     // </editor-fold>
  2093     /*
  2094      * These keys provide mappings for various translated lambda symbols
  2095      * and the prevailing order must be maintained.
  2096      */
  2097     enum LambdaSymbolKind {
  2098         PARAM,          // original to translated lambda parameters
  2099         LOCAL_VAR,      // original to translated lambda locals
  2100         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
  2101         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
  2102         TYPE_VAR;       // original to translated lambda type variables
  2105     /**
  2106      * ****************************************************************
  2107      * Signature Generation
  2108      * ****************************************************************
  2109      */
  2111     private String typeSig(Type type) {
  2112         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2113         sg.assembleSig(type);
  2114         return sg.toString();
  2117     private String classSig(Type type) {
  2118         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2119         sg.assembleClassSig(type);
  2120         return sg.toString();
  2123     /**
  2124      * Signature Generation
  2125      */
  2126     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  2128         /**
  2129          * An output buffer for type signatures.
  2130          */
  2131         StringBuilder sb = new StringBuilder();
  2133         L2MSignatureGenerator() {
  2134             super(types);
  2137         @Override
  2138         protected void append(char ch) {
  2139             sb.append(ch);
  2142         @Override
  2143         protected void append(byte[] ba) {
  2144             sb.append(new String(ba));
  2147         @Override
  2148         protected void append(Name name) {
  2149             sb.append(name.toString());
  2152         @Override
  2153         public String toString() {
  2154             return sb.toString();

mercurial