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

Thu, 10 Apr 2014 14:01:53 -0700

author
rfield
date
Thu, 10 Apr 2014 14:01:53 -0700
changeset 2359
ba7ee72d5d6b
parent 2358
6a6a8a9860a4
child 2380
b17805de5edf
permissions
-rw-r--r--

8037935: Javac -- final local String var referenced in binary/unary op in lambda produces code that does not verify
Summary: Remove over-zealous Attr optimization breaking lambdas
Reviewed-by: jjg, vromero

     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.VarSymbol;
    40 import com.sun.tools.javac.code.Symtab;
    41 import com.sun.tools.javac.code.Type;
    42 import com.sun.tools.javac.code.Type.MethodType;
    43 import com.sun.tools.javac.code.Types;
    44 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
    45 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
    46 import com.sun.tools.javac.jvm.*;
    47 import com.sun.tools.javac.util.*;
    48 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    49 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
    51 import java.util.EnumMap;
    52 import java.util.HashMap;
    53 import java.util.LinkedHashMap;
    54 import java.util.Map;
    56 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
    57 import static com.sun.tools.javac.code.Flags.*;
    58 import static com.sun.tools.javac.code.Kinds.*;
    59 import static com.sun.tools.javac.code.TypeTag.*;
    60 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    62 /**
    63  * This pass desugars lambda expressions into static methods
    64  *
    65  *  <p><b>This is NOT part of any supported API.
    66  *  If you write code that depends on this, you do so at your own risk.
    67  *  This code and its internal interfaces are subject to change or
    68  *  deletion without notice.</b>
    69  */
    70 public class LambdaToMethod extends TreeTranslator {
    72     private Attr attr;
    73     private JCDiagnostic.Factory diags;
    74     private Log log;
    75     private Lower lower;
    76     private Names names;
    77     private Symtab syms;
    78     private Resolve rs;
    79     private TreeMaker make;
    80     private Types types;
    81     private TransTypes transTypes;
    82     private Env<AttrContext> attrEnv;
    84     /** the analyzer scanner */
    85     private LambdaAnalyzerPreprocessor analyzer;
    87     /** map from lambda trees to translation contexts */
    88     private Map<JCTree, TranslationContext<?>> contextMap;
    90     /** current translation context (visitor argument) */
    91     private TranslationContext<?> context;
    93     /** info about the current class being processed */
    94     private KlassInfo kInfo;
    96     /** dump statistics about lambda code generation */
    97     private boolean dumpLambdaToMethodStats;
    99     /** force serializable representation, for stress testing **/
   100     private final boolean forceSerializable;
   102     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
   103     public static final int FLAG_SERIALIZABLE = 1 << 0;
   105     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
   106     public static final int FLAG_MARKERS = 1 << 1;
   108     /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
   109     public static final int FLAG_BRIDGES = 1 << 2;
   111     // <editor-fold defaultstate="collapsed" desc="Instantiating">
   112     protected static final Context.Key<LambdaToMethod> unlambdaKey =
   113             new Context.Key<LambdaToMethod>();
   115     public static LambdaToMethod instance(Context context) {
   116         LambdaToMethod instance = context.get(unlambdaKey);
   117         if (instance == null) {
   118             instance = new LambdaToMethod(context);
   119         }
   120         return instance;
   121     }
   122     private LambdaToMethod(Context context) {
   123         context.put(unlambdaKey, this);
   124         diags = JCDiagnostic.Factory.instance(context);
   125         log = Log.instance(context);
   126         lower = Lower.instance(context);
   127         names = Names.instance(context);
   128         syms = Symtab.instance(context);
   129         rs = Resolve.instance(context);
   130         make = TreeMaker.instance(context);
   131         types = Types.instance(context);
   132         transTypes = TransTypes.instance(context);
   133         analyzer = new LambdaAnalyzerPreprocessor();
   134         Options options = Options.instance(context);
   135         dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats");
   136         attr = Attr.instance(context);
   137         forceSerializable = options.isSet("forceSerializable");
   138     }
   139     // </editor-fold>
   141     private class KlassInfo {
   143         /**
   144          * list of methods to append
   145          */
   146         private ListBuffer<JCTree> appendedMethodList;
   148         /**
   149          * list of deserialization cases
   150          */
   151         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   153        /**
   154          * deserialize method symbol
   155          */
   156         private final MethodSymbol deserMethodSym;
   158         /**
   159          * deserialize method parameter symbol
   160          */
   161         private final VarSymbol deserParamSym;
   163         private final JCClassDecl clazz;
   165         private KlassInfo(JCClassDecl clazz) {
   166             this.clazz = clazz;
   167             appendedMethodList = new ListBuffer<>();
   168             deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
   169             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
   170                     List.<Type>nil(), syms.methodClass);
   171             deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
   172             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
   173                     syms.serializedLambdaType, deserMethodSym);
   174         }
   176         private void addMethod(JCTree decl) {
   177             appendedMethodList = appendedMethodList.prepend(decl);
   178         }
   179     }
   181     // <editor-fold defaultstate="collapsed" desc="translate methods">
   182     @Override
   183     public <T extends JCTree> T translate(T tree) {
   184         TranslationContext<?> newContext = contextMap.get(tree);
   185         return translate(tree, newContext != null ? newContext : context);
   186     }
   188     <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
   189         TranslationContext<?> prevContext = context;
   190         try {
   191             context = newContext;
   192             return super.translate(tree);
   193         }
   194         finally {
   195             context = prevContext;
   196         }
   197     }
   199     <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
   200         ListBuffer<T> buf = new ListBuffer<>();
   201         for (T tree : trees) {
   202             buf.append(translate(tree, newContext));
   203         }
   204         return buf.toList();
   205     }
   207     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
   208         this.make = make;
   209         this.attrEnv = env;
   210         this.context = null;
   211         this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
   212         return translate(cdef);
   213     }
   214     // </editor-fold>
   216     // <editor-fold defaultstate="collapsed" desc="visitor methods">
   217     /**
   218      * Visit a class.
   219      * Maintain the translatedMethodList across nested classes.
   220      * Append the translatedMethodList to the class after it is translated.
   221      * @param tree
   222      */
   223     @Override
   224     public void visitClassDef(JCClassDecl tree) {
   225         if (tree.sym.owner.kind == PCK) {
   226             //analyze class
   227             tree = analyzer.analyzeAndPreprocessClass(tree);
   228         }
   229         KlassInfo prevKlassInfo = kInfo;
   230         try {
   231             kInfo = new KlassInfo(tree);
   232             super.visitClassDef(tree);
   233             if (!kInfo.deserializeCases.isEmpty()) {
   234                 int prevPos = make.pos;
   235                 try {
   236                     make.at(tree);
   237                     kInfo.addMethod(makeDeserializeMethod(tree.sym));
   238                 } finally {
   239                     make.at(prevPos);
   240                 }
   241             }
   242             //add all translated instance methods here
   243             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
   244             tree.defs = tree.defs.appendList(newMethods);
   245             for (JCTree lambda : newMethods) {
   246                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
   247             }
   248             result = tree;
   249         } finally {
   250             kInfo = prevKlassInfo;
   251         }
   252     }
   254     /**
   255      * Translate a lambda into a method to be inserted into the class.
   256      * Then replace the lambda site with an invokedynamic call of to lambda
   257      * meta-factory, which will use the lambda method.
   258      * @param tree
   259      */
   260     @Override
   261     public void visitLambda(JCLambda tree) {
   262         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
   263         MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
   264         MethodType lambdaType = (MethodType) sym.type;
   266         {
   267             Symbol owner = localContext.owner;
   268             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   269             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   271             for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
   272                 if (tc.position.onLambda == tree) {
   273                     lambdaTypeAnnos.append(tc);
   274                 } else {
   275                     ownerTypeAnnos.append(tc);
   276                 }
   277             }
   278             if (lambdaTypeAnnos.nonEmpty()) {
   279                 owner.setTypeAttributes(ownerTypeAnnos.toList());
   280                 sym.setTypeAttributes(lambdaTypeAnnos.toList());
   281             }
   282         }
   284         //create the method declaration hoisting the lambda body
   285         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
   286                 sym.name,
   287                 make.QualIdent(lambdaType.getReturnType().tsym),
   288                 List.<JCTypeParameter>nil(),
   289                 localContext.syntheticParams,
   290                 lambdaType.getThrownTypes() == null ?
   291                     List.<JCExpression>nil() :
   292                     make.Types(lambdaType.getThrownTypes()),
   293                 null,
   294                 null);
   295         lambdaDecl.sym = sym;
   296         lambdaDecl.type = lambdaType;
   298         //translate lambda body
   299         //As the lambda body is translated, all references to lambda locals,
   300         //captured variables, enclosing members are adjusted accordingly
   301         //to refer to the static method parameters (rather than i.e. acessing to
   302         //captured members directly).
   303         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
   305         //Add the method to the list of methods to be added to this class.
   306         kInfo.addMethod(lambdaDecl);
   308         //now that we have generated a method for the lambda expression,
   309         //we can translate the lambda into a method reference pointing to the newly
   310         //created method.
   311         //
   312         //Note that we need to adjust the method handle so that it will match the
   313         //signature of the SAM descriptor - this means that the method reference
   314         //should be added the following synthetic arguments:
   315         //
   316         // * the "this" argument if it is an instance method
   317         // * enclosing locals captured by the lambda expression
   319         ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
   321         if (!sym.isStatic()) {
   322             syntheticInits.append(makeThis(
   323                     sym.owner.enclClass().asType(),
   324                     localContext.owner.enclClass()));
   325         }
   327         //add captured locals
   328         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
   329             if (fv != localContext.self) {
   330                 JCTree captured_local = make.Ident(fv).setType(fv.type);
   331                 syntheticInits.append((JCExpression) captured_local);
   332             }
   333         }
   335         //then, determine the arguments to the indy call
   336         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   338         //build a sam instance using an indy call to the meta-factory
   339         int refKind = referenceKind(sym);
   341         //convert to an invokedynamic call
   342         result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
   343     }
   345     private JCIdent makeThis(Type type, Symbol owner) {
   346         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
   347                 names._this,
   348                 type,
   349                 owner);
   350         return make.Ident(_this);
   351     }
   353     /**
   354      * Translate a method reference into an invokedynamic call to the
   355      * meta-factory.
   356      * @param tree
   357      */
   358     @Override
   359     public void visitReference(JCMemberReference tree) {
   360         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   362         //first determine the method symbol to be used to generate the sam instance
   363         //this is either the method reference symbol, or the bridged reference symbol
   364         Symbol refSym = localContext.needsBridge()
   365                 ? localContext.bridgeSym
   366                 : localContext.isSignaturePolymorphic()
   367                 ? localContext.sigPolySym
   368                 : tree.sym;
   370         //build the bridge method, if needed
   371         if (localContext.needsBridge()) {
   372             bridgeMemberReference(tree, localContext);
   373         }
   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             JCExpression init = translate(tree.init);
   442             int prevPos = make.pos;
   443             try {
   444                 result = make.at(tree).VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
   445             } finally {
   446                 make.at(prevPos);
   447             }
   448         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   449             JCExpression init = translate(tree.init);
   450             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   451             int prevPos = make.pos;
   452             try {
   453                 result = make.at(tree).VarDef(xsym, init);
   454             } finally {
   455                 make.at(prevPos);
   456             }
   457             // Replace the entered symbol for this variable
   458             Scope sc = tree.sym.owner.members();
   459             if (sc != null) {
   460                 sc.remove(tree.sym);
   461                 sc.enter(xsym);
   462             }
   463         } else {
   464             super.visitVarDef(tree);
   465         }
   466     }
   468     // </editor-fold>
   470     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   472     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   473         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   474                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   475                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   476     }
   478     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   479         Type restype = lambdaMethodDecl.type.getReturnType();
   480         boolean isLambda_void = expr.type.hasTag(VOID);
   481         boolean isTarget_void = restype.hasTag(VOID);
   482         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   483         int prevPos = make.pos;
   484         try {
   485             if (isTarget_void) {
   486                 //target is void:
   487                 // BODY;
   488                 JCStatement stat = make.at(expr).Exec(expr);
   489                 return make.Block(0, List.<JCStatement>of(stat));
   490             } else if (isLambda_void && isTarget_Void) {
   491                 //void to Void conversion:
   492                 // BODY; return null;
   493                 ListBuffer<JCStatement> stats = new ListBuffer<>();
   494                 stats.append(make.at(expr).Exec(expr));
   495                 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   496                 return make.Block(0, stats.toList());
   497             } else {
   498                 //non-void to non-void conversion:
   499                 // return (TYPE)BODY;
   500                 JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   501                 return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
   502             }
   503         } finally {
   504             make.at(prevPos);
   505         }
   506     }
   508     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   509         final Type restype = lambdaMethodDecl.type.getReturnType();
   510         final boolean isTarget_void = restype.hasTag(VOID);
   511         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   513         class LambdaBodyTranslator extends TreeTranslator {
   515             @Override
   516             public void visitClassDef(JCClassDecl tree) {
   517                 //do NOT recurse on any inner classes
   518                 result = tree;
   519             }
   521             @Override
   522             public void visitLambda(JCLambda tree) {
   523                 //do NOT recurse on any nested lambdas
   524                 result = tree;
   525             }
   527             @Override
   528             public void visitReturn(JCReturn tree) {
   529                 boolean isLambda_void = tree.expr == null;
   530                 if (isTarget_void && !isLambda_void) {
   531                     //Void to void conversion:
   532                     // { TYPE $loc = RET-EXPR; return; }
   533                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   534                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   535                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   536                 } else if (!isTarget_void || !isLambda_void) {
   537                     //non-void to non-void conversion:
   538                     // return (TYPE)RET-EXPR;
   539                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   540                     result = tree;
   541                 } else {
   542                     result = tree;
   543                 }
   545             }
   546         }
   548         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   549         if (completeNormally && isTarget_Void) {
   550             //there's no return statement and the lambda (possibly inferred)
   551             //return type is java.lang.Void; emit a synthetic return statement
   552             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   553         }
   554         return trans_block;
   555     }
   557     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   558         ListBuffer<JCCase> cases = new ListBuffer<>();
   559         ListBuffer<JCBreak> breaks = new ListBuffer<>();
   560         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   561             JCBreak br = make.Break(null);
   562             breaks.add(br);
   563             List<JCStatement> stmts = entry.getValue().append(br).toList();
   564             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   565         }
   566         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   567         for (JCBreak br : breaks) {
   568             br.target = sw;
   569         }
   570         JCBlock body = make.Block(0L, List.<JCStatement>of(
   571                 sw,
   572                 make.Throw(makeNewClass(
   573                     syms.illegalArgumentExceptionType,
   574                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   575         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   576                         names.deserializeLambda,
   577                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   578                         List.<JCTypeParameter>nil(),
   579                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   580                         List.<JCExpression>nil(),
   581                         body,
   582                         null);
   583         deser.sym = kInfo.deserMethodSym;
   584         deser.type = kInfo.deserMethodSym.type;
   585         //System.err.printf("DESER: '%s'\n", deser);
   586         return deser;
   587     }
   589     /** Make an attributed class instance creation expression.
   590      *  @param ctype    The class type.
   591      *  @param args     The constructor arguments.
   592      *  @param cons     The constructor symbol
   593      */
   594     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
   595         JCNewClass tree = make.NewClass(null,
   596             null, make.QualIdent(ctype.tsym), args, null);
   597         tree.constructor = cons;
   598         tree.type = ctype;
   599         return tree;
   600     }
   602     /** Make an attributed class instance creation expression.
   603      *  @param ctype    The class type.
   604      *  @param args     The constructor arguments.
   605      */
   606     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   607         return makeNewClass(ctype, args,
   608                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
   609      }
   611     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   612             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   613         String functionalInterfaceClass = classSig(targetType);
   614         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   615         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
   616         String implClass = classSig(types.erasure(refSym.owner.type));
   617         String implMethodName = refSym.getQualifiedName().toString();
   618         String implMethodSignature = typeSig(types.erasure(refSym.type));
   620         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   621         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
   622         int i = 0;
   623         for (Type t : indyType.getParameterTypes()) {
   624             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
   625             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
   626             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   627             ++i;
   628         }
   629         JCStatement stmt = make.If(
   630                 deserTest(deserTest(deserTest(deserTest(deserTest(
   631                     kindTest,
   632                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   633                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   634                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   635                     "getImplClass", implClass),
   636                     "getImplMethodSignature", implMethodSignature),
   637                 make.Return(makeIndyCall(
   638                     pos,
   639                     syms.lambdaMetafactory,
   640                     names.altMetafactory,
   641                     staticArgs, indyType, serArgs.toList(), samSym.name)),
   642                 null);
   643         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   644         if (stmts == null) {
   645             stmts = new ListBuffer<>();
   646             kInfo.deserializeCases.put(implMethodName, stmts);
   647         }
   648         /****
   649         System.err.printf("+++++++++++++++++\n");
   650         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   651         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   652         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   653         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   654         System.err.printf("*implClass: '%s'\n", implClass);
   655         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   656         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   657         ****/
   658         stmts.append(stmt);
   659     }
   661     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   662         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   663         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   664         testExpr.setType(syms.booleanType);
   665         return testExpr;
   666     }
   668     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   669         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   670         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   671         JCMethodInvocation eqtest = make.Apply(
   672                 List.<JCExpression>nil(),
   673                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   674                 List.<JCExpression>of(make.Literal(lit)));
   675         eqtest.setType(syms.booleanType);
   676         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   677         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   678         compound.setType(syms.booleanType);
   679         return compound;
   680     }
   682     private JCExpression deserGetter(String func, Type type) {
   683         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   684     }
   686     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   687         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   688         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   689         return make.Apply(
   690                     List.<JCExpression>nil(),
   691                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   692                     args).setType(type);
   693     }
   695     /**
   696      * Create new synthetic method with given flags, name, type, owner
   697      */
   698     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   699         return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
   700     }
   702     /**
   703      * Create new synthetic variable with given flags, name, type, owner
   704      */
   705     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   706         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   707     }
   709     /**
   710      * Create new synthetic variable with given flags, name, type, owner
   711      */
   712     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   713         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   714     }
   716     /**
   717      * Set varargsElement field on a given tree (must be either a new class tree
   718      * or a method call tree)
   719      */
   720     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   721         if (varargsElement != null) {
   722             switch (tree.getTag()) {
   723                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   724                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   725                 default: throw new AssertionError();
   726             }
   727         }
   728     }
   730     /**
   731      * Convert method/constructor arguments by inserting appropriate cast
   732      * as required by type-erasure - this is needed when bridging a lambda/method
   733      * reference, as the bridged signature might require downcast to be compatible
   734      * with the generated signature.
   735      */
   736     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   737        Assert.check(meth.kind == Kinds.MTH);
   738        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   739        if (varargsElement != null) {
   740            Assert.check((meth.flags() & VARARGS) != 0);
   741        }
   742        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   743     }
   745     // </editor-fold>
   747     /**
   748      * Generate an adapter method "bridge" for a method reference which cannot
   749      * be used directly.
   750      */
   751     private class MemberReferenceBridger {
   753         private final JCMemberReference tree;
   754         private final ReferenceTranslationContext localContext;
   755         private final ListBuffer<JCExpression> args = new ListBuffer<>();
   756         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
   758         MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
   759             this.tree = tree;
   760             this.localContext = localContext;
   761         }
   763         /**
   764          * Generate the bridge
   765          */
   766         JCMethodDecl bridge() {
   767             int prevPos = make.pos;
   768             try {
   769                 make.at(tree);
   770                 Type samDesc = localContext.bridgedRefSig();
   771                 List<Type> samPTypes = samDesc.getParameterTypes();
   773                 //an extra argument is prepended to the signature of the bridge in case
   774                 //the member reference is an instance method reference (in which case
   775                 //the receiver expression is passed to the bridge itself).
   776                 Type recType = null;
   777                 switch (tree.kind) {
   778                     case IMPLICIT_INNER:
   779                         recType = tree.sym.owner.type.getEnclosingType();
   780                         break;
   781                     case BOUND:
   782                         recType = tree.getQualifierExpression().type;
   783                         break;
   784                     case UNBOUND:
   785                         recType = samPTypes.head;
   786                         samPTypes = samPTypes.tail;
   787                         break;
   788                 }
   790                 //generate the parameter list for the bridged member reference - the
   791                 //bridge signature will match the signature of the target sam descriptor
   793                 VarSymbol rcvr = (recType == null)
   794                         ? null
   795                         : addParameter("rec$", recType, false);
   797                 List<Type> refPTypes = tree.sym.type.getParameterTypes();
   798                 int refSize = refPTypes.size();
   799                 int samSize = samPTypes.size();
   800                 // Last parameter to copy from referenced method
   801                 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
   803                 List<Type> l = refPTypes;
   804                 // Use parameter types of the referenced method, excluding final var args
   805                 for (int i = 0; l.nonEmpty() && i < last; ++i) {
   806                     addParameter("x$" + i, l.head, true);
   807                     l = l.tail;
   808                 }
   809                 // Flatten out the var args
   810                 for (int i = last; i < samSize; ++i) {
   811                     addParameter("xva$" + i, tree.varargsElement, true);
   812                 }
   814                 //generate the bridge method declaration
   815                 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
   816                         localContext.bridgeSym.name,
   817                         make.QualIdent(samDesc.getReturnType().tsym),
   818                         List.<JCTypeParameter>nil(),
   819                         params.toList(),
   820                         tree.sym.type.getThrownTypes() == null
   821                         ? List.<JCExpression>nil()
   822                         : make.Types(tree.sym.type.getThrownTypes()),
   823                         null,
   824                         null);
   825                 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
   826                 bridgeDecl.type = localContext.bridgeSym.type =
   827                         types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
   829                 //bridge method body generation - this can be either a method call or a
   830                 //new instance creation expression, depending on the member reference kind
   831                 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
   832                         ? bridgeExpressionInvoke(makeReceiver(rcvr))
   833                         : bridgeExpressionNew();
   835                 //the body is either a return expression containing a method call,
   836                 //or the method call itself, depending on whether the return type of
   837                 //the bridge is non-void/void.
   838                 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
   840                 return bridgeDecl;
   841             } finally {
   842                 make.at(prevPos);
   843             }
   844         }
   845         //where
   846             private JCExpression makeReceiver(VarSymbol rcvr) {
   847                 if (rcvr == null) return null;
   848                 JCExpression rcvrExpr = make.Ident(rcvr);
   849                 Type rcvrType = tree.sym.enclClass().type;
   850                 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   851                     rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   852                 }
   853                 return rcvrExpr;
   854             }
   856         /**
   857          * determine the receiver of the bridged method call - the receiver can
   858          * be either the synthetic receiver parameter or a type qualifier; the
   859          * original qualifier expression is never used here, as it might refer
   860          * to symbols not available in the static context of the bridge
   861          */
   862         private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
   863             JCExpression qualifier =
   864                     tree.sym.isStatic() ?
   865                         make.Type(tree.sym.owner.type) :
   866                         (rcvr != null) ?
   867                             rcvr :
   868                             tree.getQualifierExpression();
   870             //create the qualifier expression
   871             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   872             select.sym = tree.sym;
   873             select.type = tree.sym.erasure(types);
   875             //create the method call expression
   876             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   877                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   878                     setType(tree.sym.erasure(types).getReturnType());
   880             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   881             setVarargsIfNeeded(apply, tree.varargsElement);
   882             return apply;
   883         }
   885         /**
   886          * the enclosing expression is either 'null' (no enclosing type) or set
   887          * to the first bridge synthetic parameter
   888          */
   889         private JCExpression bridgeExpressionNew() {
   890             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   891                 //create the array creation expression
   892                 JCNewArray newArr = make.NewArray(
   893                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   894                         List.of(make.Ident(params.first())),
   895                         null);
   896                 newArr.type = tree.getQualifierExpression().type;
   897                 return newArr;
   898             } else {
   899                 JCExpression encl = null;
   900                 switch (tree.kind) {
   901                     case UNBOUND:
   902                     case IMPLICIT_INNER:
   903                         encl = make.Ident(params.first());
   904                 }
   906                 //create the instance creation expression
   907                 JCNewClass newClass = make.NewClass(encl,
   908                         List.<JCExpression>nil(),
   909                         make.Type(tree.getQualifierExpression().type),
   910                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   911                         null);
   912                 newClass.constructor = tree.sym;
   913                 newClass.constructorType = tree.sym.erasure(types);
   914                 newClass.type = tree.getQualifierExpression().type;
   915                 setVarargsIfNeeded(newClass, tree.varargsElement);
   916                 return newClass;
   917             }
   918         }
   920         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   921             VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
   922             params.append(make.VarDef(vsym, null));
   923             if (genArg) {
   924                 args.append(make.Ident(vsym));
   925             }
   926             return vsym;
   927         }
   928     }
   930     /**
   931      * Bridges a member reference - this is needed when:
   932      * * Var args in the referenced method need to be flattened away
   933      * * super is used
   934      */
   935     private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
   936         kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
   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             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
  1181                     syntheticMethodNameCounts;
  1182             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1183             DiagnosticSource prevSource = log.currentSource();
  1184             try {
  1185                 log.useSource(tree.sym.sourcefile);
  1186                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
  1187                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1188                 if (tree.sym.owner.kind == MTH) {
  1189                     localClassDefs.put(tree.sym, tree);
  1191                 if (directlyEnclosingLambda() != null) {
  1192                     tree.sym.owner = owner();
  1193                     if (tree.sym.hasOuterInstance()) {
  1194                         //if a class is defined within a lambda, the lambda must capture
  1195                         //its enclosing instance (if any)
  1196                         TranslationContext<?> localContext = context();
  1197                         while (localContext != null) {
  1198                             if (localContext.tree.getTag() == LAMBDA) {
  1199                                 ((LambdaTranslationContext)localContext)
  1200                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1202                             localContext = localContext.prev;
  1206                 frameStack = frameStack.prepend(new Frame(tree));
  1207                 super.visitClassDef(tree);
  1209             finally {
  1210                 log.useSource(prevSource.getFile());
  1211                 frameStack = prevStack;
  1212                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
  1213                 clinits = prevClinits;
  1217         @Override
  1218         public void visitIdent(JCIdent tree) {
  1219             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1220                 if (tree.sym.kind == VAR &&
  1221                         tree.sym.owner.kind == MTH &&
  1222                         tree.type.constValue() == null) {
  1223                     TranslationContext<?> localContext = context();
  1224                     while (localContext != null) {
  1225                         if (localContext.tree.getTag() == LAMBDA) {
  1226                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1227                             if (block == null) break;
  1228                             ((LambdaTranslationContext)localContext)
  1229                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1231                         localContext = localContext.prev;
  1233                 } else if (tree.sym.owner.kind == TYP) {
  1234                     TranslationContext<?> localContext = context();
  1235                     while (localContext != null) {
  1236                         if (localContext.tree.hasTag(LAMBDA)) {
  1237                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1238                             if (block == null) break;
  1239                             switch (block.getTag()) {
  1240                                 case CLASSDEF:
  1241                                     JCClassDecl cdecl = (JCClassDecl)block;
  1242                                     ((LambdaTranslationContext)localContext)
  1243                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1244                                     break;
  1245                                 default:
  1246                                     Assert.error("bad block kind");
  1249                         localContext = localContext.prev;
  1253             super.visitIdent(tree);
  1256         @Override
  1257         public void visitLambda(JCLambda tree) {
  1258             List<Frame> prevStack = frameStack;
  1259             try {
  1260                 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
  1261                 frameStack = frameStack.prepend(new Frame(tree));
  1262                 for (JCVariableDecl param : tree.params) {
  1263                     context.addSymbol(param.sym, PARAM);
  1264                     frameStack.head.addLocal(param.sym);
  1266                 contextMap.put(tree, context);
  1267                 super.visitLambda(tree);
  1268                 context.complete();
  1270             finally {
  1271                 frameStack = prevStack;
  1275         @Override
  1276         public void visitMethodDef(JCMethodDecl tree) {
  1277             List<Frame> prevStack = frameStack;
  1278             try {
  1279                 frameStack = frameStack.prepend(new Frame(tree));
  1280                 super.visitMethodDef(tree);
  1282             finally {
  1283                 frameStack = prevStack;
  1287         @Override
  1288         public void visitNewClass(JCNewClass tree) {
  1289             if (lambdaNewClassFilter(context(), tree)) {
  1290                 TranslationContext<?> localContext = context();
  1291                 while (localContext != null) {
  1292                     if (localContext.tree.getTag() == LAMBDA) {
  1293                         ((LambdaTranslationContext)localContext)
  1294                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1296                     localContext = localContext.prev;
  1299             if (context() != null && tree.type.tsym.owner.kind == MTH) {
  1300                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1301                 captureLocalClassDefs(tree.type.tsym, lambdaContext);
  1303             super.visitNewClass(tree);
  1305         //where
  1306             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1307                 JCClassDecl localCDef = localClassDefs.get(csym);
  1308                 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
  1309                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1310                         @Override
  1311                         void addFreeVars(ClassSymbol c) {
  1312                             captureLocalClassDefs(c, lambdaContext);
  1314                         @Override
  1315                         void visitSymbol(Symbol sym) {
  1316                             if (sym.kind == VAR &&
  1317                                     sym.owner.kind == MTH &&
  1318                                     ((VarSymbol)sym).getConstValue() == null) {
  1319                                 TranslationContext<?> localContext = context();
  1320                                 while (localContext != null) {
  1321                                     if (localContext.tree.getTag() == LAMBDA) {
  1322                                         JCTree block = capturedDecl(localContext.depth, sym);
  1323                                         if (block == null) break;
  1324                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1326                                     localContext = localContext.prev;
  1330                     };
  1331                     fvc.scan(localCDef);
  1335         /**
  1336          * Method references to local class constructors, may, if the local
  1337          * class references local variables, have implicit constructor
  1338          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1339          * information added in the LambdaToMethod pass will have the wrong
  1340          * signature. Hooks between Lower and LambdaToMethod have been added to
  1341          * handle normal "new" in this case. This visitor converts potentially
  1342          * effected method references into a lambda containing a normal "new" of
  1343          * the class.
  1345          * @param tree
  1346          */
  1347         @Override
  1348         public void visitReference(JCMemberReference tree) {
  1349             if (tree.getMode() == ReferenceMode.NEW
  1350                     && tree.kind != ReferenceKind.ARRAY_CTOR
  1351                     && tree.sym.owner.isLocal()) {
  1352                 MethodSymbol consSym = (MethodSymbol) tree.sym;
  1353                 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
  1354                 Type classType = consSym.owner.type;
  1356                 // Build lambda parameters
  1357                 // partially cloned from TreeMaker.Params until 8014021 is fixed
  1358                 Symbol owner = owner();
  1359                 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
  1360                 int i = 0;
  1361                 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
  1362                     JCVariableDecl param = make.Param(make.paramName(i++), l.head, owner);
  1363                     param.sym.pos = tree.pos;
  1364                     paramBuff.append(param);
  1366                 List<JCVariableDecl> params = paramBuff.toList();
  1368                 // Make new-class call
  1369                 JCNewClass nc = makeNewClass(classType, make.Idents(params));
  1370                 nc.pos = tree.pos;
  1372                 // Make lambda holding the new-class call
  1373                 JCLambda slam = make.Lambda(params, nc);
  1374                 slam.targets = tree.targets;
  1375                 slam.type = tree.type;
  1376                 slam.pos = tree.pos;
  1378                 // Now it is a lambda, process as such
  1379                 visitLambda(slam);
  1380             } else {
  1381                 super.visitReference(tree);
  1382                 contextMap.put(tree, makeReferenceContext(tree));
  1386         @Override
  1387         public void visitSelect(JCFieldAccess tree) {
  1388             if (context() != null && tree.sym.kind == VAR &&
  1389                         (tree.sym.name == names._this ||
  1390                          tree.sym.name == names._super)) {
  1391                 // A select of this or super means, if we are in a lambda,
  1392                 // we much have an instance context
  1393                 TranslationContext<?> localContext = context();
  1394                 while (localContext != null) {
  1395                     if (localContext.tree.hasTag(LAMBDA)) {
  1396                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1397                         if (clazz == null) break;
  1398                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1400                     localContext = localContext.prev;
  1403             super.visitSelect(tree);
  1406         @Override
  1407         public void visitVarDef(JCVariableDecl tree) {
  1408             TranslationContext<?> context = context();
  1409             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1410                     (LambdaTranslationContext)context :
  1411                     null;
  1412             if (ltc != null) {
  1413                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1414                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1416                 // Check for type variables (including as type arguments).
  1417                 // If they occur within class nested in a lambda, mark for erasure
  1418                 Type type = tree.sym.asType();
  1419                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1420                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1424             List<Frame> prevStack = frameStack;
  1425             try {
  1426                 if (tree.sym.owner.kind == MTH) {
  1427                     frameStack.head.addLocal(tree.sym);
  1429                 frameStack = frameStack.prepend(new Frame(tree));
  1430                 super.visitVarDef(tree);
  1432             finally {
  1433                 frameStack = prevStack;
  1437         /**
  1438          * Return a valid owner given the current declaration stack
  1439          * (required to skip synthetic lambda symbols)
  1440          */
  1441         private Symbol owner() {
  1442             return owner(false);
  1445         @SuppressWarnings("fallthrough")
  1446         private Symbol owner(boolean skipLambda) {
  1447             List<Frame> frameStack2 = frameStack;
  1448             while (frameStack2.nonEmpty()) {
  1449                 switch (frameStack2.head.tree.getTag()) {
  1450                     case VARDEF:
  1451                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1452                             frameStack2 = frameStack2.tail;
  1453                             break;
  1455                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1456                         return initSym(cdecl.sym,
  1457                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1458                     case BLOCK:
  1459                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1460                         return initSym(cdecl2.sym,
  1461                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1462                     case CLASSDEF:
  1463                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1464                     case METHODDEF:
  1465                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1466                     case LAMBDA:
  1467                         if (!skipLambda)
  1468                             return ((LambdaTranslationContext)contextMap
  1469                                     .get(frameStack2.head.tree)).translatedSym;
  1470                     default:
  1471                         frameStack2 = frameStack2.tail;
  1474             Assert.error();
  1475             return null;
  1478         private Symbol initSym(ClassSymbol csym, long flags) {
  1479             boolean isStatic = (flags & STATIC) != 0;
  1480             if (isStatic) {
  1481                 /* static clinits are generated in Gen, so we need to use a fake
  1482                  * one. Attr creates a fake clinit method while attributing
  1483                  * lambda expressions used as initializers of static fields, so
  1484                  * let's use that one.
  1485                  */
  1486                 MethodSymbol clinit = attr.removeClinit(csym);
  1487                 if (clinit != null) {
  1488                     clinits.put(csym, clinit);
  1489                     return clinit;
  1492                 /* if no clinit is found at Attr, then let's try at clinits.
  1493                  */
  1494                 clinit = (MethodSymbol)clinits.get(csym);
  1495                 if (clinit == null) {
  1496                     /* no luck, let's create a new one
  1497                      */
  1498                     clinit = makePrivateSyntheticMethod(STATIC,
  1499                             names.clinit,
  1500                             new MethodType(List.<Type>nil(), syms.voidType,
  1501                                 List.<Type>nil(), syms.methodClass),
  1502                             csym);
  1503                     clinits.put(csym, clinit);
  1505                 return clinit;
  1506             } else {
  1507                 //get the first constructor and treat it as the instance init sym
  1508                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1509                     return s;
  1512             Assert.error("init not found");
  1513             return null;
  1516         private JCTree directlyEnclosingLambda() {
  1517             if (frameStack.isEmpty()) {
  1518                 return null;
  1520             List<Frame> frameStack2 = frameStack;
  1521             while (frameStack2.nonEmpty()) {
  1522                 switch (frameStack2.head.tree.getTag()) {
  1523                     case CLASSDEF:
  1524                     case METHODDEF:
  1525                         return null;
  1526                     case LAMBDA:
  1527                         return frameStack2.head.tree;
  1528                     default:
  1529                         frameStack2 = frameStack2.tail;
  1532             Assert.error();
  1533             return null;
  1536         private boolean inClassWithinLambda() {
  1537             if (frameStack.isEmpty()) {
  1538                 return false;
  1540             List<Frame> frameStack2 = frameStack;
  1541             boolean classFound = false;
  1542             while (frameStack2.nonEmpty()) {
  1543                 switch (frameStack2.head.tree.getTag()) {
  1544                     case LAMBDA:
  1545                         return classFound;
  1546                     case CLASSDEF:
  1547                         classFound = true;
  1548                         frameStack2 = frameStack2.tail;
  1549                         break;
  1550                     default:
  1551                         frameStack2 = frameStack2.tail;
  1554             // No lambda
  1555             return false;
  1558         /**
  1559          * Return the declaration corresponding to a symbol in the enclosing
  1560          * scope; the depth parameter is used to filter out symbols defined
  1561          * in nested scopes (which do not need to undergo capture).
  1562          */
  1563         private JCTree capturedDecl(int depth, Symbol sym) {
  1564             int currentDepth = frameStack.size() - 1;
  1565             for (Frame block : frameStack) {
  1566                 switch (block.tree.getTag()) {
  1567                     case CLASSDEF:
  1568                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1569                         if (sym.isMemberOf(clazz, types)) {
  1570                             return currentDepth > depth ? null : block.tree;
  1572                         break;
  1573                     case VARDEF:
  1574                         if (((JCVariableDecl)block.tree).sym == sym &&
  1575                                 sym.owner.kind == MTH) { //only locals are captured
  1576                             return currentDepth > depth ? null : block.tree;
  1578                         break;
  1579                     case BLOCK:
  1580                     case METHODDEF:
  1581                     case LAMBDA:
  1582                         if (block.locals != null && block.locals.contains(sym)) {
  1583                             return currentDepth > depth ? null : block.tree;
  1585                         break;
  1586                     default:
  1587                         Assert.error("bad decl kind " + block.tree.getTag());
  1589                 currentDepth--;
  1591             return null;
  1594         private TranslationContext<?> context() {
  1595             for (Frame frame : frameStack) {
  1596                 TranslationContext<?> context = contextMap.get(frame.tree);
  1597                 if (context != null) {
  1598                     return context;
  1601             return null;
  1604         /**
  1605          *  This is used to filter out those identifiers that needs to be adjusted
  1606          *  when translating away lambda expressions
  1607          */
  1608         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1609             return (sym.kind == VAR || sym.kind == MTH)
  1610                     && !sym.isStatic()
  1611                     && sym.name != names.init;
  1614         /**
  1615          * This is used to filter out those new class expressions that need to
  1616          * be qualified with an enclosing tree
  1617          */
  1618         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1619             if (context != null
  1620                     && tree.encl == null
  1621                     && tree.def == null
  1622                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1623                 Type encl = tree.type.getEnclosingType();
  1624                 Type current = context.owner.enclClass().type;
  1625                 while (!current.hasTag(NONE)) {
  1626                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1627                         return true;
  1629                     current = current.getEnclosingType();
  1631                 return false;
  1632             } else {
  1633                 return false;
  1637         private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
  1638             return new LambdaTranslationContext(tree);
  1641         private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
  1642             return new ReferenceTranslationContext(tree);
  1645         private class Frame {
  1646             final JCTree tree;
  1647             List<Symbol> locals;
  1649             public Frame(JCTree tree) {
  1650                 this.tree = tree;
  1653             void addLocal(Symbol sym) {
  1654                 if (locals == null) {
  1655                     locals = List.nil();
  1657                 locals = locals.prepend(sym);
  1661         /**
  1662          * This class is used to store important information regarding translation of
  1663          * lambda expression/method references (see subclasses).
  1664          */
  1665         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1667             /** the underlying (untranslated) tree */
  1668             final T tree;
  1670             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1671             final Symbol owner;
  1673             /** the depth of this lambda expression in the frame stack */
  1674             final int depth;
  1676             /** the enclosing translation context (set for nested lambdas/mref) */
  1677             final TranslationContext<?> prev;
  1679             /** list of methods to be bridged by the meta-factory */
  1680             final List<Symbol> bridges;
  1682             TranslationContext(T tree) {
  1683                 this.tree = tree;
  1684                 this.owner = owner();
  1685                 this.depth = frameStack.size() - 1;
  1686                 this.prev = context();
  1687                 ClassSymbol csym =
  1688                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1689                 this.bridges = types.functionalInterfaceBridges(csym);
  1692             /** does this functional expression need to be created using alternate metafactory? */
  1693             boolean needsAltMetafactory() {
  1694                 return tree.targets.length() > 1 ||
  1695                         isSerializable() ||
  1696                         bridges.length() > 1;
  1699             /** does this functional expression require serialization support? */
  1700             boolean isSerializable() {
  1701                 if (forceSerializable) {
  1702                     return true;
  1704                 for (Type target : tree.targets) {
  1705                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1706                         return true;
  1709                 return false;
  1712             /**
  1713              * @return Name of the enclosing method to be folded into synthetic
  1714              * method name
  1715              */
  1716             String enclosingMethodName() {
  1717                 return syntheticMethodNameComponent(owner.name);
  1720             /**
  1721              * @return Method name in a form that can be folded into a
  1722              * component of a synthetic method name
  1723              */
  1724             String syntheticMethodNameComponent(Name name) {
  1725                 if (name == null) {
  1726                     return "null";
  1728                 String methodName = name.toString();
  1729                 if (methodName.equals("<clinit>")) {
  1730                     methodName = "static";
  1731                 } else if (methodName.equals("<init>")) {
  1732                     methodName = "new";
  1734                 return methodName;
  1738         /**
  1739          * This class retains all the useful information about a lambda expression;
  1740          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1741          * and the used by the main translation routines in order to adjust references
  1742          * to captured locals/members, etc.
  1743          */
  1744         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1746             /** variable in the enclosing context to which this lambda is assigned */
  1747             final Symbol self;
  1749             /** variable in the enclosing context to which this lambda is assigned */
  1750             final Symbol assignedTo;
  1752             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
  1754             /** the synthetic symbol for the method hoisting the translated lambda */
  1755             Symbol translatedSym;
  1757             List<JCVariableDecl> syntheticParams;
  1759             LambdaTranslationContext(JCLambda tree) {
  1760                 super(tree);
  1761                 Frame frame = frameStack.head;
  1762                 switch (frame.tree.getTag()) {
  1763                     case VARDEF:
  1764                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
  1765                         break;
  1766                     case ASSIGN:
  1767                         self = null;
  1768                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
  1769                         break;
  1770                     default:
  1771                         assignedTo = self = null;
  1772                         break;
  1775                 // This symbol will be filled-in in complete
  1776                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
  1778                 if (dumpLambdaToMethodStats) {
  1779                     log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym);
  1781                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
  1783                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
  1784                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
  1785                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
  1786                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
  1787                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
  1790              /**
  1791              * For a serializable lambda, generate a disambiguating string
  1792              * which maximizes stability across deserialization.
  1794              * @return String to differentiate synthetic lambda method names
  1795              */
  1796             private String serializedLambdaDisambiguation() {
  1797                 StringBuilder buf = new StringBuilder();
  1798                 // Append the enclosing method signature to differentiate
  1799                 // overloaded enclosing methods.  For lambdas enclosed in
  1800                 // lambdas, the generated lambda method will not have type yet,
  1801                 // but the enclosing method's name will have been generated
  1802                 // with this same method, so it will be unique and never be
  1803                 // overloaded.
  1804                 Assert.check(
  1805                         owner.type != null ||
  1806                         directlyEnclosingLambda() != null);
  1807                 if (owner.type != null) {
  1808                     buf.append(typeSig(owner.type));
  1809                     buf.append(":");
  1812                 // Add target type info
  1813                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
  1814                 buf.append(" ");
  1816                 // Add variable assigned to
  1817                 if (assignedTo != null) {
  1818                     buf.append(assignedTo.flatName());
  1819                     buf.append("=");
  1821                 //add captured locals info: type, name, order
  1822                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
  1823                     if (fv != self) {
  1824                         buf.append(typeSig(fv.type));
  1825                         buf.append(" ");
  1826                         buf.append(fv.flatName());
  1827                         buf.append(",");
  1831                 return buf.toString();
  1834             /**
  1835              * For a non-serializable lambda, generate a simple method.
  1837              * @return Name to use for the synthetic lambda method name
  1838              */
  1839             private Name lambdaName() {
  1840                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
  1843             /**
  1844              * For a serializable lambda, generate a method name which maximizes
  1845              * name stability across deserialization.
  1847              * @return Name to use for the synthetic lambda method name
  1848              */
  1849             private Name serializedLambdaName() {
  1850                 StringBuilder buf = new StringBuilder();
  1851                 buf.append(names.lambda);
  1852                 // Append the name of the method enclosing the lambda.
  1853                 buf.append(enclosingMethodName());
  1854                 buf.append('$');
  1855                 // Append a hash of the disambiguating string : enclosing method
  1856                 // signature, etc.
  1857                 String disam = serializedLambdaDisambiguation();
  1858                 buf.append(Integer.toHexString(disam.hashCode()));
  1859                 buf.append('$');
  1860                 // The above appended name components may not be unique, append
  1861                 // a count based on the above name components.
  1862                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  1863                 String result = buf.toString();
  1864                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
  1865                 return names.fromString(result);
  1868             /**
  1869              * Translate a symbol of a given kind into something suitable for the
  1870              * synthetic lambda body
  1871              */
  1872             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1873                 Symbol ret;
  1874                 switch (skind) {
  1875                     case CAPTURED_THIS:
  1876                         ret = sym;  // self represented
  1877                         break;
  1878                     case TYPE_VAR:
  1879                         // Just erase the type var
  1880                         ret = new VarSymbol(sym.flags(), name,
  1881                                 types.erasure(sym.type), sym.owner);
  1883                         /* this information should also be kept for LVT generation at Gen
  1884                          * a Symbol with pos < startPos won't be tracked.
  1885                          */
  1886                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
  1887                         break;
  1888                     case CAPTURED_VAR:
  1889                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
  1890                             @Override
  1891                             public Symbol baseSymbol() {
  1892                                 //keep mapping with original captured symbol
  1893                                 return sym;
  1895                         };
  1896                         break;
  1897                     case LOCAL_VAR:
  1898                         ret = new VarSymbol(sym.flags() & FINAL, name, types.erasure(sym.type), translatedSym);
  1899                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1900                         break;
  1901                     case PARAM:
  1902                         ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, name, types.erasure(sym.type), translatedSym);
  1903                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1904                         break;
  1905                     default:
  1906                         ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1907                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1909                 if (ret != sym) {
  1910                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1911                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1913                 return ret;
  1916             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1917                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
  1918                 Name preferredName;
  1919                 switch (skind) {
  1920                     case CAPTURED_THIS:
  1921                         preferredName = names.fromString("encl$" + transMap.size());
  1922                         break;
  1923                     case CAPTURED_VAR:
  1924                         preferredName = names.fromString("cap$" + transMap.size());
  1925                         break;
  1926                     case LOCAL_VAR:
  1927                         preferredName = sym.name;
  1928                         break;
  1929                     case PARAM:
  1930                         preferredName = sym.name;
  1931                         break;
  1932                     case TYPE_VAR:
  1933                         preferredName = sym.name;
  1934                         break;
  1935                     default: throw new AssertionError();
  1937                 if (!transMap.containsKey(sym)) {
  1938                     transMap.put(sym, translate(preferredName, sym, skind));
  1942             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
  1943                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
  1944                 Assert.checkNonNull(m);
  1945                 return m;
  1948             JCTree translate(JCIdent lambdaIdent) {
  1949                 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
  1950                     if (m.containsKey(lambdaIdent.sym)) {
  1951                         Symbol tSym = m.get(lambdaIdent.sym);
  1952                         JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
  1953                         tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
  1954                         return t;
  1957                 return null;
  1960             /**
  1961              * The translatedSym is not complete/accurate until the analysis is
  1962              * finished.  Once the analysis is finished, the translatedSym is
  1963              * "completed" -- updated with type information, access modifiers,
  1964              * and full parameter list.
  1965              */
  1966             void complete() {
  1967                 if (syntheticParams != null) {
  1968                     return;
  1970                 boolean inInterface = translatedSym.owner.isInterface();
  1971                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1973                 // If instance access isn't needed, make it static.
  1974                 // Interface instance methods must be default methods.
  1975                 // Lambda methods are private synthetic.
  1976                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
  1977                         PRIVATE |
  1978                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  1980                 //compute synthetic params
  1981                 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
  1983                 // The signature of the method is augmented with the following
  1984                 // synthetic parameters:
  1985                 //
  1986                 // 1) reference to enclosing contexts captured by the lambda expression
  1987                 // 2) enclosing locals captured by the lambda expression
  1988                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
  1989                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1991                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
  1992                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1994                 syntheticParams = params.toList();
  1996                 // Compute and set the lambda name
  1997                 translatedSym.name = isSerializable()
  1998                         ? serializedLambdaName()
  1999                         : lambdaName();
  2001                 //prepend synthetic args to translated lambda method signature
  2002                 translatedSym.type = types.createMethodTypeWithParameters(
  2003                         generatedLambdaSig(),
  2004                         TreeInfo.types(syntheticParams));
  2007             Type generatedLambdaSig() {
  2008                 return types.erasure(tree.getDescriptorType(types));
  2012         /**
  2013          * This class retains all the useful information about a method reference;
  2014          * the contents of this class are filled by the LambdaAnalyzer visitor,
  2015          * and the used by the main translation routines in order to adjust method
  2016          * references (i.e. in case a bridge is needed)
  2017          */
  2018         private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  2020             final boolean isSuper;
  2021             final Symbol bridgeSym;
  2022             final Symbol sigPolySym;
  2024             ReferenceTranslationContext(JCMemberReference tree) {
  2025                 super(tree);
  2026                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2027                 this.bridgeSym = needsBridge()
  2028                         ? makePrivateSyntheticMethod(isSuper ? 0 : STATIC,
  2029                                               referenceBridgeName(), null,
  2030                                               owner.enclClass())
  2031                         : null;
  2032                 this.sigPolySym = isSignaturePolymorphic()
  2033                         ? makePrivateSyntheticMethod(tree.sym.flags(),
  2034                                               tree.sym.name,
  2035                                               bridgedRefSig(),
  2036                                               tree.sym.enclClass())
  2037                         : null;
  2038                 if (dumpLambdaToMethodStats) {
  2039                     String key = bridgeSym == null ?
  2040                             "mref.stat" : "mref.stat.1";
  2041                     log.note(tree, key, needsAltMetafactory(), bridgeSym);
  2045             /**
  2046              * Get the opcode associated with this method reference
  2047              */
  2048             int referenceKind() {
  2049                 return LambdaToMethod.this.referenceKind(needsBridge()
  2050                         ? bridgeSym
  2051                         : tree.sym);
  2054             boolean needsVarArgsConversion() {
  2055                 return tree.varargsElement != null;
  2058             /**
  2059              * Generate a disambiguating string to increase stability (important
  2060              * if serialized)
  2062              * @return String to differentiate synthetic lambda method names
  2063              */
  2064             private String referenceBridgeDisambiguation() {
  2065                 StringBuilder buf = new StringBuilder();
  2066                 // Append the enclosing method signature to differentiate
  2067                 // overloaded enclosing methods.
  2068                 if (owner.type != null) {
  2069                     buf.append(typeSig(owner.type));
  2070                     buf.append(":");
  2073                 // Append qualifier type
  2074                 buf.append(classSig(tree.sym.owner.type));
  2076                 // Note static/instance
  2077                 buf.append(tree.sym.isStatic()? " S " : " I ");
  2079                 // Append referenced signature
  2080                 buf.append(typeSig(tree.sym.erasure(types)));
  2082                 return buf.toString();
  2085             /**
  2086              * Construct a unique stable name for the method reference bridge
  2088              * @return Name to use for the synthetic method name
  2089              */
  2090             private Name referenceBridgeName() {
  2091                 StringBuilder buf = new StringBuilder();
  2092                 // Append lambda ID, this is semantically significant
  2093                 buf.append(names.lambda);
  2094                 // Note that it is a method reference bridge
  2095                 buf.append("MR$");
  2096                 // Append the enclosing method name
  2097                 buf.append(enclosingMethodName());
  2098                 buf.append('$');
  2099                 // Append the referenced method name
  2100                 buf.append(syntheticMethodNameComponent(tree.sym.name));
  2101                 buf.append('$');
  2102                 // Append a hash of the disambiguating string : enclosing method
  2103                 // signature, etc.
  2104                 String disam = referenceBridgeDisambiguation();
  2105                 buf.append(Integer.toHexString(disam.hashCode()));
  2106                 buf.append('$');
  2107                 // The above appended name components may not be unique, append
  2108                 // a count based on the above name components.
  2109                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  2110                 String result = buf.toString();
  2111                 return names.fromString(result);
  2114             /**
  2115              * @return Is this an array operation like clone()
  2116              */
  2117             boolean isArrayOp() {
  2118                 return tree.sym.owner == syms.arrayClass;
  2121             boolean receiverAccessible() {
  2122                 //hack needed to workaround 292 bug (7087658)
  2123                 //when 292 issue is fixed we should remove this and change the backend
  2124                 //code to always generate a method handle to an accessible method
  2125                 return tree.ownerAccessible;
  2128             /**
  2129              * The VM does not support access across nested classes (8010319).
  2130              * Were that ever to change, this should be removed.
  2131              */
  2132             boolean isPrivateInOtherClass() {
  2133                 return  (tree.sym.flags() & PRIVATE) != 0 &&
  2134                         !types.isSameType(
  2135                               types.erasure(tree.sym.enclClass().asType()),
  2136                               types.erasure(owner.enclClass().asType()));
  2139             /**
  2140              * Signature polymorphic methods need special handling.
  2141              * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
  2142              */
  2143             final boolean isSignaturePolymorphic() {
  2144                 return  tree.sym.kind == MTH &&
  2145                         types.isSignaturePolymorphic((MethodSymbol)tree.sym);
  2148             /**
  2149              * Does this reference needs a bridge (i.e. var args need to be
  2150              * expanded or "super" is used)
  2151              */
  2152             final boolean needsBridge() {
  2153                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  2154                         isPrivateInOtherClass() ||
  2155                         !receiverAccessible();
  2158             Type generatedRefSig() {
  2159                 return types.erasure(tree.sym.type);
  2162             Type bridgedRefSig() {
  2163                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  2167     // </editor-fold>
  2169     /*
  2170      * These keys provide mappings for various translated lambda symbols
  2171      * and the prevailing order must be maintained.
  2172      */
  2173     enum LambdaSymbolKind {
  2174         PARAM,          // original to translated lambda parameters
  2175         LOCAL_VAR,      // original to translated lambda locals
  2176         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
  2177         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
  2178         TYPE_VAR;       // original to translated lambda type variables
  2181     /**
  2182      * ****************************************************************
  2183      * Signature Generation
  2184      * ****************************************************************
  2185      */
  2187     private String typeSig(Type type) {
  2188         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2189         sg.assembleSig(type);
  2190         return sg.toString();
  2193     private String classSig(Type type) {
  2194         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2195         sg.assembleClassSig(type);
  2196         return sg.toString();
  2199     /**
  2200      * Signature Generation
  2201      */
  2202     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  2204         /**
  2205          * An output buffer for type signatures.
  2206          */
  2207         StringBuilder sb = new StringBuilder();
  2209         L2MSignatureGenerator() {
  2210             super(types);
  2213         @Override
  2214         protected void append(char ch) {
  2215             sb.append(ch);
  2218         @Override
  2219         protected void append(byte[] ba) {
  2220             sb.append(new String(ba));
  2223         @Override
  2224         protected void append(Name name) {
  2225             sb.append(name.toString());
  2228         @Override
  2229         public String toString() {
  2230             return sb.toString();

mercurial