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

Tue, 29 Mar 2016 10:48:49 +0000

author
dbuck
date
Tue, 29 Mar 2016 10:48:49 +0000
changeset 3102
e74dd6df4d4c
parent 3076
30f0dce3fbd3
child 3167
d5af468ae383
permissions
-rw-r--r--

8143647: Javac compiles method reference that allows results in an IllegalAccessError
Summary: Lambda implementation method synthesized by javac should not mention inaccessible types.
Reviewed-by: mcimadamore

     1 /*
     2  * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 package com.sun.tools.javac.comp;
    27 import com.sun.tools.javac.tree.*;
    28 import com.sun.tools.javac.tree.JCTree.*;
    29 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
    30 import com.sun.tools.javac.tree.TreeMaker;
    31 import com.sun.tools.javac.tree.TreeTranslator;
    32 import com.sun.tools.javac.code.Attribute;
    33 import com.sun.tools.javac.code.Kinds;
    34 import com.sun.tools.javac.code.Scope;
    35 import com.sun.tools.javac.code.Symbol;
    36 import com.sun.tools.javac.code.Symbol.ClassSymbol;
    37 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
    38 import com.sun.tools.javac.code.Symbol.MethodSymbol;
    39 import com.sun.tools.javac.code.Symbol.TypeSymbol;
    40 import com.sun.tools.javac.code.Symbol.VarSymbol;
    41 import com.sun.tools.javac.code.Symtab;
    42 import com.sun.tools.javac.code.Type;
    43 import com.sun.tools.javac.code.Type.MethodType;
    44 import com.sun.tools.javac.code.Type.TypeVar;
    45 import com.sun.tools.javac.code.Types;
    46 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
    47 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
    48 import com.sun.tools.javac.jvm.*;
    49 import com.sun.tools.javac.util.*;
    50 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    51 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
    53 import java.util.EnumMap;
    54 import java.util.HashMap;
    55 import java.util.HashSet;
    56 import java.util.LinkedHashMap;
    57 import java.util.Map;
    58 import java.util.Set;
    60 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
    61 import static com.sun.tools.javac.code.Flags.*;
    62 import static com.sun.tools.javac.code.Kinds.*;
    63 import static com.sun.tools.javac.code.TypeTag.*;
    64 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    65 import javax.lang.model.type.TypeKind;
    67 /**
    68  * This pass desugars lambda expressions into static methods
    69  *
    70  *  <p><b>This is NOT part of any supported API.
    71  *  If you write code that depends on this, you do so at your own risk.
    72  *  This code and its internal interfaces are subject to change or
    73  *  deletion without notice.</b>
    74  */
    75 public class LambdaToMethod extends TreeTranslator {
    77     private Attr attr;
    78     private JCDiagnostic.Factory diags;
    79     private Log log;
    80     private Lower lower;
    81     private Names names;
    82     private Symtab syms;
    83     private Resolve rs;
    84     private TreeMaker make;
    85     private Types types;
    86     private TransTypes transTypes;
    87     private Env<AttrContext> attrEnv;
    89     /** the analyzer scanner */
    90     private LambdaAnalyzerPreprocessor analyzer;
    92     /** map from lambda trees to translation contexts */
    93     private Map<JCTree, TranslationContext<?>> contextMap;
    95     /** current translation context (visitor argument) */
    96     private TranslationContext<?> context;
    98     /** info about the current class being processed */
    99     private KlassInfo kInfo;
   101     /** dump statistics about lambda code generation */
   102     private boolean dumpLambdaToMethodStats;
   104     /** force serializable representation, for stress testing **/
   105     private final boolean forceSerializable;
   107     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
   108     public static final int FLAG_SERIALIZABLE = 1 << 0;
   110     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
   111     public static final int FLAG_MARKERS = 1 << 1;
   113     /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
   114     public static final int FLAG_BRIDGES = 1 << 2;
   116     // <editor-fold defaultstate="collapsed" desc="Instantiating">
   117     protected static final Context.Key<LambdaToMethod> unlambdaKey =
   118             new Context.Key<LambdaToMethod>();
   120     public static LambdaToMethod instance(Context context) {
   121         LambdaToMethod instance = context.get(unlambdaKey);
   122         if (instance == null) {
   123             instance = new LambdaToMethod(context);
   124         }
   125         return instance;
   126     }
   127     private LambdaToMethod(Context context) {
   128         context.put(unlambdaKey, this);
   129         diags = JCDiagnostic.Factory.instance(context);
   130         log = Log.instance(context);
   131         lower = Lower.instance(context);
   132         names = Names.instance(context);
   133         syms = Symtab.instance(context);
   134         rs = Resolve.instance(context);
   135         make = TreeMaker.instance(context);
   136         types = Types.instance(context);
   137         transTypes = TransTypes.instance(context);
   138         analyzer = new LambdaAnalyzerPreprocessor();
   139         Options options = Options.instance(context);
   140         dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats");
   141         attr = Attr.instance(context);
   142         forceSerializable = options.isSet("forceSerializable");
   143     }
   144     // </editor-fold>
   146     private class KlassInfo {
   148         /**
   149          * list of methods to append
   150          */
   151         private ListBuffer<JCTree> appendedMethodList;
   153         /**
   154          * list of deserialization cases
   155          */
   156         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   158        /**
   159          * deserialize method symbol
   160          */
   161         private final MethodSymbol deserMethodSym;
   163         /**
   164          * deserialize method parameter symbol
   165          */
   166         private final VarSymbol deserParamSym;
   168         private final JCClassDecl clazz;
   170         private KlassInfo(JCClassDecl clazz) {
   171             this.clazz = clazz;
   172             appendedMethodList = new ListBuffer<>();
   173             deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
   174             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
   175                     List.<Type>nil(), syms.methodClass);
   176             deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
   177             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
   178                     syms.serializedLambdaType, deserMethodSym);
   179         }
   181         private void addMethod(JCTree decl) {
   182             appendedMethodList = appendedMethodList.prepend(decl);
   183         }
   184     }
   186     // <editor-fold defaultstate="collapsed" desc="translate methods">
   187     @Override
   188     public <T extends JCTree> T translate(T tree) {
   189         TranslationContext<?> newContext = contextMap.get(tree);
   190         return translate(tree, newContext != null ? newContext : context);
   191     }
   193     <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
   194         TranslationContext<?> prevContext = context;
   195         try {
   196             context = newContext;
   197             return super.translate(tree);
   198         }
   199         finally {
   200             context = prevContext;
   201         }
   202     }
   204     <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
   205         ListBuffer<T> buf = new ListBuffer<>();
   206         for (T tree : trees) {
   207             buf.append(translate(tree, newContext));
   208         }
   209         return buf.toList();
   210     }
   212     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
   213         this.make = make;
   214         this.attrEnv = env;
   215         this.context = null;
   216         this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
   217         return translate(cdef);
   218     }
   219     // </editor-fold>
   221     // <editor-fold defaultstate="collapsed" desc="visitor methods">
   222     /**
   223      * Visit a class.
   224      * Maintain the translatedMethodList across nested classes.
   225      * Append the translatedMethodList to the class after it is translated.
   226      * @param tree
   227      */
   228     @Override
   229     public void visitClassDef(JCClassDecl tree) {
   230         if (tree.sym.owner.kind == PCK) {
   231             //analyze class
   232             tree = analyzer.analyzeAndPreprocessClass(tree);
   233         }
   234         KlassInfo prevKlassInfo = kInfo;
   235         try {
   236             kInfo = new KlassInfo(tree);
   237             super.visitClassDef(tree);
   238             if (!kInfo.deserializeCases.isEmpty()) {
   239                 int prevPos = make.pos;
   240                 try {
   241                     make.at(tree);
   242                     kInfo.addMethod(makeDeserializeMethod(tree.sym));
   243                 } finally {
   244                     make.at(prevPos);
   245                 }
   246             }
   247             //add all translated instance methods here
   248             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
   249             tree.defs = tree.defs.appendList(newMethods);
   250             for (JCTree lambda : newMethods) {
   251                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
   252             }
   253             result = tree;
   254         } finally {
   255             kInfo = prevKlassInfo;
   256         }
   257     }
   259     /**
   260      * Translate a lambda into a method to be inserted into the class.
   261      * Then replace the lambda site with an invokedynamic call of to lambda
   262      * meta-factory, which will use the lambda method.
   263      * @param tree
   264      */
   265     @Override
   266     public void visitLambda(JCLambda tree) {
   267         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
   268         MethodSymbol sym = localContext.translatedSym;
   269         MethodType lambdaType = (MethodType) sym.type;
   271         {
   272             Symbol owner = localContext.owner;
   273             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   274             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   276             for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
   277                 if (tc.position.onLambda == tree) {
   278                     lambdaTypeAnnos.append(tc);
   279                 } else {
   280                     ownerTypeAnnos.append(tc);
   281                 }
   282             }
   283             if (lambdaTypeAnnos.nonEmpty()) {
   284                 owner.setTypeAttributes(ownerTypeAnnos.toList());
   285                 sym.setTypeAttributes(lambdaTypeAnnos.toList());
   286             }
   287         }
   289         //create the method declaration hoisting the lambda body
   290         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
   291                 sym.name,
   292                 make.QualIdent(lambdaType.getReturnType().tsym),
   293                 List.<JCTypeParameter>nil(),
   294                 localContext.syntheticParams,
   295                 lambdaType.getThrownTypes() == null ?
   296                     List.<JCExpression>nil() :
   297                     make.Types(lambdaType.getThrownTypes()),
   298                 null,
   299                 null);
   300         lambdaDecl.sym = sym;
   301         lambdaDecl.type = lambdaType;
   303         //translate lambda body
   304         //As the lambda body is translated, all references to lambda locals,
   305         //captured variables, enclosing members are adjusted accordingly
   306         //to refer to the static method parameters (rather than i.e. acessing to
   307         //captured members directly).
   308         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
   310         //Add the method to the list of methods to be added to this class.
   311         kInfo.addMethod(lambdaDecl);
   313         //now that we have generated a method for the lambda expression,
   314         //we can translate the lambda into a method reference pointing to the newly
   315         //created method.
   316         //
   317         //Note that we need to adjust the method handle so that it will match the
   318         //signature of the SAM descriptor - this means that the method reference
   319         //should be added the following synthetic arguments:
   320         //
   321         // * the "this" argument if it is an instance method
   322         // * enclosing locals captured by the lambda expression
   324         ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
   326         if (localContext.methodReferenceReceiver != null) {
   327             syntheticInits.append(localContext.methodReferenceReceiver);
   328         } else if (!sym.isStatic()) {
   329             syntheticInits.append(makeThis(
   330                     sym.owner.enclClass().asType(),
   331                     localContext.owner.enclClass()));
   332         }
   334         //add captured locals
   335         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
   336             if (fv != localContext.self) {
   337                 JCTree captured_local = make.Ident(fv).setType(fv.type);
   338                 syntheticInits.append((JCExpression) captured_local);
   339             }
   340         }
   342         //then, determine the arguments to the indy call
   343         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   345         //build a sam instance using an indy call to the meta-factory
   346         int refKind = referenceKind(sym);
   348         //convert to an invokedynamic call
   349         result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
   350     }
   352     private JCIdent makeThis(Type type, Symbol owner) {
   353         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
   354                 names._this,
   355                 type,
   356                 owner);
   357         return make.Ident(_this);
   358     }
   360     /**
   361      * Translate a method reference into an invokedynamic call to the
   362      * meta-factory.
   363      * @param tree
   364      */
   365     @Override
   366     public void visitReference(JCMemberReference tree) {
   367         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   369         //first determine the method symbol to be used to generate the sam instance
   370         //this is either the method reference symbol, or the bridged reference symbol
   371         Symbol refSym = localContext.isSignaturePolymorphic()
   372                 ? localContext.sigPolySym
   373                 : tree.sym;
   375         //the qualifying expression is treated as a special captured arg
   376         JCExpression init;
   377         switch(tree.kind) {
   379             case IMPLICIT_INNER:    /** Inner :: new */
   380             case SUPER:             /** super :: instMethod */
   381                 init = makeThis(
   382                     localContext.owner.enclClass().asType(),
   383                     localContext.owner.enclClass());
   384                 break;
   386             case BOUND:             /** Expr :: instMethod */
   387                 init = tree.getQualifierExpression();
   388                 init = attr.makeNullCheck(init);
   389                 break;
   391             case UNBOUND:           /** Type :: instMethod */
   392             case STATIC:            /** Type :: staticMethod */
   393             case TOPLEVEL:          /** Top level :: new */
   394             case ARRAY_CTOR:        /** ArrayType :: new */
   395                 init = null;
   396                 break;
   398             default:
   399                 throw new InternalError("Should not have an invalid kind");
   400         }
   402         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
   405         //build a sam instance using an indy call to the meta-factory
   406         result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
   407     }
   409     /**
   410      * Translate identifiers within a lambda to the mapped identifier
   411      * @param tree
   412      */
   413     @Override
   414     public void visitIdent(JCIdent tree) {
   415         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
   416             super.visitIdent(tree);
   417         } else {
   418             int prevPos = make.pos;
   419             try {
   420                 make.at(tree);
   422                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
   423                 JCTree ltree = lambdaContext.translate(tree);
   424                 if (ltree != null) {
   425                     result = ltree;
   426                 } else {
   427                     //access to untranslated symbols (i.e. compile-time constants,
   428                     //members defined inside the lambda body, etc.) )
   429                     super.visitIdent(tree);
   430                 }
   431             } finally {
   432                 make.at(prevPos);
   433             }
   434         }
   435     }
   437     @Override
   438     public void visitVarDef(JCVariableDecl tree) {
   439         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
   440         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   441             tree.init = translate(tree.init);
   442             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
   443             result = tree;
   444         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   445             JCExpression init = translate(tree.init);
   446             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   447             int prevPos = make.pos;
   448             try {
   449                 result = make.at(tree).VarDef(xsym, init);
   450             } finally {
   451                 make.at(prevPos);
   452             }
   453             // Replace the entered symbol for this variable
   454             Scope sc = tree.sym.owner.members();
   455             if (sc != null) {
   456                 sc.remove(tree.sym);
   457                 sc.enter(xsym);
   458             }
   459         } else {
   460             super.visitVarDef(tree);
   461         }
   462     }
   464     // </editor-fold>
   466     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   468     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   469         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   470                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   471                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   472     }
   474     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   475         Type restype = lambdaMethodDecl.type.getReturnType();
   476         boolean isLambda_void = expr.type.hasTag(VOID);
   477         boolean isTarget_void = restype.hasTag(VOID);
   478         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   479         int prevPos = make.pos;
   480         try {
   481             if (isTarget_void) {
   482                 //target is void:
   483                 // BODY;
   484                 JCStatement stat = make.at(expr).Exec(expr);
   485                 return make.Block(0, List.<JCStatement>of(stat));
   486             } else if (isLambda_void && isTarget_Void) {
   487                 //void to Void conversion:
   488                 // BODY; return null;
   489                 ListBuffer<JCStatement> stats = new ListBuffer<>();
   490                 stats.append(make.at(expr).Exec(expr));
   491                 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   492                 return make.Block(0, stats.toList());
   493             } else {
   494                 //non-void to non-void conversion:
   495                 // return (TYPE)BODY;
   496                 JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   497                 return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
   498             }
   499         } finally {
   500             make.at(prevPos);
   501         }
   502     }
   504     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   505         final Type restype = lambdaMethodDecl.type.getReturnType();
   506         final boolean isTarget_void = restype.hasTag(VOID);
   507         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   509         class LambdaBodyTranslator extends TreeTranslator {
   511             @Override
   512             public void visitClassDef(JCClassDecl tree) {
   513                 //do NOT recurse on any inner classes
   514                 result = tree;
   515             }
   517             @Override
   518             public void visitLambda(JCLambda tree) {
   519                 //do NOT recurse on any nested lambdas
   520                 result = tree;
   521             }
   523             @Override
   524             public void visitReturn(JCReturn tree) {
   525                 boolean isLambda_void = tree.expr == null;
   526                 if (isTarget_void && !isLambda_void) {
   527                     //Void to void conversion:
   528                     // { TYPE $loc = RET-EXPR; return; }
   529                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   530                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   531                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   532                 } else if (!isTarget_void || !isLambda_void) {
   533                     //non-void to non-void conversion:
   534                     // return (TYPE)RET-EXPR;
   535                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   536                     result = tree;
   537                 } else {
   538                     result = tree;
   539                 }
   541             }
   542         }
   544         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   545         if (completeNormally && isTarget_Void) {
   546             //there's no return statement and the lambda (possibly inferred)
   547             //return type is java.lang.Void; emit a synthetic return statement
   548             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   549         }
   550         return trans_block;
   551     }
   553     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   554         ListBuffer<JCCase> cases = new ListBuffer<>();
   555         ListBuffer<JCBreak> breaks = new ListBuffer<>();
   556         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   557             JCBreak br = make.Break(null);
   558             breaks.add(br);
   559             List<JCStatement> stmts = entry.getValue().append(br).toList();
   560             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   561         }
   562         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   563         for (JCBreak br : breaks) {
   564             br.target = sw;
   565         }
   566         JCBlock body = make.Block(0L, List.<JCStatement>of(
   567                 sw,
   568                 make.Throw(makeNewClass(
   569                     syms.illegalArgumentExceptionType,
   570                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   571         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   572                         names.deserializeLambda,
   573                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   574                         List.<JCTypeParameter>nil(),
   575                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   576                         List.<JCExpression>nil(),
   577                         body,
   578                         null);
   579         deser.sym = kInfo.deserMethodSym;
   580         deser.type = kInfo.deserMethodSym.type;
   581         //System.err.printf("DESER: '%s'\n", deser);
   582         return deser;
   583     }
   585     /** Make an attributed class instance creation expression.
   586      *  @param ctype    The class type.
   587      *  @param args     The constructor arguments.
   588      *  @param cons     The constructor symbol
   589      */
   590     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
   591         JCNewClass tree = make.NewClass(null,
   592             null, make.QualIdent(ctype.tsym), args, null);
   593         tree.constructor = cons;
   594         tree.type = ctype;
   595         return tree;
   596     }
   598     /** Make an attributed class instance creation expression.
   599      *  @param ctype    The class type.
   600      *  @param args     The constructor arguments.
   601      */
   602     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   603         return makeNewClass(ctype, args,
   604                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
   605      }
   607     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   608             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   609         String functionalInterfaceClass = classSig(targetType);
   610         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   611         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
   612         String implClass = classSig(types.erasure(refSym.owner.type));
   613         String implMethodName = refSym.getQualifiedName().toString();
   614         String implMethodSignature = typeSig(types.erasure(refSym.type));
   616         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   617         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
   618         int i = 0;
   619         for (Type t : indyType.getParameterTypes()) {
   620             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
   621             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
   622             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   623             ++i;
   624         }
   625         JCStatement stmt = make.If(
   626                 deserTest(deserTest(deserTest(deserTest(deserTest(
   627                     kindTest,
   628                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   629                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   630                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   631                     "getImplClass", implClass),
   632                     "getImplMethodSignature", implMethodSignature),
   633                 make.Return(makeIndyCall(
   634                     pos,
   635                     syms.lambdaMetafactory,
   636                     names.altMetafactory,
   637                     staticArgs, indyType, serArgs.toList(), samSym.name)),
   638                 null);
   639         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   640         if (stmts == null) {
   641             stmts = new ListBuffer<>();
   642             kInfo.deserializeCases.put(implMethodName, stmts);
   643         }
   644         /****
   645         System.err.printf("+++++++++++++++++\n");
   646         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   647         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   648         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   649         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   650         System.err.printf("*implClass: '%s'\n", implClass);
   651         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   652         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   653         ****/
   654         stmts.append(stmt);
   655     }
   657     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   658         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   659         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   660         testExpr.setType(syms.booleanType);
   661         return testExpr;
   662     }
   664     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   665         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   666         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   667         JCMethodInvocation eqtest = make.Apply(
   668                 List.<JCExpression>nil(),
   669                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   670                 List.<JCExpression>of(make.Literal(lit)));
   671         eqtest.setType(syms.booleanType);
   672         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   673         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   674         compound.setType(syms.booleanType);
   675         return compound;
   676     }
   678     private JCExpression deserGetter(String func, Type type) {
   679         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   680     }
   682     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   683         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   684         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   685         return make.Apply(
   686                     List.<JCExpression>nil(),
   687                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   688                     args).setType(type);
   689     }
   691     /**
   692      * Create new synthetic method with given flags, name, type, owner
   693      */
   694     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   695         return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
   696     }
   698     /**
   699      * Create new synthetic variable with given flags, name, type, owner
   700      */
   701     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   702         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   703     }
   705     /**
   706      * Create new synthetic variable with given flags, name, type, owner
   707      */
   708     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   709         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   710     }
   712     /**
   713      * Set varargsElement field on a given tree (must be either a new class tree
   714      * or a method call tree)
   715      */
   716     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   717         if (varargsElement != null) {
   718             switch (tree.getTag()) {
   719                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   720                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   721                 default: throw new AssertionError();
   722             }
   723         }
   724     }
   726     /**
   727      * Convert method/constructor arguments by inserting appropriate cast
   728      * as required by type-erasure - this is needed when bridging a lambda/method
   729      * reference, as the bridged signature might require downcast to be compatible
   730      * with the generated signature.
   731      */
   732     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   733        Assert.check(meth.kind == Kinds.MTH);
   734        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   735        if (varargsElement != null) {
   736            Assert.check((meth.flags() & VARARGS) != 0);
   737        }
   738        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   739     }
   741     // </editor-fold>
   743     /**
   744      * Converts a method reference which cannot be used directly into a lambda
   745      */
   746     private class MemberReferenceToLambda {
   748         private final JCMemberReference tree;
   749         private final ReferenceTranslationContext localContext;
   750         private final Symbol owner;
   751         private final ListBuffer<JCExpression> args = new ListBuffer<>();
   752         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
   754         private JCExpression receiverExpression = null;
   756         MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) {
   757             this.tree = tree;
   758             this.localContext = localContext;
   759             this.owner = owner;
   760         }
   762         JCLambda lambda() {
   763             int prevPos = make.pos;
   764             try {
   765                 make.at(tree);
   767                 //body generation - this can be either a method call or a
   768                 //new instance creation expression, depending on the member reference kind
   769                 VarSymbol rcvr = addParametersReturnReceiver();
   770                 JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
   771                         ? expressionInvoke(rcvr)
   772                         : expressionNew();
   774                 JCLambda slam = make.Lambda(params.toList(), expr);
   775                 slam.targets = tree.targets;
   776                 slam.type = tree.type;
   777                 slam.pos = tree.pos;
   778                 return slam;
   779             } finally {
   780                 make.at(prevPos);
   781             }
   782         }
   784         /**
   785          * Generate the parameter list for the converted member reference.
   786          *
   787          * @return The receiver variable symbol, if any
   788          */
   789         VarSymbol addParametersReturnReceiver() {
   790             Type samDesc = localContext.bridgedRefSig();
   791             List<Type> samPTypes = samDesc.getParameterTypes();
   792             List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes();
   794             // Determine the receiver, if any
   795             VarSymbol rcvr;
   796             switch (tree.kind) {
   797                 case BOUND:
   798                     // The receiver is explicit in the method reference
   799                     rcvr = addParameter("rec$", tree.getQualifierExpression().type, false);
   800                     receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
   801                     break;
   802                 case UNBOUND:
   803                     // The receiver is the first parameter, extract it and
   804                     // adjust the SAM and unerased type lists accordingly
   805                     rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false);
   806                     samPTypes = samPTypes.tail;
   807                     descPTypes = descPTypes.tail;
   808                     break;
   809                 default:
   810                     rcvr = null;
   811                     break;
   812             }
   813             List<Type> implPTypes = tree.sym.type.getParameterTypes();
   814             int implSize = implPTypes.size();
   815             int samSize = samPTypes.size();
   816             // Last parameter to copy from referenced method, exclude final var args
   817             int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize;
   819             // Failsafe -- assure match-up
   820             boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size();
   822             // Use parameter types of the implementation method unless the unerased
   823             // SAM parameter type is an intersection type, in that case use the
   824             // erased SAM parameter type so that the supertype relationship
   825             // the implementation method parameters is not obscured.
   826             // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes
   827             // are used as pointers to the current parameter type information
   828             // and are thus not usable afterwards.
   829             for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) {
   830                 // By default use the implementation method parmeter type
   831                 Type parmType = implPTypes.head;
   832                 // If the unerased parameter type is a type variable whose
   833                 // bound is an intersection (eg. <T extends A & B>) then
   834                 // use the SAM parameter type
   835                 if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) {
   836                     TypeVar tv = (TypeVar) descPTypes.head;
   837                     if (tv.bound.getKind() == TypeKind.INTERSECTION) {
   838                         parmType = samPTypes.head;
   839                     }
   840                 }
   841                 addParameter("x$" + i, parmType, true);
   843                 // Advance to the next parameter
   844                 implPTypes = implPTypes.tail;
   845                 samPTypes = samPTypes.tail;
   846                 descPTypes = descPTypes.tail;
   847             }
   848             // Flatten out the var args
   849             for (int i = last; i < samSize; ++i) {
   850                 addParameter("xva$" + i, tree.varargsElement, true);
   851             }
   853             return rcvr;
   854         }
   856         JCExpression getReceiverExpression() {
   857             return receiverExpression;
   858         }
   860         private JCExpression makeReceiver(VarSymbol rcvr) {
   861             if (rcvr == null) return null;
   862             JCExpression rcvrExpr = make.Ident(rcvr);
   863             Type rcvrType = tree.ownerAccessible ? tree.sym.enclClass().type : tree.expr.type;
   864             if (rcvrType == syms.arrayClass.type) {
   865                 // Map the receiver type to the actually type, not just "array"
   866                 rcvrType = tree.getQualifierExpression().type;
   867             }
   868             if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   869                 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   870             }
   871             return rcvrExpr;
   872         }
   874         /**
   875          * determine the receiver of the method call - the receiver can
   876          * be a type qualifier, the synthetic receiver parameter or 'super'.
   877          */
   878         private JCExpression expressionInvoke(VarSymbol rcvr) {
   879             JCExpression qualifier =
   880                     (rcvr != null) ?
   881                         makeReceiver(rcvr) :
   882                         tree.getQualifierExpression();
   884             //create the qualifier expression
   885             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   886             select.sym = tree.sym;
   887             select.type = tree.sym.erasure(types);
   889             //create the method call expression
   890             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   891                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   892                     setType(tree.sym.erasure(types).getReturnType());
   894             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   895             setVarargsIfNeeded(apply, tree.varargsElement);
   896             return apply;
   897         }
   899         /**
   900          * Lambda body to use for a 'new'.
   901          */
   902         private JCExpression expressionNew() {
   903             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   904                 //create the array creation expression
   905                 JCNewArray newArr = make.NewArray(
   906                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   907                         List.of(make.Ident(params.first())),
   908                         null);
   909                 newArr.type = tree.getQualifierExpression().type;
   910                 return newArr;
   911             } else {
   912                 //create the instance creation expression
   913                 //note that method reference syntax does not allow an explicit
   914                 //enclosing class (so the enclosing class is null)
   915                 JCNewClass newClass = make.NewClass(null,
   916                         List.<JCExpression>nil(),
   917                         make.Type(tree.getQualifierExpression().type),
   918                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   919                         null);
   920                 newClass.constructor = tree.sym;
   921                 newClass.constructorType = tree.sym.erasure(types);
   922                 newClass.type = tree.getQualifierExpression().type;
   923                 setVarargsIfNeeded(newClass, tree.varargsElement);
   924                 return newClass;
   925             }
   926         }
   928         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   929             VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
   930             vsym.pos = tree.pos;
   931             params.append(make.VarDef(vsym, null));
   932             if (genArg) {
   933                 args.append(make.Ident(vsym));
   934             }
   935             return vsym;
   936         }
   937     }
   939     private MethodType typeToMethodType(Type mt) {
   940         Type type = types.erasure(mt);
   941         return new MethodType(type.getParameterTypes(),
   942                         type.getReturnType(),
   943                         type.getThrownTypes(),
   944                         syms.methodClass);
   945     }
   947     /**
   948      * Generate an indy method call to the meta factory
   949      */
   950     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
   951             int refKind, Symbol refSym, List<JCExpression> indy_args) {
   952         JCFunctionalExpression tree = context.tree;
   953         //determine the static bsm args
   954         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   955         List<Object> staticArgs = List.<Object>of(
   956                 typeToMethodType(samSym.type),
   957                 new Pool.MethodHandle(refKind, refSym, types),
   958                 typeToMethodType(tree.getDescriptorType(types)));
   960         //computed indy arg types
   961         ListBuffer<Type> indy_args_types = new ListBuffer<>();
   962         for (JCExpression arg : indy_args) {
   963             indy_args_types.append(arg.type);
   964         }
   966         //finally, compute the type of the indy call
   967         MethodType indyType = new MethodType(indy_args_types.toList(),
   968                 tree.type,
   969                 List.<Type>nil(),
   970                 syms.methodClass);
   972         Name metafactoryName = context.needsAltMetafactory() ?
   973                 names.altMetafactory : names.metafactory;
   975         if (context.needsAltMetafactory()) {
   976             ListBuffer<Object> markers = new ListBuffer<>();
   977             for (Type t : tree.targets.tail) {
   978                 if (t.tsym != syms.serializableType.tsym) {
   979                     markers.append(t.tsym);
   980                 }
   981             }
   982             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
   983             boolean hasMarkers = markers.nonEmpty();
   984             boolean hasBridges = context.bridges.nonEmpty();
   985             if (hasMarkers) {
   986                 flags |= FLAG_MARKERS;
   987             }
   988             if (hasBridges) {
   989                 flags |= FLAG_BRIDGES;
   990             }
   991             staticArgs = staticArgs.append(flags);
   992             if (hasMarkers) {
   993                 staticArgs = staticArgs.append(markers.length());
   994                 staticArgs = staticArgs.appendList(markers.toList());
   995             }
   996             if (hasBridges) {
   997                 staticArgs = staticArgs.append(context.bridges.length() - 1);
   998                 for (Symbol s : context.bridges) {
   999                     Type s_erasure = s.erasure(types);
  1000                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
  1001                         staticArgs = staticArgs.append(s.erasure(types));
  1005             if (context.isSerializable()) {
  1006                 int prevPos = make.pos;
  1007                 try {
  1008                     make.at(kInfo.clazz);
  1009                     addDeserializationCase(refKind, refSym, tree.type, samSym,
  1010                             tree, staticArgs, indyType);
  1011                 } finally {
  1012                     make.at(prevPos);
  1017         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
  1020     /**
  1021      * Generate an indy method call with given name, type and static bootstrap
  1022      * arguments types
  1023      */
  1024     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
  1025             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
  1026             Name methName) {
  1027         int prevPos = make.pos;
  1028         try {
  1029             make.at(pos);
  1030             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
  1031                     syms.stringType,
  1032                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
  1034             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
  1035                     bsmName, bsm_staticArgs, List.<Type>nil());
  1037             DynamicMethodSymbol dynSym =
  1038                     new DynamicMethodSymbol(methName,
  1039                                             syms.noSymbol,
  1040                                             bsm.isStatic() ?
  1041                                                 ClassFile.REF_invokeStatic :
  1042                                                 ClassFile.REF_invokeVirtual,
  1043                                             (MethodSymbol)bsm,
  1044                                             indyType,
  1045                                             staticArgs.toArray());
  1047             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1048             qualifier.sym = dynSym;
  1049             qualifier.type = indyType.getReturnType();
  1051             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
  1052             proxyCall.type = indyType.getReturnType();
  1053             return proxyCall;
  1054         } finally {
  1055             make.at(prevPos);
  1058     //where
  1059     private List<Type> bsmStaticArgToTypes(List<Object> args) {
  1060         ListBuffer<Type> argtypes = new ListBuffer<>();
  1061         for (Object arg : args) {
  1062             argtypes.append(bsmStaticArgToType(arg));
  1064         return argtypes.toList();
  1067     private Type bsmStaticArgToType(Object arg) {
  1068         Assert.checkNonNull(arg);
  1069         if (arg instanceof ClassSymbol) {
  1070             return syms.classType;
  1071         } else if (arg instanceof Integer) {
  1072             return syms.intType;
  1073         } else if (arg instanceof Long) {
  1074             return syms.longType;
  1075         } else if (arg instanceof Float) {
  1076             return syms.floatType;
  1077         } else if (arg instanceof Double) {
  1078             return syms.doubleType;
  1079         } else if (arg instanceof String) {
  1080             return syms.stringType;
  1081         } else if (arg instanceof Pool.MethodHandle) {
  1082             return syms.methodHandleType;
  1083         } else if (arg instanceof MethodType) {
  1084             return syms.methodTypeType;
  1085         } else {
  1086             Assert.error("bad static arg " + arg.getClass());
  1087             return null;
  1091     /**
  1092      * Get the opcode associated with this method reference
  1093      */
  1094     private int referenceKind(Symbol refSym) {
  1095         if (refSym.isConstructor()) {
  1096             return ClassFile.REF_newInvokeSpecial;
  1097         } else {
  1098             if (refSym.isStatic()) {
  1099                 return ClassFile.REF_invokeStatic;
  1100             } else if ((refSym.flags() & PRIVATE) != 0) {
  1101                 return ClassFile.REF_invokeSpecial;
  1102             } else if (refSym.enclClass().isInterface()) {
  1103                 return ClassFile.REF_invokeInterface;
  1104             } else {
  1105                 return ClassFile.REF_invokeVirtual;
  1110     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1111     /**
  1112      * This visitor collects information about translation of a lambda expression.
  1113      * More specifically, it keeps track of the enclosing contexts and captured locals
  1114      * accessed by the lambda being translated (as well as other useful info).
  1115      * It also translates away problems for LambdaToMethod.
  1116      */
  1117     class LambdaAnalyzerPreprocessor extends TreeTranslator {
  1119         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1120         private List<Frame> frameStack;
  1122         /**
  1123          * keep the count of lambda expression (used to generate unambiguous
  1124          * names)
  1125          */
  1126         private int lambdaCount = 0;
  1128         /**
  1129          * keep the count of lambda expression defined in given context (used to
  1130          * generate unambiguous names for serializable lambdas)
  1131          */
  1132         private class SyntheticMethodNameCounter {
  1133             private Map<String, Integer> map = new HashMap<>();
  1134             int getIndex(StringBuilder buf) {
  1135                 String temp = buf.toString();
  1136                 Integer count = map.get(temp);
  1137                 if (count == null) {
  1138                     count = 0;
  1140                 ++count;
  1141                 map.put(temp, count);
  1142                 return count;
  1145         private SyntheticMethodNameCounter syntheticMethodNameCounts =
  1146                 new SyntheticMethodNameCounter();
  1148         private Map<Symbol, JCClassDecl> localClassDefs;
  1150         /**
  1151          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1152          * a static var init context
  1153          */
  1154         private Map<ClassSymbol, Symbol> clinits =
  1155                 new HashMap<ClassSymbol, Symbol>();
  1157         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
  1158             frameStack = List.nil();
  1159             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1160             return translate(tree);
  1163         @Override
  1164         public void visitBlock(JCBlock tree) {
  1165             List<Frame> prevStack = frameStack;
  1166             try {
  1167                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1168                     frameStack = frameStack.prepend(new Frame(tree));
  1170                 super.visitBlock(tree);
  1172             finally {
  1173                 frameStack = prevStack;
  1177         @Override
  1178         public void visitClassDef(JCClassDecl tree) {
  1179             List<Frame> prevStack = frameStack;
  1180             int prevLambdaCount = lambdaCount;
  1181             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
  1182                     syntheticMethodNameCounts;
  1183             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1184             DiagnosticSource prevSource = log.currentSource();
  1185             try {
  1186                 log.useSource(tree.sym.sourcefile);
  1187                 lambdaCount = 0;
  1188                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
  1189                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1190                 if (tree.sym.owner.kind == MTH) {
  1191                     localClassDefs.put(tree.sym, tree);
  1193                 if (directlyEnclosingLambda() != null) {
  1194                     tree.sym.owner = owner();
  1195                     if (tree.sym.hasOuterInstance()) {
  1196                         //if a class is defined within a lambda, the lambda must capture
  1197                         //its enclosing instance (if any)
  1198                         TranslationContext<?> localContext = context();
  1199                         while (localContext != null) {
  1200                             if (localContext.tree.getTag() == LAMBDA) {
  1201                                 ((LambdaTranslationContext)localContext)
  1202                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1204                             localContext = localContext.prev;
  1208                 frameStack = frameStack.prepend(new Frame(tree));
  1209                 super.visitClassDef(tree);
  1211             finally {
  1212                 log.useSource(prevSource.getFile());
  1213                 frameStack = prevStack;
  1214                 lambdaCount = prevLambdaCount;
  1215                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
  1216                 clinits = prevClinits;
  1220         @Override
  1221         public void visitIdent(JCIdent tree) {
  1222             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1223                 if (tree.sym.kind == VAR &&
  1224                         tree.sym.owner.kind == MTH &&
  1225                         tree.type.constValue() == null) {
  1226                     TranslationContext<?> localContext = context();
  1227                     while (localContext != null) {
  1228                         if (localContext.tree.getTag() == LAMBDA) {
  1229                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1230                             if (block == null) break;
  1231                             ((LambdaTranslationContext)localContext)
  1232                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1234                         localContext = localContext.prev;
  1236                 } else if (tree.sym.owner.kind == TYP) {
  1237                     TranslationContext<?> localContext = context();
  1238                     while (localContext != null) {
  1239                         if (localContext.tree.hasTag(LAMBDA)) {
  1240                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1241                             if (block == null) break;
  1242                             switch (block.getTag()) {
  1243                                 case CLASSDEF:
  1244                                     JCClassDecl cdecl = (JCClassDecl)block;
  1245                                     ((LambdaTranslationContext)localContext)
  1246                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1247                                     break;
  1248                                 default:
  1249                                     Assert.error("bad block kind");
  1252                         localContext = localContext.prev;
  1256             super.visitIdent(tree);
  1259         @Override
  1260         public void visitLambda(JCLambda tree) {
  1261             analyzeLambda(tree, "lambda.stat");
  1264         private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) {
  1265             // Translation of the receiver expression must occur first
  1266             JCExpression rcvr = translate(methodReferenceReceiver);
  1267             LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1");
  1268             if (rcvr != null) {
  1269                 context.methodReferenceReceiver = rcvr;
  1273         private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) {
  1274             List<Frame> prevStack = frameStack;
  1275             try {
  1276                 LambdaTranslationContext context = new LambdaTranslationContext(tree);
  1277                 if (dumpLambdaToMethodStats) {
  1278                     log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym);
  1280                 frameStack = frameStack.prepend(new Frame(tree));
  1281                 for (JCVariableDecl param : tree.params) {
  1282                     context.addSymbol(param.sym, PARAM);
  1283                     frameStack.head.addLocal(param.sym);
  1285                 contextMap.put(tree, context);
  1286                 super.visitLambda(tree);
  1287                 context.complete();
  1288                 return context;
  1290             finally {
  1291                 frameStack = prevStack;
  1295         @Override
  1296         public void visitMethodDef(JCMethodDecl tree) {
  1297             List<Frame> prevStack = frameStack;
  1298             try {
  1299                 frameStack = frameStack.prepend(new Frame(tree));
  1300                 super.visitMethodDef(tree);
  1302             finally {
  1303                 frameStack = prevStack;
  1307         @Override
  1308         public void visitNewClass(JCNewClass tree) {
  1309             TypeSymbol def = tree.type.tsym;
  1310             boolean inReferencedClass = currentlyInClass(def);
  1311             boolean isLocal = def.isLocal();
  1312             if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
  1313                 TranslationContext<?> localContext = context();
  1314                 while (localContext != null) {
  1315                     if (localContext.tree.getTag() == LAMBDA) {
  1316                         ((LambdaTranslationContext)localContext)
  1317                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1319                     localContext = localContext.prev;
  1322             if (context() != null && !inReferencedClass && isLocal) {
  1323                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1324                 captureLocalClassDefs(def, lambdaContext);
  1326             super.visitNewClass(tree);
  1328         //where
  1329             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1330                 JCClassDecl localCDef = localClassDefs.get(csym);
  1331                 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
  1332                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1333                         @Override
  1334                         void addFreeVars(ClassSymbol c) {
  1335                             captureLocalClassDefs(c, lambdaContext);
  1337                         @Override
  1338                         void visitSymbol(Symbol sym) {
  1339                             if (sym.kind == VAR &&
  1340                                     sym.owner.kind == MTH &&
  1341                                     ((VarSymbol)sym).getConstValue() == null) {
  1342                                 TranslationContext<?> localContext = context();
  1343                                 while (localContext != null) {
  1344                                     if (localContext.tree.getTag() == LAMBDA) {
  1345                                         JCTree block = capturedDecl(localContext.depth, sym);
  1346                                         if (block == null) break;
  1347                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1349                                     localContext = localContext.prev;
  1353                     };
  1354                     fvc.scan(localCDef);
  1357         //where
  1358         boolean currentlyInClass(Symbol csym) {
  1359             for (Frame frame : frameStack) {
  1360                 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
  1361                     JCClassDecl cdef = (JCClassDecl) frame.tree;
  1362                     if (cdef.sym == csym) {
  1363                         return true;
  1367             return false;
  1370         /**
  1371          * Method references to local class constructors, may, if the local
  1372          * class references local variables, have implicit constructor
  1373          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1374          * information added in the LambdaToMethod pass will have the wrong
  1375          * signature. Hooks between Lower and LambdaToMethod have been added to
  1376          * handle normal "new" in this case. This visitor converts potentially
  1377          * affected method references into a lambda containing a normal
  1378          * expression.
  1380          * @param tree
  1381          */
  1382         @Override
  1383         public void visitReference(JCMemberReference tree) {
  1384             ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree);
  1385             contextMap.put(tree, rcontext);
  1386             if (rcontext.needsConversionToLambda()) {
  1387                  // Convert to a lambda, and process as such
  1388                 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner());
  1389                 analyzeLambda(conv.lambda(), conv.getReceiverExpression());
  1390             } else {
  1391                 super.visitReference(tree);
  1392                 if (dumpLambdaToMethodStats) {
  1393                     log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null);
  1398         @Override
  1399         public void visitSelect(JCFieldAccess tree) {
  1400             if (context() != null && tree.sym.kind == VAR &&
  1401                         (tree.sym.name == names._this ||
  1402                          tree.sym.name == names._super)) {
  1403                 // A select of this or super means, if we are in a lambda,
  1404                 // we much have an instance context
  1405                 TranslationContext<?> localContext = context();
  1406                 while (localContext != null) {
  1407                     if (localContext.tree.hasTag(LAMBDA)) {
  1408                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1409                         if (clazz == null) break;
  1410                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1412                     localContext = localContext.prev;
  1415             super.visitSelect(tree);
  1418         @Override
  1419         public void visitVarDef(JCVariableDecl tree) {
  1420             TranslationContext<?> context = context();
  1421             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1422                     (LambdaTranslationContext)context :
  1423                     null;
  1424             if (ltc != null) {
  1425                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1426                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1428                 // Check for type variables (including as type arguments).
  1429                 // If they occur within class nested in a lambda, mark for erasure
  1430                 Type type = tree.sym.asType();
  1431                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1432                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1436             List<Frame> prevStack = frameStack;
  1437             try {
  1438                 if (tree.sym.owner.kind == MTH) {
  1439                     frameStack.head.addLocal(tree.sym);
  1441                 frameStack = frameStack.prepend(new Frame(tree));
  1442                 super.visitVarDef(tree);
  1444             finally {
  1445                 frameStack = prevStack;
  1449         /**
  1450          * Return a valid owner given the current declaration stack
  1451          * (required to skip synthetic lambda symbols)
  1452          */
  1453         private Symbol owner() {
  1454             return owner(false);
  1457         @SuppressWarnings("fallthrough")
  1458         private Symbol owner(boolean skipLambda) {
  1459             List<Frame> frameStack2 = frameStack;
  1460             while (frameStack2.nonEmpty()) {
  1461                 switch (frameStack2.head.tree.getTag()) {
  1462                     case VARDEF:
  1463                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1464                             frameStack2 = frameStack2.tail;
  1465                             break;
  1467                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1468                         return initSym(cdecl.sym,
  1469                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1470                     case BLOCK:
  1471                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1472                         return initSym(cdecl2.sym,
  1473                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1474                     case CLASSDEF:
  1475                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1476                     case METHODDEF:
  1477                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1478                     case LAMBDA:
  1479                         if (!skipLambda)
  1480                             return ((LambdaTranslationContext)contextMap
  1481                                     .get(frameStack2.head.tree)).translatedSym;
  1482                     default:
  1483                         frameStack2 = frameStack2.tail;
  1486             Assert.error();
  1487             return null;
  1490         private Symbol initSym(ClassSymbol csym, long flags) {
  1491             boolean isStatic = (flags & STATIC) != 0;
  1492             if (isStatic) {
  1493                 /* static clinits are generated in Gen, so we need to use a fake
  1494                  * one. Attr creates a fake clinit method while attributing
  1495                  * lambda expressions used as initializers of static fields, so
  1496                  * let's use that one.
  1497                  */
  1498                 MethodSymbol clinit = attr.removeClinit(csym);
  1499                 if (clinit != null) {
  1500                     clinits.put(csym, clinit);
  1501                     return clinit;
  1504                 /* if no clinit is found at Attr, then let's try at clinits.
  1505                  */
  1506                 clinit = (MethodSymbol)clinits.get(csym);
  1507                 if (clinit == null) {
  1508                     /* no luck, let's create a new one
  1509                      */
  1510                     clinit = makePrivateSyntheticMethod(STATIC,
  1511                             names.clinit,
  1512                             new MethodType(List.<Type>nil(), syms.voidType,
  1513                                 List.<Type>nil(), syms.methodClass),
  1514                             csym);
  1515                     clinits.put(csym, clinit);
  1517                 return clinit;
  1518             } else {
  1519                 //get the first constructor and treat it as the instance init sym
  1520                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1521                     return s;
  1524             Assert.error("init not found");
  1525             return null;
  1528         private JCTree directlyEnclosingLambda() {
  1529             if (frameStack.isEmpty()) {
  1530                 return null;
  1532             List<Frame> frameStack2 = frameStack;
  1533             while (frameStack2.nonEmpty()) {
  1534                 switch (frameStack2.head.tree.getTag()) {
  1535                     case CLASSDEF:
  1536                     case METHODDEF:
  1537                         return null;
  1538                     case LAMBDA:
  1539                         return frameStack2.head.tree;
  1540                     default:
  1541                         frameStack2 = frameStack2.tail;
  1544             Assert.error();
  1545             return null;
  1548         private boolean inClassWithinLambda() {
  1549             if (frameStack.isEmpty()) {
  1550                 return false;
  1552             List<Frame> frameStack2 = frameStack;
  1553             boolean classFound = false;
  1554             while (frameStack2.nonEmpty()) {
  1555                 switch (frameStack2.head.tree.getTag()) {
  1556                     case LAMBDA:
  1557                         return classFound;
  1558                     case CLASSDEF:
  1559                         classFound = true;
  1560                         frameStack2 = frameStack2.tail;
  1561                         break;
  1562                     default:
  1563                         frameStack2 = frameStack2.tail;
  1566             // No lambda
  1567             return false;
  1570         /**
  1571          * Return the declaration corresponding to a symbol in the enclosing
  1572          * scope; the depth parameter is used to filter out symbols defined
  1573          * in nested scopes (which do not need to undergo capture).
  1574          */
  1575         private JCTree capturedDecl(int depth, Symbol sym) {
  1576             int currentDepth = frameStack.size() - 1;
  1577             for (Frame block : frameStack) {
  1578                 switch (block.tree.getTag()) {
  1579                     case CLASSDEF:
  1580                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1581                         if (sym.isMemberOf(clazz, types)) {
  1582                             return currentDepth > depth ? null : block.tree;
  1584                         break;
  1585                     case VARDEF:
  1586                         if (((JCVariableDecl)block.tree).sym == sym &&
  1587                                 sym.owner.kind == MTH) { //only locals are captured
  1588                             return currentDepth > depth ? null : block.tree;
  1590                         break;
  1591                     case BLOCK:
  1592                     case METHODDEF:
  1593                     case LAMBDA:
  1594                         if (block.locals != null && block.locals.contains(sym)) {
  1595                             return currentDepth > depth ? null : block.tree;
  1597                         break;
  1598                     default:
  1599                         Assert.error("bad decl kind " + block.tree.getTag());
  1601                 currentDepth--;
  1603             return null;
  1606         private TranslationContext<?> context() {
  1607             for (Frame frame : frameStack) {
  1608                 TranslationContext<?> context = contextMap.get(frame.tree);
  1609                 if (context != null) {
  1610                     return context;
  1613             return null;
  1616         /**
  1617          *  This is used to filter out those identifiers that needs to be adjusted
  1618          *  when translating away lambda expressions
  1619          */
  1620         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1621             return (sym.kind == VAR || sym.kind == MTH)
  1622                     && !sym.isStatic()
  1623                     && sym.name != names.init;
  1626         /**
  1627          * This is used to filter out those new class expressions that need to
  1628          * be qualified with an enclosing tree
  1629          */
  1630         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1631             if (context != null
  1632                     && tree.encl == null
  1633                     && tree.def == null
  1634                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1635                 Type encl = tree.type.getEnclosingType();
  1636                 Type current = context.owner.enclClass().type;
  1637                 while (!current.hasTag(NONE)) {
  1638                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1639                         return true;
  1641                     current = current.getEnclosingType();
  1643                 return false;
  1644             } else {
  1645                 return false;
  1649         private class Frame {
  1650             final JCTree tree;
  1651             List<Symbol> locals;
  1653             public Frame(JCTree tree) {
  1654                 this.tree = tree;
  1657             void addLocal(Symbol sym) {
  1658                 if (locals == null) {
  1659                     locals = List.nil();
  1661                 locals = locals.prepend(sym);
  1665         /**
  1666          * This class is used to store important information regarding translation of
  1667          * lambda expression/method references (see subclasses).
  1668          */
  1669         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1671             /** the underlying (untranslated) tree */
  1672             final T tree;
  1674             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1675             final Symbol owner;
  1677             /** the depth of this lambda expression in the frame stack */
  1678             final int depth;
  1680             /** the enclosing translation context (set for nested lambdas/mref) */
  1681             final TranslationContext<?> prev;
  1683             /** list of methods to be bridged by the meta-factory */
  1684             final List<Symbol> bridges;
  1686             TranslationContext(T tree) {
  1687                 this.tree = tree;
  1688                 this.owner = owner();
  1689                 this.depth = frameStack.size() - 1;
  1690                 this.prev = context();
  1691                 ClassSymbol csym =
  1692                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1693                 this.bridges = types.functionalInterfaceBridges(csym);
  1696             /** does this functional expression need to be created using alternate metafactory? */
  1697             boolean needsAltMetafactory() {
  1698                 return tree.targets.length() > 1 ||
  1699                         isSerializable() ||
  1700                         bridges.length() > 1;
  1703             /** does this functional expression require serialization support? */
  1704             boolean isSerializable() {
  1705                 if (forceSerializable) {
  1706                     return true;
  1708                 for (Type target : tree.targets) {
  1709                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1710                         return true;
  1713                 return false;
  1716             /**
  1717              * @return Name of the enclosing method to be folded into synthetic
  1718              * method name
  1719              */
  1720             String enclosingMethodName() {
  1721                 return syntheticMethodNameComponent(owner.name);
  1724             /**
  1725              * @return Method name in a form that can be folded into a
  1726              * component of a synthetic method name
  1727              */
  1728             String syntheticMethodNameComponent(Name name) {
  1729                 if (name == null) {
  1730                     return "null";
  1732                 String methodName = name.toString();
  1733                 if (methodName.equals("<clinit>")) {
  1734                     methodName = "static";
  1735                 } else if (methodName.equals("<init>")) {
  1736                     methodName = "new";
  1738                 return methodName;
  1742         /**
  1743          * This class retains all the useful information about a lambda expression;
  1744          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1745          * and the used by the main translation routines in order to adjust references
  1746          * to captured locals/members, etc.
  1747          */
  1748         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1750             /** variable in the enclosing context to which this lambda is assigned */
  1751             final Symbol self;
  1753             /** variable in the enclosing context to which this lambda is assigned */
  1754             final Symbol assignedTo;
  1756             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
  1758             /** the synthetic symbol for the method hoisting the translated lambda */
  1759             MethodSymbol translatedSym;
  1761             List<JCVariableDecl> syntheticParams;
  1763             /**
  1764              * to prevent recursion, track local classes processed
  1765              */
  1766             final Set<Symbol> freeVarProcessedLocalClasses;
  1768             /**
  1769              * For method references converted to lambdas.  The method
  1770              * reference receiver expression. Must be treated like a captured
  1771              * variable.
  1772              */
  1773             JCExpression methodReferenceReceiver;
  1775             LambdaTranslationContext(JCLambda tree) {
  1776                 super(tree);
  1777                 Frame frame = frameStack.head;
  1778                 switch (frame.tree.getTag()) {
  1779                     case VARDEF:
  1780                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
  1781                         break;
  1782                     case ASSIGN:
  1783                         self = null;
  1784                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
  1785                         break;
  1786                     default:
  1787                         assignedTo = self = null;
  1788                         break;
  1791                 // This symbol will be filled-in in complete
  1792                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
  1794                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
  1796                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
  1797                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
  1798                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
  1799                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
  1800                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
  1802                 freeVarProcessedLocalClasses = new HashSet<>();
  1805              /**
  1806              * For a serializable lambda, generate a disambiguating string
  1807              * which maximizes stability across deserialization.
  1809              * @return String to differentiate synthetic lambda method names
  1810              */
  1811             private String serializedLambdaDisambiguation() {
  1812                 StringBuilder buf = new StringBuilder();
  1813                 // Append the enclosing method signature to differentiate
  1814                 // overloaded enclosing methods.  For lambdas enclosed in
  1815                 // lambdas, the generated lambda method will not have type yet,
  1816                 // but the enclosing method's name will have been generated
  1817                 // with this same method, so it will be unique and never be
  1818                 // overloaded.
  1819                 Assert.check(
  1820                         owner.type != null ||
  1821                         directlyEnclosingLambda() != null);
  1822                 if (owner.type != null) {
  1823                     buf.append(typeSig(owner.type));
  1824                     buf.append(":");
  1827                 // Add target type info
  1828                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
  1829                 buf.append(" ");
  1831                 // Add variable assigned to
  1832                 if (assignedTo != null) {
  1833                     buf.append(assignedTo.flatName());
  1834                     buf.append("=");
  1836                 //add captured locals info: type, name, order
  1837                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
  1838                     if (fv != self) {
  1839                         buf.append(typeSig(fv.type));
  1840                         buf.append(" ");
  1841                         buf.append(fv.flatName());
  1842                         buf.append(",");
  1846                 return buf.toString();
  1849             /**
  1850              * For a non-serializable lambda, generate a simple method.
  1852              * @return Name to use for the synthetic lambda method name
  1853              */
  1854             private Name lambdaName() {
  1855                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
  1858             /**
  1859              * For a serializable lambda, generate a method name which maximizes
  1860              * name stability across deserialization.
  1862              * @return Name to use for the synthetic lambda method name
  1863              */
  1864             private Name serializedLambdaName() {
  1865                 StringBuilder buf = new StringBuilder();
  1866                 buf.append(names.lambda);
  1867                 // Append the name of the method enclosing the lambda.
  1868                 buf.append(enclosingMethodName());
  1869                 buf.append('$');
  1870                 // Append a hash of the disambiguating string : enclosing method
  1871                 // signature, etc.
  1872                 String disam = serializedLambdaDisambiguation();
  1873                 buf.append(Integer.toHexString(disam.hashCode()));
  1874                 buf.append('$');
  1875                 // The above appended name components may not be unique, append
  1876                 // a count based on the above name components.
  1877                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  1878                 String result = buf.toString();
  1879                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
  1880                 return names.fromString(result);
  1883             /**
  1884              * Translate a symbol of a given kind into something suitable for the
  1885              * synthetic lambda body
  1886              */
  1887             Symbol translate(final Symbol sym, LambdaSymbolKind skind) {
  1888                 Symbol ret;
  1889                 switch (skind) {
  1890                     case CAPTURED_THIS:
  1891                         ret = sym;  // self represented
  1892                         break;
  1893                     case TYPE_VAR:
  1894                         // Just erase the type var
  1895                         ret = new VarSymbol(sym.flags(), sym.name,
  1896                                 types.erasure(sym.type), sym.owner);
  1898                         /* this information should also be kept for LVT generation at Gen
  1899                          * a Symbol with pos < startPos won't be tracked.
  1900                          */
  1901                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
  1902                         break;
  1903                     case CAPTURED_VAR:
  1904                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
  1905                             @Override
  1906                             public Symbol baseSymbol() {
  1907                                 //keep mapping with original captured symbol
  1908                                 return sym;
  1910                         };
  1911                         break;
  1912                     case LOCAL_VAR:
  1913                         ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
  1914                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1915                         break;
  1916                     case PARAM:
  1917                         ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym);
  1918                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1919                         break;
  1920                     default:
  1921                         Assert.error(skind.name());
  1922                         throw new AssertionError();
  1924                 if (ret != sym) {
  1925                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1926                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1928                 return ret;
  1931             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1932                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
  1933                 if (!transMap.containsKey(sym)) {
  1934                     transMap.put(sym, translate(sym, skind));
  1938             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
  1939                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
  1940                 Assert.checkNonNull(m);
  1941                 return m;
  1944             JCTree translate(JCIdent lambdaIdent) {
  1945                 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
  1946                     if (m.containsKey(lambdaIdent.sym)) {
  1947                         Symbol tSym = m.get(lambdaIdent.sym);
  1948                         JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
  1949                         tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
  1950                         return t;
  1953                 return null;
  1956             /**
  1957              * The translatedSym is not complete/accurate until the analysis is
  1958              * finished.  Once the analysis is finished, the translatedSym is
  1959              * "completed" -- updated with type information, access modifiers,
  1960              * and full parameter list.
  1961              */
  1962             void complete() {
  1963                 if (syntheticParams != null) {
  1964                     return;
  1966                 boolean inInterface = translatedSym.owner.isInterface();
  1967                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1969                 // If instance access isn't needed, make it static.
  1970                 // Interface instance methods must be default methods.
  1971                 // Lambda methods are private synthetic.
  1972                 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
  1973                 // from the class.
  1974                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
  1975                         owner.flags_field & STRICTFP |
  1976                         owner.owner.flags_field & STRICTFP |
  1977                         PRIVATE |
  1978                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  1980                 //compute synthetic params
  1981                 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
  1982                 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>();
  1984                 // The signature of the method is augmented with the following
  1985                 // synthetic parameters:
  1986                 //
  1987                 // 1) reference to enclosing contexts captured by the lambda expression
  1988                 // 2) enclosing locals captured by the lambda expression
  1989                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
  1990                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1991                     parameterSymbols.append((VarSymbol) thisSym);
  1993                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
  1994                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1995                     parameterSymbols.append((VarSymbol) thisSym);
  1997                 syntheticParams = params.toList();
  1999                 translatedSym.params = parameterSymbols.toList();
  2001                 // Compute and set the lambda name
  2002                 translatedSym.name = isSerializable()
  2003                         ? serializedLambdaName()
  2004                         : lambdaName();
  2006                 //prepend synthetic args to translated lambda method signature
  2007                 translatedSym.type = types.createMethodTypeWithParameters(
  2008                         generatedLambdaSig(),
  2009                         TreeInfo.types(syntheticParams));
  2012             Type generatedLambdaSig() {
  2013                 return types.erasure(tree.getDescriptorType(types));
  2017         /**
  2018          * This class retains all the useful information about a method reference;
  2019          * the contents of this class are filled by the LambdaAnalyzer visitor,
  2020          * and the used by the main translation routines in order to adjust method
  2021          * references (i.e. in case a bridge is needed)
  2022          */
  2023         private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  2025             final boolean isSuper;
  2026             final Symbol sigPolySym;
  2028             ReferenceTranslationContext(JCMemberReference tree) {
  2029                 super(tree);
  2030                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2031                 this.sigPolySym = isSignaturePolymorphic()
  2032                         ? makePrivateSyntheticMethod(tree.sym.flags(),
  2033                                               tree.sym.name,
  2034                                               bridgedRefSig(),
  2035                                               tree.sym.enclClass())
  2036                         : null;
  2039             /**
  2040              * Get the opcode associated with this method reference
  2041              */
  2042             int referenceKind() {
  2043                 return LambdaToMethod.this.referenceKind(tree.sym);
  2046             boolean needsVarArgsConversion() {
  2047                 return tree.varargsElement != null;
  2050             /**
  2051              * @return Is this an array operation like clone()
  2052              */
  2053             boolean isArrayOp() {
  2054                 return tree.sym.owner == syms.arrayClass;
  2057             boolean receiverAccessible() {
  2058                 //hack needed to workaround 292 bug (7087658)
  2059                 //when 292 issue is fixed we should remove this and change the backend
  2060                 //code to always generate a method handle to an accessible method
  2061                 return tree.ownerAccessible;
  2064             /**
  2065              * The VM does not support access across nested classes (8010319).
  2066              * Were that ever to change, this should be removed.
  2067              */
  2068             boolean isPrivateInOtherClass() {
  2069                 return  (tree.sym.flags() & PRIVATE) != 0 &&
  2070                         !types.isSameType(
  2071                               types.erasure(tree.sym.enclClass().asType()),
  2072                               types.erasure(owner.enclClass().asType()));
  2075             /**
  2076              * Signature polymorphic methods need special handling.
  2077              * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
  2078              */
  2079             final boolean isSignaturePolymorphic() {
  2080                 return  tree.sym.kind == MTH &&
  2081                         types.isSignaturePolymorphic((MethodSymbol)tree.sym);
  2084             /**
  2085              * Erasure destroys the implementation parameter subtype
  2086              * relationship for intersection types
  2087              */
  2088             boolean interfaceParameterIsIntersectionType() {
  2089                 List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
  2090                 if (tree.kind == ReferenceKind.UNBOUND) {
  2091                     tl = tl.tail;
  2093                 for (; tl.nonEmpty(); tl = tl.tail) {
  2094                     Type pt = tl.head;
  2095                     if (pt.getKind() == TypeKind.TYPEVAR) {
  2096                         TypeVar tv = (TypeVar) pt;
  2097                         if (tv.bound.getKind() == TypeKind.INTERSECTION) {
  2098                             return true;
  2102                 return false;
  2105             /**
  2106              * Does this reference need to be converted to a lambda
  2107              * (i.e. var args need to be expanded or "super" is used)
  2108              */
  2109             final boolean needsConversionToLambda() {
  2110                 return interfaceParameterIsIntersectionType() ||
  2111                         isSuper ||
  2112                         needsVarArgsConversion() ||
  2113                         isArrayOp() ||
  2114                         isPrivateInOtherClass() ||
  2115                         !receiverAccessible() ||
  2116                         (tree.getMode() == ReferenceMode.NEW &&
  2117                           tree.kind != ReferenceKind.ARRAY_CTOR &&
  2118                           (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
  2121             Type generatedRefSig() {
  2122                 return types.erasure(tree.sym.type);
  2125             Type bridgedRefSig() {
  2126                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  2130     // </editor-fold>
  2132     /*
  2133      * These keys provide mappings for various translated lambda symbols
  2134      * and the prevailing order must be maintained.
  2135      */
  2136     enum LambdaSymbolKind {
  2137         PARAM,          // original to translated lambda parameters
  2138         LOCAL_VAR,      // original to translated lambda locals
  2139         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
  2140         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
  2141         TYPE_VAR;       // original to translated lambda type variables
  2144     /**
  2145      * ****************************************************************
  2146      * Signature Generation
  2147      * ****************************************************************
  2148      */
  2150     private String typeSig(Type type) {
  2151         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2152         sg.assembleSig(type);
  2153         return sg.toString();
  2156     private String classSig(Type type) {
  2157         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2158         sg.assembleClassSig(type);
  2159         return sg.toString();
  2162     /**
  2163      * Signature Generation
  2164      */
  2165     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  2167         /**
  2168          * An output buffer for type signatures.
  2169          */
  2170         StringBuilder sb = new StringBuilder();
  2172         L2MSignatureGenerator() {
  2173             super(types);
  2176         @Override
  2177         protected void append(char ch) {
  2178             sb.append(ch);
  2181         @Override
  2182         protected void append(byte[] ba) {
  2183             sb.append(new String(ba));
  2186         @Override
  2187         protected void append(Name name) {
  2188             sb.append(name.toString());
  2191         @Override
  2192         public String toString() {
  2193             return sb.toString();

mercurial