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

Thu, 01 May 2014 11:35:02 -0700

author
rfield
date
Thu, 01 May 2014 11:35:02 -0700
changeset 2380
b17805de5edf
parent 2358
6a6a8a9860a4
child 2381
d02e9b7444fe
permissions
-rw-r--r--

8036942: javac generates incorrect exception table for multi-catch statements inside a lambda
Summary: Union type info lost and also union type is not processed by TreeMaker.Type -- address by using existing tree, thus by-passing such issues.
Reviewed-by: vromero, jlahoda

     1 /*
     2  * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 package com.sun.tools.javac.comp;
    27 import com.sun.tools.javac.tree.*;
    28 import com.sun.tools.javac.tree.JCTree.*;
    29 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
    30 import com.sun.tools.javac.tree.TreeMaker;
    31 import com.sun.tools.javac.tree.TreeTranslator;
    32 import com.sun.tools.javac.code.Attribute;
    33 import com.sun.tools.javac.code.Kinds;
    34 import com.sun.tools.javac.code.Scope;
    35 import com.sun.tools.javac.code.Symbol;
    36 import com.sun.tools.javac.code.Symbol.ClassSymbol;
    37 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
    38 import com.sun.tools.javac.code.Symbol.MethodSymbol;
    39 import com.sun.tools.javac.code.Symbol.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             tree.init = translate(tree.init);
   442             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
   443             result = tree;
   444         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   445             JCExpression init = translate(tree.init);
   446             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   447             int prevPos = make.pos;
   448             try {
   449                 result = make.at(tree).VarDef(xsym, init);
   450             } finally {
   451                 make.at(prevPos);
   452             }
   453             // Replace the entered symbol for this variable
   454             Scope sc = tree.sym.owner.members();
   455             if (sc != null) {
   456                 sc.remove(tree.sym);
   457                 sc.enter(xsym);
   458             }
   459         } else {
   460             super.visitVarDef(tree);
   461         }
   462     }
   464     // </editor-fold>
   466     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   468     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   469         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   470                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   471                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   472     }
   474     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   475         Type restype = lambdaMethodDecl.type.getReturnType();
   476         boolean isLambda_void = expr.type.hasTag(VOID);
   477         boolean isTarget_void = restype.hasTag(VOID);
   478         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   479         int prevPos = make.pos;
   480         try {
   481             if (isTarget_void) {
   482                 //target is void:
   483                 // BODY;
   484                 JCStatement stat = make.at(expr).Exec(expr);
   485                 return make.Block(0, List.<JCStatement>of(stat));
   486             } else if (isLambda_void && isTarget_Void) {
   487                 //void to Void conversion:
   488                 // BODY; return null;
   489                 ListBuffer<JCStatement> stats = new ListBuffer<>();
   490                 stats.append(make.at(expr).Exec(expr));
   491                 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   492                 return make.Block(0, stats.toList());
   493             } else {
   494                 //non-void to non-void conversion:
   495                 // return (TYPE)BODY;
   496                 JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   497                 return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
   498             }
   499         } finally {
   500             make.at(prevPos);
   501         }
   502     }
   504     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   505         final Type restype = lambdaMethodDecl.type.getReturnType();
   506         final boolean isTarget_void = restype.hasTag(VOID);
   507         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   509         class LambdaBodyTranslator extends TreeTranslator {
   511             @Override
   512             public void visitClassDef(JCClassDecl tree) {
   513                 //do NOT recurse on any inner classes
   514                 result = tree;
   515             }
   517             @Override
   518             public void visitLambda(JCLambda tree) {
   519                 //do NOT recurse on any nested lambdas
   520                 result = tree;
   521             }
   523             @Override
   524             public void visitReturn(JCReturn tree) {
   525                 boolean isLambda_void = tree.expr == null;
   526                 if (isTarget_void && !isLambda_void) {
   527                     //Void to void conversion:
   528                     // { TYPE $loc = RET-EXPR; return; }
   529                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   530                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   531                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   532                 } else if (!isTarget_void || !isLambda_void) {
   533                     //non-void to non-void conversion:
   534                     // return (TYPE)RET-EXPR;
   535                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   536                     result = tree;
   537                 } else {
   538                     result = tree;
   539                 }
   541             }
   542         }
   544         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   545         if (completeNormally && isTarget_Void) {
   546             //there's no return statement and the lambda (possibly inferred)
   547             //return type is java.lang.Void; emit a synthetic return statement
   548             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   549         }
   550         return trans_block;
   551     }
   553     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   554         ListBuffer<JCCase> cases = new ListBuffer<>();
   555         ListBuffer<JCBreak> breaks = new ListBuffer<>();
   556         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   557             JCBreak br = make.Break(null);
   558             breaks.add(br);
   559             List<JCStatement> stmts = entry.getValue().append(br).toList();
   560             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   561         }
   562         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   563         for (JCBreak br : breaks) {
   564             br.target = sw;
   565         }
   566         JCBlock body = make.Block(0L, List.<JCStatement>of(
   567                 sw,
   568                 make.Throw(makeNewClass(
   569                     syms.illegalArgumentExceptionType,
   570                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   571         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   572                         names.deserializeLambda,
   573                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   574                         List.<JCTypeParameter>nil(),
   575                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   576                         List.<JCExpression>nil(),
   577                         body,
   578                         null);
   579         deser.sym = kInfo.deserMethodSym;
   580         deser.type = kInfo.deserMethodSym.type;
   581         //System.err.printf("DESER: '%s'\n", deser);
   582         return deser;
   583     }
   585     /** Make an attributed class instance creation expression.
   586      *  @param ctype    The class type.
   587      *  @param args     The constructor arguments.
   588      *  @param cons     The constructor symbol
   589      */
   590     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
   591         JCNewClass tree = make.NewClass(null,
   592             null, make.QualIdent(ctype.tsym), args, null);
   593         tree.constructor = cons;
   594         tree.type = ctype;
   595         return tree;
   596     }
   598     /** Make an attributed class instance creation expression.
   599      *  @param ctype    The class type.
   600      *  @param args     The constructor arguments.
   601      */
   602     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   603         return makeNewClass(ctype, args,
   604                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
   605      }
   607     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   608             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   609         String functionalInterfaceClass = classSig(targetType);
   610         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   611         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
   612         String implClass = classSig(types.erasure(refSym.owner.type));
   613         String implMethodName = refSym.getQualifiedName().toString();
   614         String implMethodSignature = typeSig(types.erasure(refSym.type));
   616         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   617         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
   618         int i = 0;
   619         for (Type t : indyType.getParameterTypes()) {
   620             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
   621             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
   622             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   623             ++i;
   624         }
   625         JCStatement stmt = make.If(
   626                 deserTest(deserTest(deserTest(deserTest(deserTest(
   627                     kindTest,
   628                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   629                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   630                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   631                     "getImplClass", implClass),
   632                     "getImplMethodSignature", implMethodSignature),
   633                 make.Return(makeIndyCall(
   634                     pos,
   635                     syms.lambdaMetafactory,
   636                     names.altMetafactory,
   637                     staticArgs, indyType, serArgs.toList(), samSym.name)),
   638                 null);
   639         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   640         if (stmts == null) {
   641             stmts = new ListBuffer<>();
   642             kInfo.deserializeCases.put(implMethodName, stmts);
   643         }
   644         /****
   645         System.err.printf("+++++++++++++++++\n");
   646         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   647         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   648         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   649         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   650         System.err.printf("*implClass: '%s'\n", implClass);
   651         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   652         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   653         ****/
   654         stmts.append(stmt);
   655     }
   657     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   658         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   659         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   660         testExpr.setType(syms.booleanType);
   661         return testExpr;
   662     }
   664     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   665         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   666         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   667         JCMethodInvocation eqtest = make.Apply(
   668                 List.<JCExpression>nil(),
   669                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   670                 List.<JCExpression>of(make.Literal(lit)));
   671         eqtest.setType(syms.booleanType);
   672         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   673         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   674         compound.setType(syms.booleanType);
   675         return compound;
   676     }
   678     private JCExpression deserGetter(String func, Type type) {
   679         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   680     }
   682     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   683         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   684         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   685         return make.Apply(
   686                     List.<JCExpression>nil(),
   687                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   688                     args).setType(type);
   689     }
   691     /**
   692      * Create new synthetic method with given flags, name, type, owner
   693      */
   694     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   695         return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
   696     }
   698     /**
   699      * Create new synthetic variable with given flags, name, type, owner
   700      */
   701     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   702         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   703     }
   705     /**
   706      * Create new synthetic variable with given flags, name, type, owner
   707      */
   708     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   709         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   710     }
   712     /**
   713      * Set varargsElement field on a given tree (must be either a new class tree
   714      * or a method call tree)
   715      */
   716     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   717         if (varargsElement != null) {
   718             switch (tree.getTag()) {
   719                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   720                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   721                 default: throw new AssertionError();
   722             }
   723         }
   724     }
   726     /**
   727      * Convert method/constructor arguments by inserting appropriate cast
   728      * as required by type-erasure - this is needed when bridging a lambda/method
   729      * reference, as the bridged signature might require downcast to be compatible
   730      * with the generated signature.
   731      */
   732     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   733        Assert.check(meth.kind == Kinds.MTH);
   734        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   735        if (varargsElement != null) {
   736            Assert.check((meth.flags() & VARARGS) != 0);
   737        }
   738        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   739     }
   741     // </editor-fold>
   743     /**
   744      * Generate an adapter method "bridge" for a method reference which cannot
   745      * be used directly.
   746      */
   747     private class MemberReferenceBridger {
   749         private final JCMemberReference tree;
   750         private final ReferenceTranslationContext localContext;
   751         private final ListBuffer<JCExpression> args = new ListBuffer<>();
   752         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
   754         MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
   755             this.tree = tree;
   756             this.localContext = localContext;
   757         }
   759         /**
   760          * Generate the bridge
   761          */
   762         JCMethodDecl bridge() {
   763             int prevPos = make.pos;
   764             try {
   765                 make.at(tree);
   766                 Type samDesc = localContext.bridgedRefSig();
   767                 List<Type> samPTypes = samDesc.getParameterTypes();
   769                 //an extra argument is prepended to the signature of the bridge in case
   770                 //the member reference is an instance method reference (in which case
   771                 //the receiver expression is passed to the bridge itself).
   772                 Type recType = null;
   773                 switch (tree.kind) {
   774                     case IMPLICIT_INNER:
   775                         recType = tree.sym.owner.type.getEnclosingType();
   776                         break;
   777                     case BOUND:
   778                         recType = tree.getQualifierExpression().type;
   779                         break;
   780                     case UNBOUND:
   781                         recType = samPTypes.head;
   782                         samPTypes = samPTypes.tail;
   783                         break;
   784                 }
   786                 //generate the parameter list for the bridged member reference - the
   787                 //bridge signature will match the signature of the target sam descriptor
   789                 VarSymbol rcvr = (recType == null)
   790                         ? null
   791                         : addParameter("rec$", recType, false);
   793                 List<Type> refPTypes = tree.sym.type.getParameterTypes();
   794                 int refSize = refPTypes.size();
   795                 int samSize = samPTypes.size();
   796                 // Last parameter to copy from referenced method
   797                 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
   799                 List<Type> l = refPTypes;
   800                 // Use parameter types of the referenced method, excluding final var args
   801                 for (int i = 0; l.nonEmpty() && i < last; ++i) {
   802                     addParameter("x$" + i, l.head, true);
   803                     l = l.tail;
   804                 }
   805                 // Flatten out the var args
   806                 for (int i = last; i < samSize; ++i) {
   807                     addParameter("xva$" + i, tree.varargsElement, true);
   808                 }
   810                 //generate the bridge method declaration
   811                 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
   812                         localContext.bridgeSym.name,
   813                         make.QualIdent(samDesc.getReturnType().tsym),
   814                         List.<JCTypeParameter>nil(),
   815                         params.toList(),
   816                         tree.sym.type.getThrownTypes() == null
   817                         ? List.<JCExpression>nil()
   818                         : make.Types(tree.sym.type.getThrownTypes()),
   819                         null,
   820                         null);
   821                 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
   822                 bridgeDecl.type = localContext.bridgeSym.type =
   823                         types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
   825                 //bridge method body generation - this can be either a method call or a
   826                 //new instance creation expression, depending on the member reference kind
   827                 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
   828                         ? bridgeExpressionInvoke(makeReceiver(rcvr))
   829                         : bridgeExpressionNew();
   831                 //the body is either a return expression containing a method call,
   832                 //or the method call itself, depending on whether the return type of
   833                 //the bridge is non-void/void.
   834                 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
   836                 return bridgeDecl;
   837             } finally {
   838                 make.at(prevPos);
   839             }
   840         }
   841         //where
   842             private JCExpression makeReceiver(VarSymbol rcvr) {
   843                 if (rcvr == null) return null;
   844                 JCExpression rcvrExpr = make.Ident(rcvr);
   845                 Type rcvrType = tree.sym.enclClass().type;
   846                 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   847                     rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   848                 }
   849                 return rcvrExpr;
   850             }
   852         /**
   853          * determine the receiver of the bridged method call - the receiver can
   854          * be either the synthetic receiver parameter or a type qualifier; the
   855          * original qualifier expression is never used here, as it might refer
   856          * to symbols not available in the static context of the bridge
   857          */
   858         private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
   859             JCExpression qualifier =
   860                     tree.sym.isStatic() ?
   861                         make.Type(tree.sym.owner.type) :
   862                         (rcvr != null) ?
   863                             rcvr :
   864                             tree.getQualifierExpression();
   866             //create the qualifier expression
   867             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   868             select.sym = tree.sym;
   869             select.type = tree.sym.erasure(types);
   871             //create the method call expression
   872             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   873                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   874                     setType(tree.sym.erasure(types).getReturnType());
   876             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   877             setVarargsIfNeeded(apply, tree.varargsElement);
   878             return apply;
   879         }
   881         /**
   882          * the enclosing expression is either 'null' (no enclosing type) or set
   883          * to the first bridge synthetic parameter
   884          */
   885         private JCExpression bridgeExpressionNew() {
   886             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   887                 //create the array creation expression
   888                 JCNewArray newArr = make.NewArray(
   889                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   890                         List.of(make.Ident(params.first())),
   891                         null);
   892                 newArr.type = tree.getQualifierExpression().type;
   893                 return newArr;
   894             } else {
   895                 JCExpression encl = null;
   896                 switch (tree.kind) {
   897                     case UNBOUND:
   898                     case IMPLICIT_INNER:
   899                         encl = make.Ident(params.first());
   900                 }
   902                 //create the instance creation expression
   903                 JCNewClass newClass = make.NewClass(encl,
   904                         List.<JCExpression>nil(),
   905                         make.Type(tree.getQualifierExpression().type),
   906                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   907                         null);
   908                 newClass.constructor = tree.sym;
   909                 newClass.constructorType = tree.sym.erasure(types);
   910                 newClass.type = tree.getQualifierExpression().type;
   911                 setVarargsIfNeeded(newClass, tree.varargsElement);
   912                 return newClass;
   913             }
   914         }
   916         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   917             VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
   918             params.append(make.VarDef(vsym, null));
   919             if (genArg) {
   920                 args.append(make.Ident(vsym));
   921             }
   922             return vsym;
   923         }
   924     }
   926     /**
   927      * Bridges a member reference - this is needed when:
   928      * * Var args in the referenced method need to be flattened away
   929      * * super is used
   930      */
   931     private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
   932         kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
   933     }
   935     private MethodType typeToMethodType(Type mt) {
   936         Type type = types.erasure(mt);
   937         return new MethodType(type.getParameterTypes(),
   938                         type.getReturnType(),
   939                         type.getThrownTypes(),
   940                         syms.methodClass);
   941     }
   943     /**
   944      * Generate an indy method call to the meta factory
   945      */
   946     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
   947             int refKind, Symbol refSym, List<JCExpression> indy_args) {
   948         JCFunctionalExpression tree = context.tree;
   949         //determine the static bsm args
   950         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   951         List<Object> staticArgs = List.<Object>of(
   952                 typeToMethodType(samSym.type),
   953                 new Pool.MethodHandle(refKind, refSym, types),
   954                 typeToMethodType(tree.getDescriptorType(types)));
   956         //computed indy arg types
   957         ListBuffer<Type> indy_args_types = new ListBuffer<>();
   958         for (JCExpression arg : indy_args) {
   959             indy_args_types.append(arg.type);
   960         }
   962         //finally, compute the type of the indy call
   963         MethodType indyType = new MethodType(indy_args_types.toList(),
   964                 tree.type,
   965                 List.<Type>nil(),
   966                 syms.methodClass);
   968         Name metafactoryName = context.needsAltMetafactory() ?
   969                 names.altMetafactory : names.metafactory;
   971         if (context.needsAltMetafactory()) {
   972             ListBuffer<Object> markers = new ListBuffer<>();
   973             for (Type t : tree.targets.tail) {
   974                 if (t.tsym != syms.serializableType.tsym) {
   975                     markers.append(t.tsym);
   976                 }
   977             }
   978             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
   979             boolean hasMarkers = markers.nonEmpty();
   980             boolean hasBridges = context.bridges.nonEmpty();
   981             if (hasMarkers) {
   982                 flags |= FLAG_MARKERS;
   983             }
   984             if (hasBridges) {
   985                 flags |= FLAG_BRIDGES;
   986             }
   987             staticArgs = staticArgs.append(flags);
   988             if (hasMarkers) {
   989                 staticArgs = staticArgs.append(markers.length());
   990                 staticArgs = staticArgs.appendList(markers.toList());
   991             }
   992             if (hasBridges) {
   993                 staticArgs = staticArgs.append(context.bridges.length() - 1);
   994                 for (Symbol s : context.bridges) {
   995                     Type s_erasure = s.erasure(types);
   996                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
   997                         staticArgs = staticArgs.append(s.erasure(types));
   998                     }
   999                 }
  1001             if (context.isSerializable()) {
  1002                 int prevPos = make.pos;
  1003                 try {
  1004                     make.at(kInfo.clazz);
  1005                     addDeserializationCase(refKind, refSym, tree.type, samSym,
  1006                             tree, staticArgs, indyType);
  1007                 } finally {
  1008                     make.at(prevPos);
  1013         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
  1016     /**
  1017      * Generate an indy method call with given name, type and static bootstrap
  1018      * arguments types
  1019      */
  1020     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
  1021             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
  1022             Name methName) {
  1023         int prevPos = make.pos;
  1024         try {
  1025             make.at(pos);
  1026             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
  1027                     syms.stringType,
  1028                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
  1030             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
  1031                     bsmName, bsm_staticArgs, List.<Type>nil());
  1033             DynamicMethodSymbol dynSym =
  1034                     new DynamicMethodSymbol(methName,
  1035                                             syms.noSymbol,
  1036                                             bsm.isStatic() ?
  1037                                                 ClassFile.REF_invokeStatic :
  1038                                                 ClassFile.REF_invokeVirtual,
  1039                                             (MethodSymbol)bsm,
  1040                                             indyType,
  1041                                             staticArgs.toArray());
  1043             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1044             qualifier.sym = dynSym;
  1045             qualifier.type = indyType.getReturnType();
  1047             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
  1048             proxyCall.type = indyType.getReturnType();
  1049             return proxyCall;
  1050         } finally {
  1051             make.at(prevPos);
  1054     //where
  1055     private List<Type> bsmStaticArgToTypes(List<Object> args) {
  1056         ListBuffer<Type> argtypes = new ListBuffer<>();
  1057         for (Object arg : args) {
  1058             argtypes.append(bsmStaticArgToType(arg));
  1060         return argtypes.toList();
  1063     private Type bsmStaticArgToType(Object arg) {
  1064         Assert.checkNonNull(arg);
  1065         if (arg instanceof ClassSymbol) {
  1066             return syms.classType;
  1067         } else if (arg instanceof Integer) {
  1068             return syms.intType;
  1069         } else if (arg instanceof Long) {
  1070             return syms.longType;
  1071         } else if (arg instanceof Float) {
  1072             return syms.floatType;
  1073         } else if (arg instanceof Double) {
  1074             return syms.doubleType;
  1075         } else if (arg instanceof String) {
  1076             return syms.stringType;
  1077         } else if (arg instanceof Pool.MethodHandle) {
  1078             return syms.methodHandleType;
  1079         } else if (arg instanceof MethodType) {
  1080             return syms.methodTypeType;
  1081         } else {
  1082             Assert.error("bad static arg " + arg.getClass());
  1083             return null;
  1087     /**
  1088      * Get the opcode associated with this method reference
  1089      */
  1090     private int referenceKind(Symbol refSym) {
  1091         if (refSym.isConstructor()) {
  1092             return ClassFile.REF_newInvokeSpecial;
  1093         } else {
  1094             if (refSym.isStatic()) {
  1095                 return ClassFile.REF_invokeStatic;
  1096             } else if ((refSym.flags() & PRIVATE) != 0) {
  1097                 return ClassFile.REF_invokeSpecial;
  1098             } else if (refSym.enclClass().isInterface()) {
  1099                 return ClassFile.REF_invokeInterface;
  1100             } else {
  1101                 return ClassFile.REF_invokeVirtual;
  1106     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1107     /**
  1108      * This visitor collects information about translation of a lambda expression.
  1109      * More specifically, it keeps track of the enclosing contexts and captured locals
  1110      * accessed by the lambda being translated (as well as other useful info).
  1111      * It also translates away problems for LambdaToMethod.
  1112      */
  1113     class LambdaAnalyzerPreprocessor extends TreeTranslator {
  1115         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1116         private List<Frame> frameStack;
  1118         /**
  1119          * keep the count of lambda expression (used to generate unambiguous
  1120          * names)
  1121          */
  1122         private int lambdaCount = 0;
  1124         /**
  1125          * keep the count of lambda expression defined in given context (used to
  1126          * generate unambiguous names for serializable lambdas)
  1127          */
  1128         private class SyntheticMethodNameCounter {
  1129             private Map<String, Integer> map = new HashMap<>();
  1130             int getIndex(StringBuilder buf) {
  1131                 String temp = buf.toString();
  1132                 Integer count = map.get(temp);
  1133                 if (count == null) {
  1134                     count = 0;
  1136                 ++count;
  1137                 map.put(temp, count);
  1138                 return count;
  1141         private SyntheticMethodNameCounter syntheticMethodNameCounts =
  1142                 new SyntheticMethodNameCounter();
  1144         private Map<Symbol, JCClassDecl> localClassDefs;
  1146         /**
  1147          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1148          * a static var init context
  1149          */
  1150         private Map<ClassSymbol, Symbol> clinits =
  1151                 new HashMap<ClassSymbol, Symbol>();
  1153         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
  1154             frameStack = List.nil();
  1155             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1156             return translate(tree);
  1159         @Override
  1160         public void visitBlock(JCBlock tree) {
  1161             List<Frame> prevStack = frameStack;
  1162             try {
  1163                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1164                     frameStack = frameStack.prepend(new Frame(tree));
  1166                 super.visitBlock(tree);
  1168             finally {
  1169                 frameStack = prevStack;
  1173         @Override
  1174         public void visitClassDef(JCClassDecl tree) {
  1175             List<Frame> prevStack = frameStack;
  1176             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
  1177                     syntheticMethodNameCounts;
  1178             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1179             DiagnosticSource prevSource = log.currentSource();
  1180             try {
  1181                 log.useSource(tree.sym.sourcefile);
  1182                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
  1183                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1184                 if (tree.sym.owner.kind == MTH) {
  1185                     localClassDefs.put(tree.sym, tree);
  1187                 if (directlyEnclosingLambda() != null) {
  1188                     tree.sym.owner = owner();
  1189                     if (tree.sym.hasOuterInstance()) {
  1190                         //if a class is defined within a lambda, the lambda must capture
  1191                         //its enclosing instance (if any)
  1192                         TranslationContext<?> localContext = context();
  1193                         while (localContext != null) {
  1194                             if (localContext.tree.getTag() == LAMBDA) {
  1195                                 ((LambdaTranslationContext)localContext)
  1196                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1198                             localContext = localContext.prev;
  1202                 frameStack = frameStack.prepend(new Frame(tree));
  1203                 super.visitClassDef(tree);
  1205             finally {
  1206                 log.useSource(prevSource.getFile());
  1207                 frameStack = prevStack;
  1208                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
  1209                 clinits = prevClinits;
  1213         @Override
  1214         public void visitIdent(JCIdent tree) {
  1215             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1216                 if (tree.sym.kind == VAR &&
  1217                         tree.sym.owner.kind == MTH &&
  1218                         tree.type.constValue() == null) {
  1219                     TranslationContext<?> localContext = context();
  1220                     while (localContext != null) {
  1221                         if (localContext.tree.getTag() == LAMBDA) {
  1222                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1223                             if (block == null) break;
  1224                             ((LambdaTranslationContext)localContext)
  1225                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1227                         localContext = localContext.prev;
  1229                 } else if (tree.sym.owner.kind == TYP) {
  1230                     TranslationContext<?> localContext = context();
  1231                     while (localContext != null) {
  1232                         if (localContext.tree.hasTag(LAMBDA)) {
  1233                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1234                             if (block == null) break;
  1235                             switch (block.getTag()) {
  1236                                 case CLASSDEF:
  1237                                     JCClassDecl cdecl = (JCClassDecl)block;
  1238                                     ((LambdaTranslationContext)localContext)
  1239                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1240                                     break;
  1241                                 default:
  1242                                     Assert.error("bad block kind");
  1245                         localContext = localContext.prev;
  1249             super.visitIdent(tree);
  1252         @Override
  1253         public void visitLambda(JCLambda tree) {
  1254             List<Frame> prevStack = frameStack;
  1255             try {
  1256                 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
  1257                 frameStack = frameStack.prepend(new Frame(tree));
  1258                 for (JCVariableDecl param : tree.params) {
  1259                     context.addSymbol(param.sym, PARAM);
  1260                     frameStack.head.addLocal(param.sym);
  1262                 contextMap.put(tree, context);
  1263                 super.visitLambda(tree);
  1264                 context.complete();
  1266             finally {
  1267                 frameStack = prevStack;
  1271         @Override
  1272         public void visitMethodDef(JCMethodDecl tree) {
  1273             List<Frame> prevStack = frameStack;
  1274             try {
  1275                 frameStack = frameStack.prepend(new Frame(tree));
  1276                 super.visitMethodDef(tree);
  1278             finally {
  1279                 frameStack = prevStack;
  1283         @Override
  1284         public void visitNewClass(JCNewClass tree) {
  1285             if (lambdaNewClassFilter(context(), tree)) {
  1286                 TranslationContext<?> localContext = context();
  1287                 while (localContext != null) {
  1288                     if (localContext.tree.getTag() == LAMBDA) {
  1289                         ((LambdaTranslationContext)localContext)
  1290                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1292                     localContext = localContext.prev;
  1295             if (context() != null && tree.type.tsym.owner.kind == MTH) {
  1296                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1297                 captureLocalClassDefs(tree.type.tsym, lambdaContext);
  1299             super.visitNewClass(tree);
  1301         //where
  1302             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1303                 JCClassDecl localCDef = localClassDefs.get(csym);
  1304                 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
  1305                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1306                         @Override
  1307                         void addFreeVars(ClassSymbol c) {
  1308                             captureLocalClassDefs(c, lambdaContext);
  1310                         @Override
  1311                         void visitSymbol(Symbol sym) {
  1312                             if (sym.kind == VAR &&
  1313                                     sym.owner.kind == MTH &&
  1314                                     ((VarSymbol)sym).getConstValue() == null) {
  1315                                 TranslationContext<?> localContext = context();
  1316                                 while (localContext != null) {
  1317                                     if (localContext.tree.getTag() == LAMBDA) {
  1318                                         JCTree block = capturedDecl(localContext.depth, sym);
  1319                                         if (block == null) break;
  1320                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1322                                     localContext = localContext.prev;
  1326                     };
  1327                     fvc.scan(localCDef);
  1331         /**
  1332          * Method references to local class constructors, may, if the local
  1333          * class references local variables, have implicit constructor
  1334          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1335          * information added in the LambdaToMethod pass will have the wrong
  1336          * signature. Hooks between Lower and LambdaToMethod have been added to
  1337          * handle normal "new" in this case. This visitor converts potentially
  1338          * effected method references into a lambda containing a normal "new" of
  1339          * the class.
  1341          * @param tree
  1342          */
  1343         @Override
  1344         public void visitReference(JCMemberReference tree) {
  1345             if (tree.getMode() == ReferenceMode.NEW
  1346                     && tree.kind != ReferenceKind.ARRAY_CTOR
  1347                     && tree.sym.owner.isLocal()) {
  1348                 MethodSymbol consSym = (MethodSymbol) tree.sym;
  1349                 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
  1350                 Type classType = consSym.owner.type;
  1352                 // Build lambda parameters
  1353                 // partially cloned from TreeMaker.Params until 8014021 is fixed
  1354                 Symbol owner = owner();
  1355                 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
  1356                 int i = 0;
  1357                 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
  1358                     JCVariableDecl param = make.Param(make.paramName(i++), l.head, owner);
  1359                     param.sym.pos = tree.pos;
  1360                     paramBuff.append(param);
  1362                 List<JCVariableDecl> params = paramBuff.toList();
  1364                 // Make new-class call
  1365                 JCNewClass nc = makeNewClass(classType, make.Idents(params));
  1366                 nc.pos = tree.pos;
  1368                 // Make lambda holding the new-class call
  1369                 JCLambda slam = make.Lambda(params, nc);
  1370                 slam.targets = tree.targets;
  1371                 slam.type = tree.type;
  1372                 slam.pos = tree.pos;
  1374                 // Now it is a lambda, process as such
  1375                 visitLambda(slam);
  1376             } else {
  1377                 super.visitReference(tree);
  1378                 contextMap.put(tree, makeReferenceContext(tree));
  1382         @Override
  1383         public void visitSelect(JCFieldAccess tree) {
  1384             if (context() != null && tree.sym.kind == VAR &&
  1385                         (tree.sym.name == names._this ||
  1386                          tree.sym.name == names._super)) {
  1387                 // A select of this or super means, if we are in a lambda,
  1388                 // we much have an instance context
  1389                 TranslationContext<?> localContext = context();
  1390                 while (localContext != null) {
  1391                     if (localContext.tree.hasTag(LAMBDA)) {
  1392                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1393                         if (clazz == null) break;
  1394                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1396                     localContext = localContext.prev;
  1399             super.visitSelect(tree);
  1402         @Override
  1403         public void visitVarDef(JCVariableDecl tree) {
  1404             TranslationContext<?> context = context();
  1405             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1406                     (LambdaTranslationContext)context :
  1407                     null;
  1408             if (ltc != null) {
  1409                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1410                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1412                 // Check for type variables (including as type arguments).
  1413                 // If they occur within class nested in a lambda, mark for erasure
  1414                 Type type = tree.sym.asType();
  1415                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1416                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1420             List<Frame> prevStack = frameStack;
  1421             try {
  1422                 if (tree.sym.owner.kind == MTH) {
  1423                     frameStack.head.addLocal(tree.sym);
  1425                 frameStack = frameStack.prepend(new Frame(tree));
  1426                 super.visitVarDef(tree);
  1428             finally {
  1429                 frameStack = prevStack;
  1433         /**
  1434          * Return a valid owner given the current declaration stack
  1435          * (required to skip synthetic lambda symbols)
  1436          */
  1437         private Symbol owner() {
  1438             return owner(false);
  1441         @SuppressWarnings("fallthrough")
  1442         private Symbol owner(boolean skipLambda) {
  1443             List<Frame> frameStack2 = frameStack;
  1444             while (frameStack2.nonEmpty()) {
  1445                 switch (frameStack2.head.tree.getTag()) {
  1446                     case VARDEF:
  1447                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1448                             frameStack2 = frameStack2.tail;
  1449                             break;
  1451                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1452                         return initSym(cdecl.sym,
  1453                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1454                     case BLOCK:
  1455                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1456                         return initSym(cdecl2.sym,
  1457                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1458                     case CLASSDEF:
  1459                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1460                     case METHODDEF:
  1461                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1462                     case LAMBDA:
  1463                         if (!skipLambda)
  1464                             return ((LambdaTranslationContext)contextMap
  1465                                     .get(frameStack2.head.tree)).translatedSym;
  1466                     default:
  1467                         frameStack2 = frameStack2.tail;
  1470             Assert.error();
  1471             return null;
  1474         private Symbol initSym(ClassSymbol csym, long flags) {
  1475             boolean isStatic = (flags & STATIC) != 0;
  1476             if (isStatic) {
  1477                 /* static clinits are generated in Gen, so we need to use a fake
  1478                  * one. Attr creates a fake clinit method while attributing
  1479                  * lambda expressions used as initializers of static fields, so
  1480                  * let's use that one.
  1481                  */
  1482                 MethodSymbol clinit = attr.removeClinit(csym);
  1483                 if (clinit != null) {
  1484                     clinits.put(csym, clinit);
  1485                     return clinit;
  1488                 /* if no clinit is found at Attr, then let's try at clinits.
  1489                  */
  1490                 clinit = (MethodSymbol)clinits.get(csym);
  1491                 if (clinit == null) {
  1492                     /* no luck, let's create a new one
  1493                      */
  1494                     clinit = makePrivateSyntheticMethod(STATIC,
  1495                             names.clinit,
  1496                             new MethodType(List.<Type>nil(), syms.voidType,
  1497                                 List.<Type>nil(), syms.methodClass),
  1498                             csym);
  1499                     clinits.put(csym, clinit);
  1501                 return clinit;
  1502             } else {
  1503                 //get the first constructor and treat it as the instance init sym
  1504                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1505                     return s;
  1508             Assert.error("init not found");
  1509             return null;
  1512         private JCTree directlyEnclosingLambda() {
  1513             if (frameStack.isEmpty()) {
  1514                 return null;
  1516             List<Frame> frameStack2 = frameStack;
  1517             while (frameStack2.nonEmpty()) {
  1518                 switch (frameStack2.head.tree.getTag()) {
  1519                     case CLASSDEF:
  1520                     case METHODDEF:
  1521                         return null;
  1522                     case LAMBDA:
  1523                         return frameStack2.head.tree;
  1524                     default:
  1525                         frameStack2 = frameStack2.tail;
  1528             Assert.error();
  1529             return null;
  1532         private boolean inClassWithinLambda() {
  1533             if (frameStack.isEmpty()) {
  1534                 return false;
  1536             List<Frame> frameStack2 = frameStack;
  1537             boolean classFound = false;
  1538             while (frameStack2.nonEmpty()) {
  1539                 switch (frameStack2.head.tree.getTag()) {
  1540                     case LAMBDA:
  1541                         return classFound;
  1542                     case CLASSDEF:
  1543                         classFound = true;
  1544                         frameStack2 = frameStack2.tail;
  1545                         break;
  1546                     default:
  1547                         frameStack2 = frameStack2.tail;
  1550             // No lambda
  1551             return false;
  1554         /**
  1555          * Return the declaration corresponding to a symbol in the enclosing
  1556          * scope; the depth parameter is used to filter out symbols defined
  1557          * in nested scopes (which do not need to undergo capture).
  1558          */
  1559         private JCTree capturedDecl(int depth, Symbol sym) {
  1560             int currentDepth = frameStack.size() - 1;
  1561             for (Frame block : frameStack) {
  1562                 switch (block.tree.getTag()) {
  1563                     case CLASSDEF:
  1564                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1565                         if (sym.isMemberOf(clazz, types)) {
  1566                             return currentDepth > depth ? null : block.tree;
  1568                         break;
  1569                     case VARDEF:
  1570                         if (((JCVariableDecl)block.tree).sym == sym &&
  1571                                 sym.owner.kind == MTH) { //only locals are captured
  1572                             return currentDepth > depth ? null : block.tree;
  1574                         break;
  1575                     case BLOCK:
  1576                     case METHODDEF:
  1577                     case LAMBDA:
  1578                         if (block.locals != null && block.locals.contains(sym)) {
  1579                             return currentDepth > depth ? null : block.tree;
  1581                         break;
  1582                     default:
  1583                         Assert.error("bad decl kind " + block.tree.getTag());
  1585                 currentDepth--;
  1587             return null;
  1590         private TranslationContext<?> context() {
  1591             for (Frame frame : frameStack) {
  1592                 TranslationContext<?> context = contextMap.get(frame.tree);
  1593                 if (context != null) {
  1594                     return context;
  1597             return null;
  1600         /**
  1601          *  This is used to filter out those identifiers that needs to be adjusted
  1602          *  when translating away lambda expressions
  1603          */
  1604         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1605             return (sym.kind == VAR || sym.kind == MTH)
  1606                     && !sym.isStatic()
  1607                     && sym.name != names.init;
  1610         /**
  1611          * This is used to filter out those new class expressions that need to
  1612          * be qualified with an enclosing tree
  1613          */
  1614         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1615             if (context != null
  1616                     && tree.encl == null
  1617                     && tree.def == null
  1618                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1619                 Type encl = tree.type.getEnclosingType();
  1620                 Type current = context.owner.enclClass().type;
  1621                 while (!current.hasTag(NONE)) {
  1622                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1623                         return true;
  1625                     current = current.getEnclosingType();
  1627                 return false;
  1628             } else {
  1629                 return false;
  1633         private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
  1634             return new LambdaTranslationContext(tree);
  1637         private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
  1638             return new ReferenceTranslationContext(tree);
  1641         private class Frame {
  1642             final JCTree tree;
  1643             List<Symbol> locals;
  1645             public Frame(JCTree tree) {
  1646                 this.tree = tree;
  1649             void addLocal(Symbol sym) {
  1650                 if (locals == null) {
  1651                     locals = List.nil();
  1653                 locals = locals.prepend(sym);
  1657         /**
  1658          * This class is used to store important information regarding translation of
  1659          * lambda expression/method references (see subclasses).
  1660          */
  1661         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1663             /** the underlying (untranslated) tree */
  1664             final T tree;
  1666             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1667             final Symbol owner;
  1669             /** the depth of this lambda expression in the frame stack */
  1670             final int depth;
  1672             /** the enclosing translation context (set for nested lambdas/mref) */
  1673             final TranslationContext<?> prev;
  1675             /** list of methods to be bridged by the meta-factory */
  1676             final List<Symbol> bridges;
  1678             TranslationContext(T tree) {
  1679                 this.tree = tree;
  1680                 this.owner = owner();
  1681                 this.depth = frameStack.size() - 1;
  1682                 this.prev = context();
  1683                 ClassSymbol csym =
  1684                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1685                 this.bridges = types.functionalInterfaceBridges(csym);
  1688             /** does this functional expression need to be created using alternate metafactory? */
  1689             boolean needsAltMetafactory() {
  1690                 return tree.targets.length() > 1 ||
  1691                         isSerializable() ||
  1692                         bridges.length() > 1;
  1695             /** does this functional expression require serialization support? */
  1696             boolean isSerializable() {
  1697                 if (forceSerializable) {
  1698                     return true;
  1700                 for (Type target : tree.targets) {
  1701                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1702                         return true;
  1705                 return false;
  1708             /**
  1709              * @return Name of the enclosing method to be folded into synthetic
  1710              * method name
  1711              */
  1712             String enclosingMethodName() {
  1713                 return syntheticMethodNameComponent(owner.name);
  1716             /**
  1717              * @return Method name in a form that can be folded into a
  1718              * component of a synthetic method name
  1719              */
  1720             String syntheticMethodNameComponent(Name name) {
  1721                 if (name == null) {
  1722                     return "null";
  1724                 String methodName = name.toString();
  1725                 if (methodName.equals("<clinit>")) {
  1726                     methodName = "static";
  1727                 } else if (methodName.equals("<init>")) {
  1728                     methodName = "new";
  1730                 return methodName;
  1734         /**
  1735          * This class retains all the useful information about a lambda expression;
  1736          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1737          * and the used by the main translation routines in order to adjust references
  1738          * to captured locals/members, etc.
  1739          */
  1740         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1742             /** variable in the enclosing context to which this lambda is assigned */
  1743             final Symbol self;
  1745             /** variable in the enclosing context to which this lambda is assigned */
  1746             final Symbol assignedTo;
  1748             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
  1750             /** the synthetic symbol for the method hoisting the translated lambda */
  1751             Symbol translatedSym;
  1753             List<JCVariableDecl> syntheticParams;
  1755             LambdaTranslationContext(JCLambda tree) {
  1756                 super(tree);
  1757                 Frame frame = frameStack.head;
  1758                 switch (frame.tree.getTag()) {
  1759                     case VARDEF:
  1760                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
  1761                         break;
  1762                     case ASSIGN:
  1763                         self = null;
  1764                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
  1765                         break;
  1766                     default:
  1767                         assignedTo = self = null;
  1768                         break;
  1771                 // This symbol will be filled-in in complete
  1772                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
  1774                 if (dumpLambdaToMethodStats) {
  1775                     log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym);
  1777                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
  1779                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
  1780                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
  1781                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
  1782                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
  1783                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
  1786              /**
  1787              * For a serializable lambda, generate a disambiguating string
  1788              * which maximizes stability across deserialization.
  1790              * @return String to differentiate synthetic lambda method names
  1791              */
  1792             private String serializedLambdaDisambiguation() {
  1793                 StringBuilder buf = new StringBuilder();
  1794                 // Append the enclosing method signature to differentiate
  1795                 // overloaded enclosing methods.  For lambdas enclosed in
  1796                 // lambdas, the generated lambda method will not have type yet,
  1797                 // but the enclosing method's name will have been generated
  1798                 // with this same method, so it will be unique and never be
  1799                 // overloaded.
  1800                 Assert.check(
  1801                         owner.type != null ||
  1802                         directlyEnclosingLambda() != null);
  1803                 if (owner.type != null) {
  1804                     buf.append(typeSig(owner.type));
  1805                     buf.append(":");
  1808                 // Add target type info
  1809                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
  1810                 buf.append(" ");
  1812                 // Add variable assigned to
  1813                 if (assignedTo != null) {
  1814                     buf.append(assignedTo.flatName());
  1815                     buf.append("=");
  1817                 //add captured locals info: type, name, order
  1818                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
  1819                     if (fv != self) {
  1820                         buf.append(typeSig(fv.type));
  1821                         buf.append(" ");
  1822                         buf.append(fv.flatName());
  1823                         buf.append(",");
  1827                 return buf.toString();
  1830             /**
  1831              * For a non-serializable lambda, generate a simple method.
  1833              * @return Name to use for the synthetic lambda method name
  1834              */
  1835             private Name lambdaName() {
  1836                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
  1839             /**
  1840              * For a serializable lambda, generate a method name which maximizes
  1841              * name stability across deserialization.
  1843              * @return Name to use for the synthetic lambda method name
  1844              */
  1845             private Name serializedLambdaName() {
  1846                 StringBuilder buf = new StringBuilder();
  1847                 buf.append(names.lambda);
  1848                 // Append the name of the method enclosing the lambda.
  1849                 buf.append(enclosingMethodName());
  1850                 buf.append('$');
  1851                 // Append a hash of the disambiguating string : enclosing method
  1852                 // signature, etc.
  1853                 String disam = serializedLambdaDisambiguation();
  1854                 buf.append(Integer.toHexString(disam.hashCode()));
  1855                 buf.append('$');
  1856                 // The above appended name components may not be unique, append
  1857                 // a count based on the above name components.
  1858                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  1859                 String result = buf.toString();
  1860                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
  1861                 return names.fromString(result);
  1864             /**
  1865              * Translate a symbol of a given kind into something suitable for the
  1866              * synthetic lambda body
  1867              */
  1868             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1869                 Symbol ret;
  1870                 switch (skind) {
  1871                     case CAPTURED_THIS:
  1872                         ret = sym;  // self represented
  1873                         break;
  1874                     case TYPE_VAR:
  1875                         // Just erase the type var
  1876                         ret = new VarSymbol(sym.flags(), name,
  1877                                 types.erasure(sym.type), sym.owner);
  1879                         /* this information should also be kept for LVT generation at Gen
  1880                          * a Symbol with pos < startPos won't be tracked.
  1881                          */
  1882                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
  1883                         break;
  1884                     case CAPTURED_VAR:
  1885                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
  1886                             @Override
  1887                             public Symbol baseSymbol() {
  1888                                 //keep mapping with original captured symbol
  1889                                 return sym;
  1891                         };
  1892                         break;
  1893                     case LOCAL_VAR:
  1894                         ret = new VarSymbol(sym.flags() & FINAL, name, sym.type, translatedSym);
  1895                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1896                         break;
  1897                     case PARAM:
  1898                         ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, name, types.erasure(sym.type), translatedSym);
  1899                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1900                         break;
  1901                     default:
  1902                         ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1903                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
  1905                 if (ret != sym) {
  1906                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1907                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1909                 return ret;
  1912             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1913                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
  1914                 Name preferredName;
  1915                 switch (skind) {
  1916                     case CAPTURED_THIS:
  1917                         preferredName = names.fromString("encl$" + transMap.size());
  1918                         break;
  1919                     case CAPTURED_VAR:
  1920                         preferredName = names.fromString("cap$" + transMap.size());
  1921                         break;
  1922                     case LOCAL_VAR:
  1923                         preferredName = sym.name;
  1924                         break;
  1925                     case PARAM:
  1926                         preferredName = sym.name;
  1927                         break;
  1928                     case TYPE_VAR:
  1929                         preferredName = sym.name;
  1930                         break;
  1931                     default: throw new AssertionError();
  1933                 if (!transMap.containsKey(sym)) {
  1934                     transMap.put(sym, translate(preferredName, sym, skind));
  1938             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
  1939                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
  1940                 Assert.checkNonNull(m);
  1941                 return m;
  1944             JCTree translate(JCIdent lambdaIdent) {
  1945                 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
  1946                     if (m.containsKey(lambdaIdent.sym)) {
  1947                         Symbol tSym = m.get(lambdaIdent.sym);
  1948                         JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
  1949                         tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
  1950                         return t;
  1953                 return null;
  1956             /**
  1957              * The translatedSym is not complete/accurate until the analysis is
  1958              * finished.  Once the analysis is finished, the translatedSym is
  1959              * "completed" -- updated with type information, access modifiers,
  1960              * and full parameter list.
  1961              */
  1962             void complete() {
  1963                 if (syntheticParams != null) {
  1964                     return;
  1966                 boolean inInterface = translatedSym.owner.isInterface();
  1967                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1969                 // If instance access isn't needed, make it static.
  1970                 // Interface instance methods must be default methods.
  1971                 // Lambda methods are private synthetic.
  1972                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
  1973                         PRIVATE |
  1974                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  1976                 //compute synthetic params
  1977                 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
  1979                 // The signature of the method is augmented with the following
  1980                 // synthetic parameters:
  1981                 //
  1982                 // 1) reference to enclosing contexts captured by the lambda expression
  1983                 // 2) enclosing locals captured by the lambda expression
  1984                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
  1985                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1987                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
  1988                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1990                 syntheticParams = params.toList();
  1992                 // Compute and set the lambda name
  1993                 translatedSym.name = isSerializable()
  1994                         ? serializedLambdaName()
  1995                         : lambdaName();
  1997                 //prepend synthetic args to translated lambda method signature
  1998                 translatedSym.type = types.createMethodTypeWithParameters(
  1999                         generatedLambdaSig(),
  2000                         TreeInfo.types(syntheticParams));
  2003             Type generatedLambdaSig() {
  2004                 return types.erasure(tree.getDescriptorType(types));
  2008         /**
  2009          * This class retains all the useful information about a method reference;
  2010          * the contents of this class are filled by the LambdaAnalyzer visitor,
  2011          * and the used by the main translation routines in order to adjust method
  2012          * references (i.e. in case a bridge is needed)
  2013          */
  2014         private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  2016             final boolean isSuper;
  2017             final Symbol bridgeSym;
  2018             final Symbol sigPolySym;
  2020             ReferenceTranslationContext(JCMemberReference tree) {
  2021                 super(tree);
  2022                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2023                 this.bridgeSym = needsBridge()
  2024                         ? makePrivateSyntheticMethod(isSuper ? 0 : STATIC,
  2025                                               referenceBridgeName(), null,
  2026                                               owner.enclClass())
  2027                         : null;
  2028                 this.sigPolySym = isSignaturePolymorphic()
  2029                         ? makePrivateSyntheticMethod(tree.sym.flags(),
  2030                                               tree.sym.name,
  2031                                               bridgedRefSig(),
  2032                                               tree.sym.enclClass())
  2033                         : null;
  2034                 if (dumpLambdaToMethodStats) {
  2035                     String key = bridgeSym == null ?
  2036                             "mref.stat" : "mref.stat.1";
  2037                     log.note(tree, key, needsAltMetafactory(), bridgeSym);
  2041             /**
  2042              * Get the opcode associated with this method reference
  2043              */
  2044             int referenceKind() {
  2045                 return LambdaToMethod.this.referenceKind(needsBridge()
  2046                         ? bridgeSym
  2047                         : tree.sym);
  2050             boolean needsVarArgsConversion() {
  2051                 return tree.varargsElement != null;
  2054             /**
  2055              * Generate a disambiguating string to increase stability (important
  2056              * if serialized)
  2058              * @return String to differentiate synthetic lambda method names
  2059              */
  2060             private String referenceBridgeDisambiguation() {
  2061                 StringBuilder buf = new StringBuilder();
  2062                 // Append the enclosing method signature to differentiate
  2063                 // overloaded enclosing methods.
  2064                 if (owner.type != null) {
  2065                     buf.append(typeSig(owner.type));
  2066                     buf.append(":");
  2069                 // Append qualifier type
  2070                 buf.append(classSig(tree.sym.owner.type));
  2072                 // Note static/instance
  2073                 buf.append(tree.sym.isStatic()? " S " : " I ");
  2075                 // Append referenced signature
  2076                 buf.append(typeSig(tree.sym.erasure(types)));
  2078                 return buf.toString();
  2081             /**
  2082              * Construct a unique stable name for the method reference bridge
  2084              * @return Name to use for the synthetic method name
  2085              */
  2086             private Name referenceBridgeName() {
  2087                 StringBuilder buf = new StringBuilder();
  2088                 // Append lambda ID, this is semantically significant
  2089                 buf.append(names.lambda);
  2090                 // Note that it is a method reference bridge
  2091                 buf.append("MR$");
  2092                 // Append the enclosing method name
  2093                 buf.append(enclosingMethodName());
  2094                 buf.append('$');
  2095                 // Append the referenced method name
  2096                 buf.append(syntheticMethodNameComponent(tree.sym.name));
  2097                 buf.append('$');
  2098                 // Append a hash of the disambiguating string : enclosing method
  2099                 // signature, etc.
  2100                 String disam = referenceBridgeDisambiguation();
  2101                 buf.append(Integer.toHexString(disam.hashCode()));
  2102                 buf.append('$');
  2103                 // The above appended name components may not be unique, append
  2104                 // a count based on the above name components.
  2105                 buf.append(syntheticMethodNameCounts.getIndex(buf));
  2106                 String result = buf.toString();
  2107                 return names.fromString(result);
  2110             /**
  2111              * @return Is this an array operation like clone()
  2112              */
  2113             boolean isArrayOp() {
  2114                 return tree.sym.owner == syms.arrayClass;
  2117             boolean receiverAccessible() {
  2118                 //hack needed to workaround 292 bug (7087658)
  2119                 //when 292 issue is fixed we should remove this and change the backend
  2120                 //code to always generate a method handle to an accessible method
  2121                 return tree.ownerAccessible;
  2124             /**
  2125              * The VM does not support access across nested classes (8010319).
  2126              * Were that ever to change, this should be removed.
  2127              */
  2128             boolean isPrivateInOtherClass() {
  2129                 return  (tree.sym.flags() & PRIVATE) != 0 &&
  2130                         !types.isSameType(
  2131                               types.erasure(tree.sym.enclClass().asType()),
  2132                               types.erasure(owner.enclClass().asType()));
  2135             /**
  2136              * Signature polymorphic methods need special handling.
  2137              * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
  2138              */
  2139             final boolean isSignaturePolymorphic() {
  2140                 return  tree.sym.kind == MTH &&
  2141                         types.isSignaturePolymorphic((MethodSymbol)tree.sym);
  2144             /**
  2145              * Does this reference needs a bridge (i.e. var args need to be
  2146              * expanded or "super" is used)
  2147              */
  2148             final boolean needsBridge() {
  2149                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  2150                         isPrivateInOtherClass() ||
  2151                         !receiverAccessible();
  2154             Type generatedRefSig() {
  2155                 return types.erasure(tree.sym.type);
  2158             Type bridgedRefSig() {
  2159                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  2163     // </editor-fold>
  2165     /*
  2166      * These keys provide mappings for various translated lambda symbols
  2167      * and the prevailing order must be maintained.
  2168      */
  2169     enum LambdaSymbolKind {
  2170         PARAM,          // original to translated lambda parameters
  2171         LOCAL_VAR,      // original to translated lambda locals
  2172         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
  2173         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
  2174         TYPE_VAR;       // original to translated lambda type variables
  2177     /**
  2178      * ****************************************************************
  2179      * Signature Generation
  2180      * ****************************************************************
  2181      */
  2183     private String typeSig(Type type) {
  2184         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2185         sg.assembleSig(type);
  2186         return sg.toString();
  2189     private String classSig(Type type) {
  2190         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  2191         sg.assembleClassSig(type);
  2192         return sg.toString();
  2195     /**
  2196      * Signature Generation
  2197      */
  2198     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  2200         /**
  2201          * An output buffer for type signatures.
  2202          */
  2203         StringBuilder sb = new StringBuilder();
  2205         L2MSignatureGenerator() {
  2206             super(types);
  2209         @Override
  2210         protected void append(char ch) {
  2211             sb.append(ch);
  2214         @Override
  2215         protected void append(byte[] ba) {
  2216             sb.append(new String(ba));
  2219         @Override
  2220         protected void append(Name name) {
  2221             sb.append(name.toString());
  2224         @Override
  2225         public String toString() {
  2226             return sb.toString();

mercurial