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

Mon, 10 Jun 2013 15:57:32 +0100

author
mcimadamore
date
Mon, 10 Jun 2013 15:57:32 +0100
changeset 1817
3582b62dccb2
parent 1802
8fb68f73d4b1
child 1824
455be95bd1b5
permissions
-rw-r--r--

8013576: Add stat support to LambdaToMethod
Summary: LambdaToMethod should emit info to help diagnose/test lambda metafactory problems
Reviewed-by: jjg, vromero

     1 /*
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 package com.sun.tools.javac.comp;
    27 import com.sun.tools.javac.tree.*;
    28 import com.sun.tools.javac.tree.JCTree.*;
    29 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
    30 import com.sun.tools.javac.tree.TreeMaker;
    31 import com.sun.tools.javac.tree.TreeTranslator;
    32 import com.sun.tools.javac.code.Attribute;
    33 import com.sun.tools.javac.code.Kinds;
    34 import com.sun.tools.javac.code.Scope;
    35 import com.sun.tools.javac.code.Symbol;
    36 import com.sun.tools.javac.code.Symbol.ClassSymbol;
    37 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
    38 import com.sun.tools.javac.code.Symbol.MethodSymbol;
    39 import com.sun.tools.javac.code.Symbol.VarSymbol;
    40 import com.sun.tools.javac.code.Symtab;
    41 import com.sun.tools.javac.code.Type;
    42 import com.sun.tools.javac.code.Type.MethodType;
    43 import com.sun.tools.javac.code.Types;
    44 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
    45 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
    46 import com.sun.tools.javac.jvm.*;
    47 import com.sun.tools.javac.util.*;
    48 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    49 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
    51 import java.util.HashMap;
    52 import java.util.LinkedHashMap;
    53 import java.util.Map;
    55 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
    56 import static com.sun.tools.javac.code.Flags.*;
    57 import static com.sun.tools.javac.code.Kinds.*;
    58 import static com.sun.tools.javac.code.TypeTag.*;
    59 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    61 /**
    62  * This pass desugars lambda expressions into static methods
    63  *
    64  *  <p><b>This is NOT part of any supported API.
    65  *  If you write code that depends on this, you do so at your own risk.
    66  *  This code and its internal interfaces are subject to change or
    67  *  deletion without notice.</b>
    68  */
    69 public class LambdaToMethod extends TreeTranslator {
    71     private JCDiagnostic.Factory diags;
    72     private Log log;
    73     private Lower lower;
    74     private Names names;
    75     private Symtab syms;
    76     private Resolve rs;
    77     private TreeMaker make;
    78     private Types types;
    79     private TransTypes transTypes;
    80     private Env<AttrContext> attrEnv;
    82     /** the analyzer scanner */
    83     private LambdaAnalyzerPreprocessor analyzer;
    85     /** map from lambda trees to translation contexts */
    86     private Map<JCTree, TranslationContext<?>> contextMap;
    88     /** current translation context (visitor argument) */
    89     private TranslationContext<?> context;
    91     /** info about the current class being processed */
    92     private KlassInfo kInfo;
    94     /** dump statistics about lambda code generation */
    95     private boolean dumpLambdaToMethodStats;
    97     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
    98     public static final int FLAG_SERIALIZABLE = 1 << 0;
   100     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
   101     public static final int FLAG_MARKERS = 1 << 1;
   103     private class KlassInfo {
   105         /**
   106          * list of methods to append
   107          */
   108         private ListBuffer<JCTree> appendedMethodList;
   110         /**
   111          * list of deserialization cases
   112          */
   113         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   115        /**
   116          * deserialize method symbol
   117          */
   118         private final MethodSymbol deserMethodSym;
   120         /**
   121          * deserialize method parameter symbol
   122          */
   123         private final VarSymbol deserParamSym;
   125         private KlassInfo(Symbol kSym) {
   126             appendedMethodList = ListBuffer.lb();
   127             deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
   128             long flags = PRIVATE | STATIC | SYNTHETIC;
   129             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
   130                     List.<Type>nil(), syms.methodClass);
   131             deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym);
   132             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
   133                     syms.serializedLambdaType, deserMethodSym);
   134         }
   136         private void addMethod(JCTree decl) {
   137             appendedMethodList = appendedMethodList.prepend(decl);
   138         }
   139     }
   141     // <editor-fold defaultstate="collapsed" desc="Instantiating">
   142     private static final Context.Key<LambdaToMethod> unlambdaKey =
   143             new Context.Key<LambdaToMethod>();
   145     public static LambdaToMethod instance(Context context) {
   146         LambdaToMethod instance = context.get(unlambdaKey);
   147         if (instance == null) {
   148             instance = new LambdaToMethod(context);
   149         }
   150         return instance;
   151     }
   153     private LambdaToMethod(Context context) {
   154         diags = JCDiagnostic.Factory.instance(context);
   155         log = Log.instance(context);
   156         lower = Lower.instance(context);
   157         names = Names.instance(context);
   158         syms = Symtab.instance(context);
   159         rs = Resolve.instance(context);
   160         make = TreeMaker.instance(context);
   161         types = Types.instance(context);
   162         transTypes = TransTypes.instance(context);
   163         analyzer = new LambdaAnalyzerPreprocessor();
   164         Options options = Options.instance(context);
   165         dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats");
   166     }
   167     // </editor-fold>
   169     // <editor-fold defaultstate="collapsed" desc="translate methods">
   170     @Override
   171     public <T extends JCTree> T translate(T tree) {
   172         TranslationContext<?> newContext = contextMap.get(tree);
   173         return translate(tree, newContext != null ? newContext : context);
   174     }
   176     <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
   177         TranslationContext<?> prevContext = context;
   178         try {
   179             context = newContext;
   180             return super.translate(tree);
   181         }
   182         finally {
   183             context = prevContext;
   184         }
   185     }
   187     <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
   188         ListBuffer<T> buf = ListBuffer.lb();
   189         for (T tree : trees) {
   190             buf.append(translate(tree, newContext));
   191         }
   192         return buf.toList();
   193     }
   195     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
   196         this.make = make;
   197         this.attrEnv = env;
   198         this.context = null;
   199         this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
   200         return translate(cdef);
   201     }
   202     // </editor-fold>
   204     // <editor-fold defaultstate="collapsed" desc="visitor methods">
   205     /**
   206      * Visit a class.
   207      * Maintain the translatedMethodList across nested classes.
   208      * Append the translatedMethodList to the class after it is translated.
   209      * @param tree
   210      */
   211     @Override
   212     public void visitClassDef(JCClassDecl tree) {
   213         if (tree.sym.owner.kind == PCK) {
   214             //analyze class
   215             tree = analyzer.analyzeAndPreprocessClass(tree);
   216         }
   217         KlassInfo prevKlassInfo = kInfo;
   218         try {
   219             kInfo = new KlassInfo(tree.sym);
   220             super.visitClassDef(tree);
   221             if (!kInfo.deserializeCases.isEmpty()) {
   222                 kInfo.addMethod(makeDeserializeMethod(tree.sym));
   223             }
   224             //add all translated instance methods here
   225             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
   226             tree.defs = tree.defs.appendList(newMethods);
   227             for (JCTree lambda : newMethods) {
   228                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
   229             }
   230             result = tree;
   231         } finally {
   232             kInfo = prevKlassInfo;
   233         }
   234     }
   236     /**
   237      * Translate a lambda into a method to be inserted into the class.
   238      * Then replace the lambda site with an invokedynamic call of to lambda
   239      * meta-factory, which will use the lambda method.
   240      * @param tree
   241      */
   242     @Override
   243     public void visitLambda(JCLambda tree) {
   244         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
   245         MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
   246         MethodType lambdaType = (MethodType) sym.type;
   248         {
   249             MethodSymbol owner = (MethodSymbol) localContext.owner;
   250             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   251             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   253             for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
   254                 if (tc.position.onLambda == tree) {
   255                     lambdaTypeAnnos.append(tc);
   256                 } else {
   257                     ownerTypeAnnos.append(tc);
   258                 }
   259             }
   260             if (lambdaTypeAnnos.nonEmpty()) {
   261                 owner.setTypeAttributes(ownerTypeAnnos.toList());
   262                 sym.setTypeAttributes(lambdaTypeAnnos.toList());
   263             }
   264         }
   266         //create the method declaration hoisting the lambda body
   267         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
   268                 sym.name,
   269                 make.QualIdent(lambdaType.getReturnType().tsym),
   270                 List.<JCTypeParameter>nil(),
   271                 localContext.syntheticParams,
   272                 lambdaType.getThrownTypes() == null ?
   273                     List.<JCExpression>nil() :
   274                     make.Types(lambdaType.getThrownTypes()),
   275                 null,
   276                 null);
   277         lambdaDecl.sym = sym;
   278         lambdaDecl.type = lambdaType;
   280         //translate lambda body
   281         //As the lambda body is translated, all references to lambda locals,
   282         //captured variables, enclosing members are adjusted accordingly
   283         //to refer to the static method parameters (rather than i.e. acessing to
   284         //captured members directly).
   285         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
   287         //Add the method to the list of methods to be added to this class.
   288         kInfo.addMethod(lambdaDecl);
   290         //now that we have generated a method for the lambda expression,
   291         //we can translate the lambda into a method reference pointing to the newly
   292         //created method.
   293         //
   294         //Note that we need to adjust the method handle so that it will match the
   295         //signature of the SAM descriptor - this means that the method reference
   296         //should be added the following synthetic arguments:
   297         //
   298         // * the "this" argument if it is an instance method
   299         // * enclosing locals captured by the lambda expression
   301         ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
   303         if (!sym.isStatic()) {
   304             syntheticInits.append(makeThis(
   305                     sym.owner.enclClass().asType(),
   306                     localContext.owner.enclClass()));
   307         }
   309         //add captured locals
   310         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
   311             if (fv != localContext.self) {
   312                 JCTree captured_local = make.Ident(fv).setType(fv.type);
   313                 syntheticInits.append((JCExpression) captured_local);
   314             }
   315         }
   317         //then, determine the arguments to the indy call
   318         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   320         //build a sam instance using an indy call to the meta-factory
   321         int refKind = referenceKind(sym);
   323         //convert to an invokedynamic call
   324         result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args);
   325     }
   327     private JCIdent makeThis(Type type, Symbol owner) {
   328         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
   329                 names._this,
   330                 type,
   331                 owner);
   332         return make.Ident(_this);
   333     }
   335     /**
   336      * Translate a method reference into an invokedynamic call to the
   337      * meta-factory.
   338      * @param tree
   339      */
   340     @Override
   341     public void visitReference(JCMemberReference tree) {
   342         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   344         //first determine the method symbol to be used to generate the sam instance
   345         //this is either the method reference symbol, or the bridged reference symbol
   346         Symbol refSym = localContext.needsBridge() ?
   347             localContext.bridgeSym :
   348             tree.sym;
   350         //build the bridge method, if needed
   351         if (localContext.needsBridge()) {
   352             bridgeMemberReference(tree, localContext);
   353         }
   355         //the qualifying expression is treated as a special captured arg
   356         JCExpression init;
   357         switch(tree.kind) {
   359             case IMPLICIT_INNER:    /** Inner :: new */
   360             case SUPER:             /** super :: instMethod */
   361                 init = makeThis(
   362                     localContext.owner.enclClass().asType(),
   363                     localContext.owner.enclClass());
   364                 break;
   366             case BOUND:             /** Expr :: instMethod */
   367                 init = tree.getQualifierExpression();
   368                 break;
   370             case UNBOUND:           /** Type :: instMethod */
   371             case STATIC:            /** Type :: staticMethod */
   372             case TOPLEVEL:          /** Top level :: new */
   373             case ARRAY_CTOR:        /** ArrayType :: new */
   374                 init = null;
   375                 break;
   377             default:
   378                 throw new InternalError("Should not have an invalid kind");
   379         }
   381         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
   384         //build a sam instance using an indy call to the meta-factory
   385         result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args);
   386     }
   388     /**
   389      * Translate identifiers within a lambda to the mapped identifier
   390      * @param tree
   391      */
   392     @Override
   393     public void visitIdent(JCIdent tree) {
   394         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
   395             super.visitIdent(tree);
   396         } else {
   397             LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
   398             if (lambdaContext.getSymbolMap(PARAM).containsKey(tree.sym)) {
   399                 Symbol translatedSym = lambdaContext.getSymbolMap(PARAM).get(tree.sym);
   400                 result = make.Ident(translatedSym).setType(tree.type);
   401                 translatedSym.setTypeAttributes(tree.sym.getRawTypeAttributes());
   402             } else if (lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   403                 Symbol translatedSym = lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
   404                 result = make.Ident(translatedSym).setType(tree.type);
   405                 translatedSym.setTypeAttributes(tree.sym.getRawTypeAttributes());
   406             } else if (lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   407                 Symbol translatedSym = lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   408                 result = make.Ident(translatedSym).setType(translatedSym.type);
   409                 translatedSym.setTypeAttributes(tree.sym.getRawTypeAttributes());
   410             } else if (lambdaContext.getSymbolMap(CAPTURED_VAR).containsKey(tree.sym)) {
   411                 Symbol translatedSym = lambdaContext.getSymbolMap(CAPTURED_VAR).get(tree.sym);
   412                 result = make.Ident(translatedSym).setType(tree.type);
   413             } else {
   414                 //access to untranslated symbols (i.e. compile-time constants,
   415                 //members defined inside the lambda body, etc.) )
   416                 super.visitIdent(tree);
   417             }
   418         }
   419     }
   421     @Override
   422     public void visitVarDef(JCVariableDecl tree) {
   423         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
   424         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   425             JCExpression init = translate(tree.init);
   426             result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
   427         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   428             JCExpression init = translate(tree.init);
   429             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   430             result = make.VarDef(xsym, init);
   431             // Replace the entered symbol for this variable
   432             Scope sc = tree.sym.owner.members();
   433             if (sc != null) {
   434                 sc.remove(tree.sym);
   435                 sc.enter(xsym);
   436             }
   437         } else {
   438             super.visitVarDef(tree);
   439         }
   440     }
   442     // </editor-fold>
   444     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   446     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   447         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   448                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   449                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   450     }
   452     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   453         Type restype = lambdaMethodDecl.type.getReturnType();
   454         boolean isLambda_void = expr.type.hasTag(VOID);
   455         boolean isTarget_void = restype.hasTag(VOID);
   456         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   457         if (isTarget_void) {
   458             //target is void:
   459             // BODY;
   460             JCStatement stat = make.Exec(expr);
   461             return make.Block(0, List.<JCStatement>of(stat));
   462         } else if (isLambda_void && isTarget_Void) {
   463             //void to Void conversion:
   464             // BODY; return null;
   465             ListBuffer<JCStatement> stats = ListBuffer.lb();
   466             stats.append(make.Exec(expr));
   467             stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   468             return make.Block(0, stats.toList());
   469         } else {
   470             //non-void to non-void conversion:
   471             // return (TYPE)BODY;
   472             JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   473             return make.Block(0, List.<JCStatement>of(make.Return(retExpr)));
   474         }
   475     }
   477     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   478         final Type restype = lambdaMethodDecl.type.getReturnType();
   479         final boolean isTarget_void = restype.hasTag(VOID);
   480         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   482         class LambdaBodyTranslator extends TreeTranslator {
   484             @Override
   485             public void visitClassDef(JCClassDecl tree) {
   486                 //do NOT recurse on any inner classes
   487                 result = tree;
   488             }
   490             @Override
   491             public void visitLambda(JCLambda tree) {
   492                 //do NOT recurse on any nested lambdas
   493                 result = tree;
   494             }
   496             @Override
   497             public void visitReturn(JCReturn tree) {
   498                 boolean isLambda_void = tree.expr == null;
   499                 if (isTarget_void && !isLambda_void) {
   500                     //Void to void conversion:
   501                     // { TYPE $loc = RET-EXPR; return; }
   502                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   503                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   504                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   505                 } else if (!isTarget_void || !isLambda_void) {
   506                     //non-void to non-void conversion:
   507                     // return (TYPE)RET-EXPR;
   508                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   509                     result = tree;
   510                 } else {
   511                     result = tree;
   512                 }
   514             }
   515         }
   517         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   518         if (completeNormally && isTarget_Void) {
   519             //there's no return statement and the lambda (possibly inferred)
   520             //return type is java.lang.Void; emit a synthetic return statement
   521             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   522         }
   523         return trans_block;
   524     }
   526     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   527         ListBuffer<JCCase> cases = ListBuffer.lb();
   528         ListBuffer<JCBreak> breaks = ListBuffer.lb();
   529         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   530             JCBreak br = make.Break(null);
   531             breaks.add(br);
   532             List<JCStatement> stmts = entry.getValue().append(br).toList();
   533             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   534         }
   535         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   536         for (JCBreak br : breaks) {
   537             br.target = sw;
   538         }
   539         JCBlock body = make.Block(0L, List.<JCStatement>of(
   540                 sw,
   541                 make.Throw(makeNewClass(
   542                     syms.illegalArgumentExceptionType,
   543                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   544         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   545                         names.deserializeLambda,
   546                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   547                         List.<JCTypeParameter>nil(),
   548                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   549                         List.<JCExpression>nil(),
   550                         body,
   551                         null);
   552         deser.sym = kInfo.deserMethodSym;
   553         deser.type = kInfo.deserMethodSym.type;
   554         //System.err.printf("DESER: '%s'\n", deser);
   555         return deser;
   556     }
   558     /** Make an attributed class instance creation expression.
   559      *  @param ctype    The class type.
   560      *  @param args     The constructor arguments.
   561      *  @param cons     The constructor symbol
   562      */
   563     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
   564         JCNewClass tree = make.NewClass(null,
   565             null, make.QualIdent(ctype.tsym), args, null);
   566         tree.constructor = cons;
   567         tree.type = ctype;
   568         return tree;
   569     }
   571     /** Make an attributed class instance creation expression.
   572      *  @param ctype    The class type.
   573      *  @param args     The constructor arguments.
   574      */
   575     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   576         return makeNewClass(ctype, args,
   577                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
   578      }
   580     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   581             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   582         String functionalInterfaceClass = classSig(targetType);
   583         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   584         String functionalInterfaceMethodSignature = methodSig(types.erasure(samSym.type));
   585         String implClass = classSig(types.erasure(refSym.owner.type));
   586         String implMethodName = refSym.getQualifiedName().toString();
   587         String implMethodSignature = methodSig(types.erasure(refSym.type));
   589         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   590         ListBuffer<JCExpression> serArgs = ListBuffer.lb();
   591         int i = 0;
   592         for (Type t : indyType.getParameterTypes()) {
   593             List<JCExpression> indexAsArg = ListBuffer.<JCExpression>lb().append(make.Literal(i)).toList();
   594             List<Type> argTypes = ListBuffer.<Type>lb().append(syms.intType).toList();
   595             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   596             ++i;
   597         }
   598         JCStatement stmt = make.If(
   599                 deserTest(deserTest(deserTest(deserTest(deserTest(
   600                     kindTest,
   601                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   602                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   603                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   604                     "getImplClass", implClass),
   605                     "getImplMethodSignature", implMethodSignature),
   606                 make.Return(makeIndyCall(
   607                     pos,
   608                     syms.lambdaMetafactory,
   609                     names.altMetaFactory,
   610                     staticArgs, indyType, serArgs.toList())),
   611                 null);
   612         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   613         if (stmts == null) {
   614             stmts = ListBuffer.lb();
   615             kInfo.deserializeCases.put(implMethodName, stmts);
   616         }
   617         /****
   618         System.err.printf("+++++++++++++++++\n");
   619         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   620         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   621         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   622         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   623         System.err.printf("*implClass: '%s'\n", implClass);
   624         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   625         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   626         ****/
   627         stmts.append(stmt);
   628     }
   630     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   631         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   632         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   633         testExpr.setType(syms.booleanType);
   634         return testExpr;
   635     }
   637     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   638         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   639         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   640         JCMethodInvocation eqtest = make.Apply(
   641                 List.<JCExpression>nil(),
   642                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   643                 List.<JCExpression>of(make.Literal(lit)));
   644         eqtest.setType(syms.booleanType);
   645         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   646         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   647         compound.setType(syms.booleanType);
   648         return compound;
   649     }
   651     private JCExpression deserGetter(String func, Type type) {
   652         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   653     }
   655     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   656         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   657         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   658         return make.Apply(
   659                     List.<JCExpression>nil(),
   660                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   661                     args).setType(type);
   662     }
   664     /**
   665      * Create new synthetic method with given flags, name, type, owner
   666      */
   667     private MethodSymbol makeSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   668         return new MethodSymbol(flags | SYNTHETIC, name, type, owner);
   669     }
   671     /**
   672      * Create new synthetic variable with given flags, name, type, owner
   673      */
   674     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   675         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   676     }
   678     /**
   679      * Create new synthetic variable with given flags, name, type, owner
   680      */
   681     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   682         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   683     }
   685     /**
   686      * Set varargsElement field on a given tree (must be either a new class tree
   687      * or a method call tree)
   688      */
   689     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   690         if (varargsElement != null) {
   691             switch (tree.getTag()) {
   692                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   693                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   694                 default: throw new AssertionError();
   695             }
   696         }
   697     }
   699     /**
   700      * Convert method/constructor arguments by inserting appropriate cast
   701      * as required by type-erasure - this is needed when bridging a lambda/method
   702      * reference, as the bridged signature might require downcast to be compatible
   703      * with the generated signature.
   704      */
   705     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   706        Assert.check(meth.kind == Kinds.MTH);
   707        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   708        if (varargsElement != null) {
   709            Assert.check((meth.flags() & VARARGS) != 0);
   710        }
   711        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   712     }
   714     // </editor-fold>
   716     /**
   717      * Generate an adapter method "bridge" for a method reference which cannot
   718      * be used directly.
   719      */
   720     private class MemberReferenceBridger {
   722         private final JCMemberReference tree;
   723         private final ReferenceTranslationContext localContext;
   724         private final ListBuffer<JCExpression> args = ListBuffer.lb();
   725         private final ListBuffer<JCVariableDecl> params = ListBuffer.lb();
   727         MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
   728             this.tree = tree;
   729             this.localContext = localContext;
   730         }
   732         /**
   733          * Generate the bridge
   734          */
   735         JCMethodDecl bridge() {
   736             int prevPos = make.pos;
   737             try {
   738                 make.at(tree);
   739                 Type samDesc = localContext.bridgedRefSig();
   740                 List<Type> samPTypes = samDesc.getParameterTypes();
   742                 //an extra argument is prepended to the signature of the bridge in case
   743                 //the member reference is an instance method reference (in which case
   744                 //the receiver expression is passed to the bridge itself).
   745                 Type recType = null;
   746                 switch (tree.kind) {
   747                     case IMPLICIT_INNER:
   748                         recType = tree.sym.owner.type.getEnclosingType();
   749                         break;
   750                     case BOUND:
   751                         recType = tree.getQualifierExpression().type;
   752                         break;
   753                     case UNBOUND:
   754                         recType = samPTypes.head;
   755                         samPTypes = samPTypes.tail;
   756                         break;
   757                 }
   759                 //generate the parameter list for the bridged member reference - the
   760                 //bridge signature will match the signature of the target sam descriptor
   762                 VarSymbol rcvr = (recType == null)
   763                         ? null
   764                         : addParameter("rec$", recType, false);
   766                 List<Type> refPTypes = tree.sym.type.getParameterTypes();
   767                 int refSize = refPTypes.size();
   768                 int samSize = samPTypes.size();
   769                 // Last parameter to copy from referenced method
   770                 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
   772                 List<Type> l = refPTypes;
   773                 // Use parameter types of the referenced method, excluding final var args
   774                 for (int i = 0; l.nonEmpty() && i < last; ++i) {
   775                     addParameter("x$" + i, l.head, true);
   776                     l = l.tail;
   777                 }
   778                 // Flatten out the var args
   779                 for (int i = last; i < samSize; ++i) {
   780                     addParameter("xva$" + i, tree.varargsElement, true);
   781                 }
   783                 //generate the bridge method declaration
   784                 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
   785                         localContext.bridgeSym.name,
   786                         make.QualIdent(samDesc.getReturnType().tsym),
   787                         List.<JCTypeParameter>nil(),
   788                         params.toList(),
   789                         tree.sym.type.getThrownTypes() == null
   790                         ? List.<JCExpression>nil()
   791                         : make.Types(tree.sym.type.getThrownTypes()),
   792                         null,
   793                         null);
   794                 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
   795                 bridgeDecl.type = localContext.bridgeSym.type =
   796                         types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
   798                 //bridge method body generation - this can be either a method call or a
   799                 //new instance creation expression, depending on the member reference kind
   800                 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
   801                         ? bridgeExpressionInvoke(makeReceiver(rcvr))
   802                         : bridgeExpressionNew();
   804                 //the body is either a return expression containing a method call,
   805                 //or the method call itself, depending on whether the return type of
   806                 //the bridge is non-void/void.
   807                 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
   809                 return bridgeDecl;
   810             } finally {
   811                 make.at(prevPos);
   812             }
   813         }
   814         //where
   815             private JCExpression makeReceiver(VarSymbol rcvr) {
   816                 if (rcvr == null) return null;
   817                 JCExpression rcvrExpr = make.Ident(rcvr);
   818                 Type rcvrType = tree.sym.enclClass().type;
   819                 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   820                     rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   821                 }
   822                 return rcvrExpr;
   823             }
   825         /**
   826          * determine the receiver of the bridged method call - the receiver can
   827          * be either the synthetic receiver parameter or a type qualifier; the
   828          * original qualifier expression is never used here, as it might refer
   829          * to symbols not available in the static context of the bridge
   830          */
   831         private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
   832             JCExpression qualifier =
   833                     tree.sym.isStatic() ?
   834                         make.Type(tree.sym.owner.type) :
   835                         (rcvr != null) ?
   836                             rcvr :
   837                             tree.getQualifierExpression();
   839             //create the qualifier expression
   840             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   841             select.sym = tree.sym;
   842             select.type = tree.sym.erasure(types);
   844             //create the method call expression
   845             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   846                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   847                     setType(tree.sym.erasure(types).getReturnType());
   849             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   850             setVarargsIfNeeded(apply, tree.varargsElement);
   851             return apply;
   852         }
   854         /**
   855          * the enclosing expression is either 'null' (no enclosing type) or set
   856          * to the first bridge synthetic parameter
   857          */
   858         private JCExpression bridgeExpressionNew() {
   859             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   860                 //create the array creation expression
   861                 JCNewArray newArr = make.NewArray(
   862                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   863                         List.of(make.Ident(params.first())),
   864                         null);
   865                 newArr.type = tree.getQualifierExpression().type;
   866                 return newArr;
   867             } else {
   868                 JCExpression encl = null;
   869                 switch (tree.kind) {
   870                     case UNBOUND:
   871                     case IMPLICIT_INNER:
   872                         encl = make.Ident(params.first());
   873                 }
   875                 //create the instance creation expression
   876                 JCNewClass newClass = make.NewClass(encl,
   877                         List.<JCExpression>nil(),
   878                         make.Type(tree.getQualifierExpression().type),
   879                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   880                         null);
   881                 newClass.constructor = tree.sym;
   882                 newClass.constructorType = tree.sym.erasure(types);
   883                 newClass.type = tree.getQualifierExpression().type;
   884                 setVarargsIfNeeded(newClass, tree.varargsElement);
   885                 return newClass;
   886             }
   887         }
   889         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   890             VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
   891             params.append(make.VarDef(vsym, null));
   892             if (genArg) {
   893                 args.append(make.Ident(vsym));
   894             }
   895             return vsym;
   896         }
   897     }
   899     /**
   900      * Bridges a member reference - this is needed when:
   901      * * Var args in the referenced method need to be flattened away
   902      * * super is used
   903      */
   904     private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
   905         kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
   906     }
   908     /**
   909      * Generate an indy method call to the meta factory
   910      */
   911     private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory,
   912             boolean isSerializable, int refKind, Symbol refSym, List<JCExpression> indy_args) {
   913         //determine the static bsm args
   914         Type mtype = types.erasure(tree.descriptorType);
   915         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   916         List<Object> staticArgs = List.<Object>of(
   917                 new Pool.MethodHandle(ClassFile.REF_invokeInterface,
   918                     types.findDescriptorSymbol(tree.type.tsym), types),
   919                 new Pool.MethodHandle(refKind, refSym, types),
   920                 new MethodType(mtype.getParameterTypes(),
   921                         mtype.getReturnType(),
   922                         mtype.getThrownTypes(),
   923                         syms.methodClass));
   925         //computed indy arg types
   926         ListBuffer<Type> indy_args_types = ListBuffer.lb();
   927         for (JCExpression arg : indy_args) {
   928             indy_args_types.append(arg.type);
   929         }
   931         //finally, compute the type of the indy call
   932         MethodType indyType = new MethodType(indy_args_types.toList(),
   933                 tree.type,
   934                 List.<Type>nil(),
   935                 syms.methodClass);
   937         Name metafactoryName = needsAltMetafactory ?
   938                 names.altMetaFactory : names.metaFactory;
   940         if (needsAltMetafactory) {
   941             ListBuffer<Object> markers = ListBuffer.lb();
   942             for (Symbol t : tree.targets.tail) {
   943                 if (t != syms.serializableType.tsym) {
   944                     markers.append(t);
   945                 }
   946             }
   947             int flags = isSerializable? FLAG_SERIALIZABLE : 0;
   948             boolean hasMarkers = markers.nonEmpty();
   949             flags |= hasMarkers ? FLAG_MARKERS : 0;
   950             staticArgs = staticArgs.append(flags);
   951             if (hasMarkers) {
   952                 staticArgs = staticArgs.append(markers.length());
   953                 staticArgs = staticArgs.appendList(markers.toList());
   954             }
   955             if (isSerializable) {
   956                 addDeserializationCase(refKind, refSym, tree.type, samSym,
   957                         tree, staticArgs, indyType);
   958             }
   959         }
   961         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
   962     }
   964     /**
   965      * Generate an indy method call with given name, type and static bootstrap
   966      * arguments types
   967      */
   968     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
   969             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
   970         int prevPos = make.pos;
   971         try {
   972             make.at(pos);
   973             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
   974                     syms.stringType,
   975                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
   977             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
   978                     bsmName, bsm_staticArgs, List.<Type>nil());
   980             DynamicMethodSymbol dynSym =
   981                     new DynamicMethodSymbol(names.lambda,
   982                                             syms.noSymbol,
   983                                             bsm.isStatic() ?
   984                                                 ClassFile.REF_invokeStatic :
   985                                                 ClassFile.REF_invokeVirtual,
   986                                             (MethodSymbol)bsm,
   987                                             indyType,
   988                                             staticArgs.toArray());
   990             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
   991             qualifier.sym = dynSym;
   992             qualifier.type = indyType.getReturnType();
   994             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
   995             proxyCall.type = indyType.getReturnType();
   996             return proxyCall;
   997         } finally {
   998             make.at(prevPos);
   999         }
  1001     //where
  1002     private List<Type> bsmStaticArgToTypes(List<Object> args) {
  1003         ListBuffer<Type> argtypes = ListBuffer.lb();
  1004         for (Object arg : args) {
  1005             argtypes.append(bsmStaticArgToType(arg));
  1007         return argtypes.toList();
  1010     private Type bsmStaticArgToType(Object arg) {
  1011         Assert.checkNonNull(arg);
  1012         if (arg instanceof ClassSymbol) {
  1013             return syms.classType;
  1014         } else if (arg instanceof Integer) {
  1015             return syms.intType;
  1016         } else if (arg instanceof Long) {
  1017             return syms.longType;
  1018         } else if (arg instanceof Float) {
  1019             return syms.floatType;
  1020         } else if (arg instanceof Double) {
  1021             return syms.doubleType;
  1022         } else if (arg instanceof String) {
  1023             return syms.stringType;
  1024         } else if (arg instanceof Pool.MethodHandle) {
  1025             return syms.methodHandleType;
  1026         } else if (arg instanceof MethodType) {
  1027             return syms.methodTypeType;
  1028         } else {
  1029             Assert.error("bad static arg " + arg.getClass());
  1030             return null;
  1034     /**
  1035      * Get the opcode associated with this method reference
  1036      */
  1037     private int referenceKind(Symbol refSym) {
  1038         if (refSym.isConstructor()) {
  1039             return ClassFile.REF_newInvokeSpecial;
  1040         } else {
  1041             if (refSym.isStatic()) {
  1042                 return ClassFile.REF_invokeStatic;
  1043             } else if (refSym.enclClass().isInterface()) {
  1044                 return ClassFile.REF_invokeInterface;
  1045             } else {
  1046                 return (refSym.flags() & PRIVATE) != 0 ?
  1047                         ClassFile.REF_invokeSpecial :
  1048                         ClassFile.REF_invokeVirtual;
  1053     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1054     /**
  1055      * This visitor collects information about translation of a lambda expression.
  1056      * More specifically, it keeps track of the enclosing contexts and captured locals
  1057      * accessed by the lambda being translated (as well as other useful info).
  1058      * It also translates away problems for LambdaToMethod.
  1059      */
  1060     class LambdaAnalyzerPreprocessor extends TreeTranslator {
  1062         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1063         private List<Frame> frameStack;
  1065         /**
  1066          * keep the count of lambda expression (used to generate unambiguous
  1067          * names)
  1068          */
  1069         private int lambdaCount = 0;
  1071         /**
  1072          * keep the count of lambda expression defined in given context (used to
  1073          * generate unambiguous names for serializable lambdas)
  1074          */
  1075         private Map<String, Integer> serializableLambdaCounts =
  1076                 new HashMap<String, Integer>();
  1078         private Map<Symbol, JCClassDecl> localClassDefs;
  1080         /**
  1081          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1082          * a static var init context
  1083          */
  1084         private Map<ClassSymbol, Symbol> clinits =
  1085                 new HashMap<ClassSymbol, Symbol>();
  1087         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
  1088             frameStack = List.nil();
  1089             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1090             return translate(tree);
  1093         @Override
  1094         public void visitBlock(JCBlock tree) {
  1095             List<Frame> prevStack = frameStack;
  1096             try {
  1097                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1098                     frameStack = frameStack.prepend(new Frame(tree));
  1100                 super.visitBlock(tree);
  1102             finally {
  1103                 frameStack = prevStack;
  1107         @Override
  1108         public void visitClassDef(JCClassDecl tree) {
  1109             List<Frame> prevStack = frameStack;
  1110             Map<String, Integer> prevSerializableLambdaCount =
  1111                     serializableLambdaCounts;
  1112             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1113             DiagnosticSource prevSource = log.currentSource();
  1114             try {
  1115                 log.useSource(tree.sym.sourcefile);
  1116                 serializableLambdaCounts = new HashMap<String, Integer>();
  1117                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1118                 if (tree.sym.owner.kind == MTH) {
  1119                     localClassDefs.put(tree.sym, tree);
  1121                 if (directlyEnclosingLambda() != null) {
  1122                     tree.sym.owner = owner();
  1123                     if (tree.sym.hasOuterInstance()) {
  1124                         //if a class is defined within a lambda, the lambda must capture
  1125                         //its enclosing instance (if any)
  1126                         TranslationContext<?> localContext = context();
  1127                         while (localContext != null) {
  1128                             if (localContext.tree.getTag() == LAMBDA) {
  1129                                 ((LambdaTranslationContext)localContext)
  1130                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1132                             localContext = localContext.prev;
  1136                 frameStack = frameStack.prepend(new Frame(tree));
  1137                 super.visitClassDef(tree);
  1139             finally {
  1140                 log.useSource(prevSource.getFile());
  1141                 frameStack = prevStack;
  1142                 serializableLambdaCounts = prevSerializableLambdaCount;
  1143                 clinits = prevClinits;
  1147         @Override
  1148         public void visitIdent(JCIdent tree) {
  1149             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1150                 if (tree.sym.kind == VAR &&
  1151                         tree.sym.owner.kind == MTH &&
  1152                         tree.type.constValue() == null) {
  1153                     TranslationContext<?> localContext = context();
  1154                     while (localContext != null) {
  1155                         if (localContext.tree.getTag() == LAMBDA) {
  1156                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1157                             if (block == null) break;
  1158                             ((LambdaTranslationContext)localContext)
  1159                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1161                         localContext = localContext.prev;
  1163                 } else if (tree.sym.owner.kind == TYP) {
  1164                     TranslationContext<?> localContext = context();
  1165                     while (localContext != null) {
  1166                         if (localContext.tree.hasTag(LAMBDA)) {
  1167                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1168                             if (block == null) break;
  1169                             switch (block.getTag()) {
  1170                                 case CLASSDEF:
  1171                                     JCClassDecl cdecl = (JCClassDecl)block;
  1172                                     ((LambdaTranslationContext)localContext)
  1173                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1174                                     break;
  1175                                 default:
  1176                                     Assert.error("bad block kind");
  1179                         localContext = localContext.prev;
  1183             super.visitIdent(tree);
  1186         @Override
  1187         public void visitLambda(JCLambda tree) {
  1188             List<Frame> prevStack = frameStack;
  1189             try {
  1190                 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
  1191                 frameStack = frameStack.prepend(new Frame(tree));
  1192                 for (JCVariableDecl param : tree.params) {
  1193                     context.addSymbol(param.sym, PARAM);
  1194                     frameStack.head.addLocal(param.sym);
  1196                 contextMap.put(tree, context);
  1197                 super.visitLambda(tree);
  1198                 context.complete();
  1200             finally {
  1201                 frameStack = prevStack;
  1205         @Override
  1206         public void visitMethodDef(JCMethodDecl tree) {
  1207             List<Frame> prevStack = frameStack;
  1208             try {
  1209                 frameStack = frameStack.prepend(new Frame(tree));
  1210                 super.visitMethodDef(tree);
  1212             finally {
  1213                 frameStack = prevStack;
  1217         @Override
  1218         public void visitNewClass(JCNewClass tree) {
  1219             if (lambdaNewClassFilter(context(), tree)) {
  1220                 TranslationContext<?> localContext = context();
  1221                 while (localContext != null) {
  1222                     if (localContext.tree.getTag() == LAMBDA) {
  1223                         ((LambdaTranslationContext)localContext)
  1224                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1226                     localContext = localContext.prev;
  1229             if (context() != null && tree.type.tsym.owner.kind == MTH) {
  1230                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1231                 captureLocalClassDefs(tree.type.tsym, lambdaContext);
  1233             super.visitNewClass(tree);
  1235         //where
  1236             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1237                 JCClassDecl localCDef = localClassDefs.get(csym);
  1238                 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
  1239                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1240                         @Override
  1241                         void addFreeVars(ClassSymbol c) {
  1242                             captureLocalClassDefs(c, lambdaContext);
  1244                         @Override
  1245                         void visitSymbol(Symbol sym) {
  1246                             if (sym.kind == VAR &&
  1247                                     sym.owner.kind == MTH &&
  1248                                     ((VarSymbol)sym).getConstValue() == null) {
  1249                                 TranslationContext<?> localContext = context();
  1250                                 while (localContext != null) {
  1251                                     if (localContext.tree.getTag() == LAMBDA) {
  1252                                         JCTree block = capturedDecl(localContext.depth, sym);
  1253                                         if (block == null) break;
  1254                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1256                                     localContext = localContext.prev;
  1260                     };
  1261                     fvc.scan(localCDef);
  1265         /**
  1266          * Method references to local class constructors, may, if the local
  1267          * class references local variables, have implicit constructor
  1268          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1269          * information added in the LambdaToMethod pass will have the wrong
  1270          * signature. Hooks between Lower and LambdaToMethod have been added to
  1271          * handle normal "new" in this case. This visitor converts potentially
  1272          * effected method references into a lambda containing a normal "new" of
  1273          * the class.
  1275          * @param tree
  1276          */
  1277         @Override
  1278         public void visitReference(JCMemberReference tree) {
  1279             if (tree.getMode() == ReferenceMode.NEW
  1280                     && tree.kind != ReferenceKind.ARRAY_CTOR
  1281                     && tree.sym.owner.isLocal()) {
  1282                 MethodSymbol consSym = (MethodSymbol) tree.sym;
  1283                 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
  1284                 Type classType = consSym.owner.type;
  1286                 // Build lambda parameters
  1287                 // partially cloned from TreeMaker.Params until 8014021 is fixed
  1288                 Symbol owner = owner();
  1289                 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
  1290                 int i = 0;
  1291                 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
  1292                     paramBuff.append(make.Param(make.paramName(i++), l.head, owner));
  1294                 List<JCVariableDecl> params = paramBuff.toList();
  1296                 // Make new-class call
  1297                 JCNewClass nc = makeNewClass(classType, make.Idents(params));
  1298                 nc.pos = tree.pos;
  1300                 // Make lambda holding the new-class call
  1301                 JCLambda slam = make.Lambda(params, nc);
  1302                 slam.descriptorType = tree.descriptorType;
  1303                 slam.targets = tree.targets;
  1304                 slam.type = tree.type;
  1305                 slam.pos = tree.pos;
  1307                 // Now it is a lambda, process as such
  1308                 visitLambda(slam);
  1309             } else {
  1310                 super.visitReference(tree);
  1311                 contextMap.put(tree, makeReferenceContext(tree));
  1315         @Override
  1316         public void visitSelect(JCFieldAccess tree) {
  1317             if (context() != null && tree.sym.kind == VAR &&
  1318                         (tree.sym.name == names._this ||
  1319                          tree.sym.name == names._super)) {
  1320                 // A select of this or super means, if we are in a lambda,
  1321                 // we much have an instance context
  1322                 TranslationContext<?> localContext = context();
  1323                 while (localContext != null) {
  1324                     if (localContext.tree.hasTag(LAMBDA)) {
  1325                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1326                         if (clazz == null) break;
  1327                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1329                     localContext = localContext.prev;
  1332             super.visitSelect(tree);
  1335         @Override
  1336         public void visitVarDef(JCVariableDecl tree) {
  1337             TranslationContext<?> context = context();
  1338             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1339                     (LambdaTranslationContext)context :
  1340                     null;
  1341             if (ltc != null) {
  1342                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1343                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1345                 // Check for type variables (including as type arguments).
  1346                 // If they occur within class nested in a lambda, mark for erasure
  1347                 Type type = tree.sym.asType();
  1348                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1349                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1353             List<Frame> prevStack = frameStack;
  1354             try {
  1355                 if (tree.sym.owner.kind == MTH) {
  1356                     frameStack.head.addLocal(tree.sym);
  1358                 frameStack = frameStack.prepend(new Frame(tree));
  1359                 super.visitVarDef(tree);
  1361             finally {
  1362                 frameStack = prevStack;
  1366         private Name lambdaName() {
  1367             return names.lambda.append(names.fromString("" + lambdaCount++));
  1370         /**
  1371          * For a serializable lambda, generate a name which maximizes name
  1372          * stability across deserialization.
  1373          * @param owner
  1374          * @return Name to use for the synthetic lambda method name
  1375          */
  1376         private Name serializedLambdaName(Symbol owner) {
  1377             StringBuilder buf = new StringBuilder();
  1378             buf.append(names.lambda);
  1379             // Append the name of the method enclosing the lambda.
  1380             String methodName = owner.name.toString();
  1381             if (methodName.equals("<clinit>"))
  1382                 methodName = "static";
  1383             else if (methodName.equals("<init>"))
  1384                 methodName = "new";
  1385             buf.append(methodName);
  1386             buf.append('$');
  1387             // Append a hash of the enclosing method signature to differentiate
  1388             // overloaded enclosing methods.  For lambdas enclosed in lambdas,
  1389             // the generated lambda method will not have type yet, but the
  1390             // enclosing method's name will have been generated with this same
  1391             // method, so it will be unique and never be overloaded.
  1392             Assert.check(owner.type != null || directlyEnclosingLambda() != null);
  1393             if (owner.type != null) {
  1394                 int methTypeHash = methodSig(owner.type).hashCode();
  1395                 buf.append(Integer.toHexString(methTypeHash));
  1397             buf.append('$');
  1398             // The above appended name components may not be unique, append a
  1399             // count based on the above name components.
  1400             String temp = buf.toString();
  1401             Integer count = serializableLambdaCounts.get(temp);
  1402             if (count == null) {
  1403                 count = 0;
  1405             buf.append(count++);
  1406             serializableLambdaCounts.put(temp, count);
  1407             return names.fromString(buf.toString());
  1410         /**
  1411          * Return a valid owner given the current declaration stack
  1412          * (required to skip synthetic lambda symbols)
  1413          */
  1414         private Symbol owner() {
  1415             return owner(false);
  1418         @SuppressWarnings("fallthrough")
  1419         private Symbol owner(boolean skipLambda) {
  1420             List<Frame> frameStack2 = frameStack;
  1421             while (frameStack2.nonEmpty()) {
  1422                 switch (frameStack2.head.tree.getTag()) {
  1423                     case VARDEF:
  1424                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1425                             frameStack2 = frameStack2.tail;
  1426                             break;
  1428                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1429                         return initSym(cdecl.sym,
  1430                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1431                     case BLOCK:
  1432                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1433                         return initSym(cdecl2.sym,
  1434                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1435                     case CLASSDEF:
  1436                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1437                     case METHODDEF:
  1438                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1439                     case LAMBDA:
  1440                         if (!skipLambda)
  1441                             return ((LambdaTranslationContext)contextMap
  1442                                     .get(frameStack2.head.tree)).translatedSym;
  1443                     default:
  1444                         frameStack2 = frameStack2.tail;
  1447             Assert.error();
  1448             return null;
  1451         private Symbol initSym(ClassSymbol csym, long flags) {
  1452             boolean isStatic = (flags & STATIC) != 0;
  1453             if (isStatic) {
  1454                 //static clinits are generated in Gen - so we need to fake them
  1455                 Symbol clinit = clinits.get(csym);
  1456                 if (clinit == null) {
  1457                     clinit = makeSyntheticMethod(STATIC,
  1458                             names.clinit,
  1459                             new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
  1460                             csym);
  1461                     clinits.put(csym, clinit);
  1463                 return clinit;
  1464             } else {
  1465                 //get the first constructor and treat it as the instance init sym
  1466                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1467                     return s;
  1470             Assert.error("init not found");
  1471             return null;
  1474         private JCTree directlyEnclosingLambda() {
  1475             if (frameStack.isEmpty()) {
  1476                 return null;
  1478             List<Frame> frameStack2 = frameStack;
  1479             while (frameStack2.nonEmpty()) {
  1480                 switch (frameStack2.head.tree.getTag()) {
  1481                     case CLASSDEF:
  1482                     case METHODDEF:
  1483                         return null;
  1484                     case LAMBDA:
  1485                         return frameStack2.head.tree;
  1486                     default:
  1487                         frameStack2 = frameStack2.tail;
  1490             Assert.error();
  1491             return null;
  1494         private boolean inClassWithinLambda() {
  1495             if (frameStack.isEmpty()) {
  1496                 return false;
  1498             List<Frame> frameStack2 = frameStack;
  1499             boolean classFound = false;
  1500             while (frameStack2.nonEmpty()) {
  1501                 switch (frameStack2.head.tree.getTag()) {
  1502                     case LAMBDA:
  1503                         return classFound;
  1504                     case CLASSDEF:
  1505                         classFound = true;
  1506                         frameStack2 = frameStack2.tail;
  1507                         break;
  1508                     default:
  1509                         frameStack2 = frameStack2.tail;
  1512             // No lambda
  1513             return false;
  1516         /**
  1517          * Return the declaration corresponding to a symbol in the enclosing
  1518          * scope; the depth parameter is used to filter out symbols defined
  1519          * in nested scopes (which do not need to undergo capture).
  1520          */
  1521         private JCTree capturedDecl(int depth, Symbol sym) {
  1522             int currentDepth = frameStack.size() - 1;
  1523             for (Frame block : frameStack) {
  1524                 switch (block.tree.getTag()) {
  1525                     case CLASSDEF:
  1526                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1527                         if (sym.isMemberOf(clazz, types)) {
  1528                             return currentDepth > depth ? null : block.tree;
  1530                         break;
  1531                     case VARDEF:
  1532                         if (((JCVariableDecl)block.tree).sym == sym &&
  1533                                 sym.owner.kind == MTH) { //only locals are captured
  1534                             return currentDepth > depth ? null : block.tree;
  1536                         break;
  1537                     case BLOCK:
  1538                     case METHODDEF:
  1539                     case LAMBDA:
  1540                         if (block.locals != null && block.locals.contains(sym)) {
  1541                             return currentDepth > depth ? null : block.tree;
  1543                         break;
  1544                     default:
  1545                         Assert.error("bad decl kind " + block.tree.getTag());
  1547                 currentDepth--;
  1549             return null;
  1552         private TranslationContext<?> context() {
  1553             for (Frame frame : frameStack) {
  1554                 TranslationContext<?> context = contextMap.get(frame.tree);
  1555                 if (context != null) {
  1556                     return context;
  1559             return null;
  1562         /**
  1563          *  This is used to filter out those identifiers that needs to be adjusted
  1564          *  when translating away lambda expressions
  1565          */
  1566         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1567             return (sym.kind == VAR || sym.kind == MTH)
  1568                     && !sym.isStatic()
  1569                     && sym.name != names.init;
  1572         /**
  1573          * This is used to filter out those new class expressions that need to
  1574          * be qualified with an enclosing tree
  1575          */
  1576         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1577             if (context != null
  1578                     && tree.encl == null
  1579                     && tree.def == null
  1580                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1581                 Type encl = tree.type.getEnclosingType();
  1582                 Type current = context.owner.enclClass().type;
  1583                 while (!current.hasTag(NONE)) {
  1584                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1585                         return true;
  1587                     current = current.getEnclosingType();
  1589                 return false;
  1590             } else {
  1591                 return false;
  1595         private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
  1596             return new LambdaTranslationContext(tree);
  1599         private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
  1600             return new ReferenceTranslationContext(tree);
  1603         private class Frame {
  1604             final JCTree tree;
  1605             List<Symbol> locals;
  1607             public Frame(JCTree tree) {
  1608                 this.tree = tree;
  1611             void addLocal(Symbol sym) {
  1612                 if (locals == null) {
  1613                     locals = List.nil();
  1615                 locals = locals.prepend(sym);
  1619         /**
  1620          * This class is used to store important information regarding translation of
  1621          * lambda expression/method references (see subclasses).
  1622          */
  1623         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1625             /** the underlying (untranslated) tree */
  1626             T tree;
  1628             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1629             Symbol owner;
  1631             /** the depth of this lambda expression in the frame stack */
  1632             int depth;
  1634             /** the enclosing translation context (set for nested lambdas/mref) */
  1635             TranslationContext<?> prev;
  1637             TranslationContext(T tree) {
  1638                 this.tree = tree;
  1639                 this.owner = owner();
  1640                 this.depth = frameStack.size() - 1;
  1641                 this.prev = context();
  1644             /** does this functional expression need to be created using alternate metafactory? */
  1645             boolean needsAltMetafactory() {
  1646                 return (tree.targets.length() > 1 ||
  1647                         isSerializable());
  1650             /** does this functional expression require serialization support? */
  1651             boolean isSerializable() {
  1652                 for (Symbol target : tree.targets) {
  1653                     if (types.asSuper(target.type, syms.serializableType.tsym) != null) {
  1654                         return true;
  1657                 return false;
  1661         /**
  1662          * This class retains all the useful information about a lambda expression;
  1663          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1664          * and the used by the main translation routines in order to adjust references
  1665          * to captured locals/members, etc.
  1666          */
  1667         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1669             /** variable in the enclosing context to which this lambda is assigned */
  1670             Symbol self;
  1672             /** map from original to translated lambda parameters */
  1673             Map<Symbol, Symbol> lambdaParams = new LinkedHashMap<Symbol, Symbol>();
  1675             /** map from original to translated lambda locals */
  1676             Map<Symbol, Symbol> lambdaLocals = new LinkedHashMap<Symbol, Symbol>();
  1678             /** map from variables in enclosing scope to translated synthetic parameters */
  1679             Map<Symbol, Symbol> capturedLocals  = new LinkedHashMap<Symbol, Symbol>();
  1681             /** map from class symbols to translated synthetic parameters (for captured member access) */
  1682             Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>();
  1684             /** map from original to translated lambda locals */
  1685             Map<Symbol, Symbol> typeVars = new LinkedHashMap<Symbol, Symbol>();
  1687             /** the synthetic symbol for the method hoisting the translated lambda */
  1688             Symbol translatedSym;
  1690             List<JCVariableDecl> syntheticParams;
  1692             LambdaTranslationContext(JCLambda tree) {
  1693                 super(tree);
  1694                 Frame frame = frameStack.head;
  1695                 if (frame.tree.hasTag(VARDEF)) {
  1696                     self = ((JCVariableDecl)frame.tree).sym;
  1698                 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName();
  1699                 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass());
  1700                 if (dumpLambdaToMethodStats) {
  1701                     log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym);
  1705             /**
  1706              * Translate a symbol of a given kind into something suitable for the
  1707              * synthetic lambda body
  1708              */
  1709             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1710                 Symbol ret;
  1711                 switch (skind) {
  1712                     case CAPTURED_THIS:
  1713                         ret = sym;  // self represented
  1714                         break;
  1715                     case TYPE_VAR:
  1716                         // Just erase the type var
  1717                         ret = new VarSymbol(sym.flags(), name,
  1718                                 types.erasure(sym.type), sym.owner);
  1719                         break;
  1720                     case CAPTURED_VAR:
  1721                         ret = new VarSymbol(SYNTHETIC | FINAL, name, types.erasure(sym.type), translatedSym) {
  1722                             @Override
  1723                             public Symbol baseSymbol() {
  1724                                 //keep mapping with original captured symbol
  1725                                 return sym;
  1727                         };
  1728                         break;
  1729                     default:
  1730                         ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1732                 if (ret != sym) {
  1733                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1734                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1736                 return ret;
  1739             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1740                 Map<Symbol, Symbol> transMap = null;
  1741                 Name preferredName;
  1742                 switch (skind) {
  1743                     case CAPTURED_THIS:
  1744                         transMap = capturedThis;
  1745                         preferredName = names.fromString("encl$" + capturedThis.size());
  1746                         break;
  1747                     case CAPTURED_VAR:
  1748                         transMap = capturedLocals;
  1749                         preferredName = names.fromString("cap$" + capturedLocals.size());
  1750                         break;
  1751                     case LOCAL_VAR:
  1752                         transMap = lambdaLocals;
  1753                         preferredName = sym.name;
  1754                         break;
  1755                     case PARAM:
  1756                         transMap = lambdaParams;
  1757                         preferredName = sym.name;
  1758                         break;
  1759                     case TYPE_VAR:
  1760                         transMap = typeVars;
  1761                         preferredName = sym.name;
  1762                         break;
  1763                     default: throw new AssertionError();
  1765                 if (!transMap.containsKey(sym)) {
  1766                     transMap.put(sym, translate(preferredName, sym, skind));
  1770             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind... skinds) {
  1771                 LinkedHashMap<Symbol, Symbol> translationMap = new LinkedHashMap<Symbol, Symbol>();
  1772                 for (LambdaSymbolKind skind : skinds) {
  1773                     switch (skind) {
  1774                         case CAPTURED_THIS:
  1775                             translationMap.putAll(capturedThis);
  1776                             break;
  1777                         case CAPTURED_VAR:
  1778                             translationMap.putAll(capturedLocals);
  1779                             break;
  1780                         case LOCAL_VAR:
  1781                             translationMap.putAll(lambdaLocals);
  1782                             break;
  1783                         case PARAM:
  1784                             translationMap.putAll(lambdaParams);
  1785                             break;
  1786                         case TYPE_VAR:
  1787                             translationMap.putAll(typeVars);
  1788                             break;
  1789                         default: throw new AssertionError();
  1792                 return translationMap;
  1795             /**
  1796              * The translatedSym is not complete/accurate until the analysis is
  1797              * finished.  Once the analysis is finished, the translatedSym is
  1798              * "completed" -- updated with type information, access modifiers,
  1799              * and full parameter list.
  1800              */
  1801             void complete() {
  1802                 if (syntheticParams != null) {
  1803                     return;
  1805                 boolean inInterface = translatedSym.owner.isInterface();
  1806                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1808                 // If instance access isn't needed, make it static.
  1809                 // Interface instance methods must be default methods.
  1810                 // Awaiting VM channges, default methods are public
  1811                 translatedSym.flags_field = SYNTHETIC |
  1812                         ((inInterface && thisReferenced)? PUBLIC : PRIVATE) |
  1813                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  1815                 //compute synthetic params
  1816                 ListBuffer<JCVariableDecl> params = ListBuffer.lb();
  1818                 // The signature of the method is augmented with the following
  1819                 // synthetic parameters:
  1820                 //
  1821                 // 1) reference to enclosing contexts captured by the lambda expression
  1822                 // 2) enclosing locals captured by the lambda expression
  1823                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR, PARAM).values()) {
  1824                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1827                 syntheticParams = params.toList();
  1829                 //prepend synthetic args to translated lambda method signature
  1830                 translatedSym.type = types.createMethodTypeWithParameters(
  1831                         generatedLambdaSig(),
  1832                         TreeInfo.types(syntheticParams));
  1835             Type generatedLambdaSig() {
  1836                 return types.erasure(tree.descriptorType);
  1840         /**
  1841          * This class retains all the useful information about a method reference;
  1842          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1843          * and the used by the main translation routines in order to adjust method
  1844          * references (i.e. in case a bridge is needed)
  1845          */
  1846         private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  1848             final boolean isSuper;
  1849             final Symbol bridgeSym;
  1851             ReferenceTranslationContext(JCMemberReference tree) {
  1852                 super(tree);
  1853                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  1854                 this.bridgeSym = needsBridge()
  1855                         ? makeSyntheticMethod(isSuper ? 0 : STATIC,
  1856                                               lambdaName().append(names.fromString("$bridge")), null,
  1857                                               owner.enclClass())
  1858                         : null;
  1859                 if (dumpLambdaToMethodStats) {
  1860                     String key = bridgeSym == null ?
  1861                             "mref.stat" : "mref.stat.1";
  1862                     log.note(tree, key, needsAltMetafactory(), bridgeSym);
  1866             /**
  1867              * Get the opcode associated with this method reference
  1868              */
  1869             int referenceKind() {
  1870                 return LambdaToMethod.this.referenceKind(needsBridge() ? bridgeSym : tree.sym);
  1873             boolean needsVarArgsConversion() {
  1874                 return tree.varargsElement != null;
  1877             /**
  1878              * @return Is this an array operation like clone()
  1879              */
  1880             boolean isArrayOp() {
  1881                 return tree.sym.owner == syms.arrayClass;
  1884             boolean isPrivateConstructor() {
  1885                 //hack needed to workaround 292 bug (8005122)
  1886                 //when 292 issue is fixed we should simply remove this
  1887                 return tree.sym.name == names.init &&
  1888                         (tree.sym.flags() & PRIVATE) != 0;
  1891             boolean receiverAccessible() {
  1892                 //hack needed to workaround 292 bug (7087658)
  1893                 //when 292 issue is fixed we should remove this and change the backend
  1894                 //code to always generate a method handle to an accessible method
  1895                 return tree.ownerAccessible;
  1898             /**
  1899              * Does this reference needs a bridge (i.e. var args need to be
  1900              * expanded or "super" is used)
  1901              */
  1902             final boolean needsBridge() {
  1903                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  1904                         isPrivateConstructor() || !receiverAccessible();
  1907             Type generatedRefSig() {
  1908                 return types.erasure(tree.sym.type);
  1911             Type bridgedRefSig() {
  1912                 return types.erasure(types.findDescriptorSymbol(tree.targets.head).type);
  1916     // </editor-fold>
  1918     enum LambdaSymbolKind {
  1919         CAPTURED_VAR,
  1920         CAPTURED_THIS,
  1921         LOCAL_VAR,
  1922         PARAM,
  1923         TYPE_VAR;
  1926     /**
  1927      * ****************************************************************
  1928      * Signature Generation
  1929      * ****************************************************************
  1930      */
  1932     private String methodSig(Type type) {
  1933         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1934         sg.assembleSig(type);
  1935         return sg.toString();
  1938     private String classSig(Type type) {
  1939         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1940         sg.assembleClassSig(type);
  1941         return sg.toString();
  1944     /**
  1945      * Signature Generation
  1946      */
  1947     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  1949         /**
  1950          * An output buffer for type signatures.
  1951          */
  1952         StringBuilder sb = new StringBuilder();
  1954         L2MSignatureGenerator() {
  1955             super(types);
  1958         @Override
  1959         protected void append(char ch) {
  1960             sb.append(ch);
  1963         @Override
  1964         protected void append(byte[] ba) {
  1965             sb.append(new String(ba));
  1968         @Override
  1969         protected void append(Name name) {
  1970             sb.append(name.toString());
  1973         @Override
  1974         public String toString() {
  1975             return sb.toString();

mercurial