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

Tue, 18 Jun 2013 19:02:48 +0100

author
vromero
date
Tue, 18 Jun 2013 19:02:48 +0100
changeset 1826
9851071b551a
parent 1824
455be95bd1b5
child 1843
be62183f938a
permissions
-rw-r--r--

8016267: javac, TypeTag refactoring has provoked performance issues
Reviewed-by: jjg

     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     /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
   104     public static final int FLAG_BRIDGES = 1 << 2;
   106     private class KlassInfo {
   108         /**
   109          * list of methods to append
   110          */
   111         private ListBuffer<JCTree> appendedMethodList;
   113         /**
   114          * list of deserialization cases
   115          */
   116         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   118        /**
   119          * deserialize method symbol
   120          */
   121         private final MethodSymbol deserMethodSym;
   123         /**
   124          * deserialize method parameter symbol
   125          */
   126         private final VarSymbol deserParamSym;
   128         private KlassInfo(Symbol kSym) {
   129             appendedMethodList = ListBuffer.lb();
   130             deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
   131             long flags = PRIVATE | STATIC | SYNTHETIC;
   132             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
   133                     List.<Type>nil(), syms.methodClass);
   134             deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym);
   135             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
   136                     syms.serializedLambdaType, deserMethodSym);
   137         }
   139         private void addMethod(JCTree decl) {
   140             appendedMethodList = appendedMethodList.prepend(decl);
   141         }
   142     }
   144     // <editor-fold defaultstate="collapsed" desc="Instantiating">
   145     private static final Context.Key<LambdaToMethod> unlambdaKey =
   146             new Context.Key<LambdaToMethod>();
   148     public static LambdaToMethod instance(Context context) {
   149         LambdaToMethod instance = context.get(unlambdaKey);
   150         if (instance == null) {
   151             instance = new LambdaToMethod(context);
   152         }
   153         return instance;
   154     }
   156     private LambdaToMethod(Context context) {
   157         diags = JCDiagnostic.Factory.instance(context);
   158         log = Log.instance(context);
   159         lower = Lower.instance(context);
   160         names = Names.instance(context);
   161         syms = Symtab.instance(context);
   162         rs = Resolve.instance(context);
   163         make = TreeMaker.instance(context);
   164         types = Types.instance(context);
   165         transTypes = TransTypes.instance(context);
   166         analyzer = new LambdaAnalyzerPreprocessor();
   167         Options options = Options.instance(context);
   168         dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats");
   169     }
   170     // </editor-fold>
   172     // <editor-fold defaultstate="collapsed" desc="translate methods">
   173     @Override
   174     public <T extends JCTree> T translate(T tree) {
   175         TranslationContext<?> newContext = contextMap.get(tree);
   176         return translate(tree, newContext != null ? newContext : context);
   177     }
   179     <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
   180         TranslationContext<?> prevContext = context;
   181         try {
   182             context = newContext;
   183             return super.translate(tree);
   184         }
   185         finally {
   186             context = prevContext;
   187         }
   188     }
   190     <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
   191         ListBuffer<T> buf = ListBuffer.lb();
   192         for (T tree : trees) {
   193             buf.append(translate(tree, newContext));
   194         }
   195         return buf.toList();
   196     }
   198     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
   199         this.make = make;
   200         this.attrEnv = env;
   201         this.context = null;
   202         this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
   203         return translate(cdef);
   204     }
   205     // </editor-fold>
   207     // <editor-fold defaultstate="collapsed" desc="visitor methods">
   208     /**
   209      * Visit a class.
   210      * Maintain the translatedMethodList across nested classes.
   211      * Append the translatedMethodList to the class after it is translated.
   212      * @param tree
   213      */
   214     @Override
   215     public void visitClassDef(JCClassDecl tree) {
   216         if (tree.sym.owner.kind == PCK) {
   217             //analyze class
   218             tree = analyzer.analyzeAndPreprocessClass(tree);
   219         }
   220         KlassInfo prevKlassInfo = kInfo;
   221         try {
   222             kInfo = new KlassInfo(tree.sym);
   223             super.visitClassDef(tree);
   224             if (!kInfo.deserializeCases.isEmpty()) {
   225                 kInfo.addMethod(makeDeserializeMethod(tree.sym));
   226             }
   227             //add all translated instance methods here
   228             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
   229             tree.defs = tree.defs.appendList(newMethods);
   230             for (JCTree lambda : newMethods) {
   231                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
   232             }
   233             result = tree;
   234         } finally {
   235             kInfo = prevKlassInfo;
   236         }
   237     }
   239     /**
   240      * Translate a lambda into a method to be inserted into the class.
   241      * Then replace the lambda site with an invokedynamic call of to lambda
   242      * meta-factory, which will use the lambda method.
   243      * @param tree
   244      */
   245     @Override
   246     public void visitLambda(JCLambda tree) {
   247         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
   248         MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
   249         MethodType lambdaType = (MethodType) sym.type;
   251         {
   252             MethodSymbol owner = (MethodSymbol) localContext.owner;
   253             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   254             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
   256             for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
   257                 if (tc.position.onLambda == tree) {
   258                     lambdaTypeAnnos.append(tc);
   259                 } else {
   260                     ownerTypeAnnos.append(tc);
   261                 }
   262             }
   263             if (lambdaTypeAnnos.nonEmpty()) {
   264                 owner.setTypeAttributes(ownerTypeAnnos.toList());
   265                 sym.setTypeAttributes(lambdaTypeAnnos.toList());
   266             }
   267         }
   269         //create the method declaration hoisting the lambda body
   270         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
   271                 sym.name,
   272                 make.QualIdent(lambdaType.getReturnType().tsym),
   273                 List.<JCTypeParameter>nil(),
   274                 localContext.syntheticParams,
   275                 lambdaType.getThrownTypes() == null ?
   276                     List.<JCExpression>nil() :
   277                     make.Types(lambdaType.getThrownTypes()),
   278                 null,
   279                 null);
   280         lambdaDecl.sym = sym;
   281         lambdaDecl.type = lambdaType;
   283         //translate lambda body
   284         //As the lambda body is translated, all references to lambda locals,
   285         //captured variables, enclosing members are adjusted accordingly
   286         //to refer to the static method parameters (rather than i.e. acessing to
   287         //captured members directly).
   288         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
   290         //Add the method to the list of methods to be added to this class.
   291         kInfo.addMethod(lambdaDecl);
   293         //now that we have generated a method for the lambda expression,
   294         //we can translate the lambda into a method reference pointing to the newly
   295         //created method.
   296         //
   297         //Note that we need to adjust the method handle so that it will match the
   298         //signature of the SAM descriptor - this means that the method reference
   299         //should be added the following synthetic arguments:
   300         //
   301         // * the "this" argument if it is an instance method
   302         // * enclosing locals captured by the lambda expression
   304         ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
   306         if (!sym.isStatic()) {
   307             syntheticInits.append(makeThis(
   308                     sym.owner.enclClass().asType(),
   309                     localContext.owner.enclClass()));
   310         }
   312         //add captured locals
   313         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
   314             if (fv != localContext.self) {
   315                 JCTree captured_local = make.Ident(fv).setType(fv.type);
   316                 syntheticInits.append((JCExpression) captured_local);
   317             }
   318         }
   320         //then, determine the arguments to the indy call
   321         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   323         //build a sam instance using an indy call to the meta-factory
   324         int refKind = referenceKind(sym);
   326         //convert to an invokedynamic call
   327         result = makeMetaFactoryIndyCall(context, refKind, sym, indy_args);
   328     }
   330     private JCIdent makeThis(Type type, Symbol owner) {
   331         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
   332                 names._this,
   333                 type,
   334                 owner);
   335         return make.Ident(_this);
   336     }
   338     /**
   339      * Translate a method reference into an invokedynamic call to the
   340      * meta-factory.
   341      * @param tree
   342      */
   343     @Override
   344     public void visitReference(JCMemberReference tree) {
   345         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   347         //first determine the method symbol to be used to generate the sam instance
   348         //this is either the method reference symbol, or the bridged reference symbol
   349         Symbol refSym = localContext.needsBridge() ?
   350             localContext.bridgeSym :
   351             tree.sym;
   353         //build the bridge method, if needed
   354         if (localContext.needsBridge()) {
   355             bridgeMemberReference(tree, localContext);
   356         }
   358         //the qualifying expression is treated as a special captured arg
   359         JCExpression init;
   360         switch(tree.kind) {
   362             case IMPLICIT_INNER:    /** Inner :: new */
   363             case SUPER:             /** super :: instMethod */
   364                 init = makeThis(
   365                     localContext.owner.enclClass().asType(),
   366                     localContext.owner.enclClass());
   367                 break;
   369             case BOUND:             /** Expr :: instMethod */
   370                 init = tree.getQualifierExpression();
   371                 break;
   373             case UNBOUND:           /** Type :: instMethod */
   374             case STATIC:            /** Type :: staticMethod */
   375             case TOPLEVEL:          /** Top level :: new */
   376             case ARRAY_CTOR:        /** ArrayType :: new */
   377                 init = null;
   378                 break;
   380             default:
   381                 throw new InternalError("Should not have an invalid kind");
   382         }
   384         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
   387         //build a sam instance using an indy call to the meta-factory
   388         result = makeMetaFactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
   389     }
   391     /**
   392      * Translate identifiers within a lambda to the mapped identifier
   393      * @param tree
   394      */
   395     @Override
   396     public void visitIdent(JCIdent tree) {
   397         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
   398             super.visitIdent(tree);
   399         } else {
   400             LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
   401             if (lambdaContext.getSymbolMap(PARAM).containsKey(tree.sym)) {
   402                 Symbol translatedSym = lambdaContext.getSymbolMap(PARAM).get(tree.sym);
   403                 result = make.Ident(translatedSym).setType(tree.type);
   404                 translatedSym.setTypeAttributes(tree.sym.getRawTypeAttributes());
   405             } else if (lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   406                 Symbol translatedSym = lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
   407                 result = make.Ident(translatedSym).setType(tree.type);
   408                 translatedSym.setTypeAttributes(tree.sym.getRawTypeAttributes());
   409             } else if (lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   410                 Symbol translatedSym = lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   411                 result = make.Ident(translatedSym).setType(translatedSym.type);
   412                 translatedSym.setTypeAttributes(tree.sym.getRawTypeAttributes());
   413             } else if (lambdaContext.getSymbolMap(CAPTURED_VAR).containsKey(tree.sym)) {
   414                 Symbol translatedSym = lambdaContext.getSymbolMap(CAPTURED_VAR).get(tree.sym);
   415                 result = make.Ident(translatedSym).setType(tree.type);
   416             } else {
   417                 //access to untranslated symbols (i.e. compile-time constants,
   418                 //members defined inside the lambda body, etc.) )
   419                 super.visitIdent(tree);
   420             }
   421         }
   422     }
   424     @Override
   425     public void visitVarDef(JCVariableDecl tree) {
   426         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
   427         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   428             JCExpression init = translate(tree.init);
   429             result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
   430         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   431             JCExpression init = translate(tree.init);
   432             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   433             result = make.VarDef(xsym, init);
   434             // Replace the entered symbol for this variable
   435             Scope sc = tree.sym.owner.members();
   436             if (sc != null) {
   437                 sc.remove(tree.sym);
   438                 sc.enter(xsym);
   439             }
   440         } else {
   441             super.visitVarDef(tree);
   442         }
   443     }
   445     // </editor-fold>
   447     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   449     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   450         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   451                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   452                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   453     }
   455     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   456         Type restype = lambdaMethodDecl.type.getReturnType();
   457         boolean isLambda_void = expr.type.hasTag(VOID);
   458         boolean isTarget_void = restype.hasTag(VOID);
   459         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   460         if (isTarget_void) {
   461             //target is void:
   462             // BODY;
   463             JCStatement stat = make.Exec(expr);
   464             return make.Block(0, List.<JCStatement>of(stat));
   465         } else if (isLambda_void && isTarget_Void) {
   466             //void to Void conversion:
   467             // BODY; return null;
   468             ListBuffer<JCStatement> stats = ListBuffer.lb();
   469             stats.append(make.Exec(expr));
   470             stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   471             return make.Block(0, stats.toList());
   472         } else {
   473             //non-void to non-void conversion:
   474             // return (TYPE)BODY;
   475             JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   476             return make.Block(0, List.<JCStatement>of(make.Return(retExpr)));
   477         }
   478     }
   480     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   481         final Type restype = lambdaMethodDecl.type.getReturnType();
   482         final boolean isTarget_void = restype.hasTag(VOID);
   483         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   485         class LambdaBodyTranslator extends TreeTranslator {
   487             @Override
   488             public void visitClassDef(JCClassDecl tree) {
   489                 //do NOT recurse on any inner classes
   490                 result = tree;
   491             }
   493             @Override
   494             public void visitLambda(JCLambda tree) {
   495                 //do NOT recurse on any nested lambdas
   496                 result = tree;
   497             }
   499             @Override
   500             public void visitReturn(JCReturn tree) {
   501                 boolean isLambda_void = tree.expr == null;
   502                 if (isTarget_void && !isLambda_void) {
   503                     //Void to void conversion:
   504                     // { TYPE $loc = RET-EXPR; return; }
   505                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   506                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   507                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   508                 } else if (!isTarget_void || !isLambda_void) {
   509                     //non-void to non-void conversion:
   510                     // return (TYPE)RET-EXPR;
   511                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   512                     result = tree;
   513                 } else {
   514                     result = tree;
   515                 }
   517             }
   518         }
   520         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   521         if (completeNormally && isTarget_Void) {
   522             //there's no return statement and the lambda (possibly inferred)
   523             //return type is java.lang.Void; emit a synthetic return statement
   524             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   525         }
   526         return trans_block;
   527     }
   529     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   530         ListBuffer<JCCase> cases = ListBuffer.lb();
   531         ListBuffer<JCBreak> breaks = ListBuffer.lb();
   532         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   533             JCBreak br = make.Break(null);
   534             breaks.add(br);
   535             List<JCStatement> stmts = entry.getValue().append(br).toList();
   536             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   537         }
   538         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   539         for (JCBreak br : breaks) {
   540             br.target = sw;
   541         }
   542         JCBlock body = make.Block(0L, List.<JCStatement>of(
   543                 sw,
   544                 make.Throw(makeNewClass(
   545                     syms.illegalArgumentExceptionType,
   546                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   547         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   548                         names.deserializeLambda,
   549                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   550                         List.<JCTypeParameter>nil(),
   551                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   552                         List.<JCExpression>nil(),
   553                         body,
   554                         null);
   555         deser.sym = kInfo.deserMethodSym;
   556         deser.type = kInfo.deserMethodSym.type;
   557         //System.err.printf("DESER: '%s'\n", deser);
   558         return deser;
   559     }
   561     /** Make an attributed class instance creation expression.
   562      *  @param ctype    The class type.
   563      *  @param args     The constructor arguments.
   564      *  @param cons     The constructor symbol
   565      */
   566     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
   567         JCNewClass tree = make.NewClass(null,
   568             null, make.QualIdent(ctype.tsym), args, null);
   569         tree.constructor = cons;
   570         tree.type = ctype;
   571         return tree;
   572     }
   574     /** Make an attributed class instance creation expression.
   575      *  @param ctype    The class type.
   576      *  @param args     The constructor arguments.
   577      */
   578     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   579         return makeNewClass(ctype, args,
   580                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
   581      }
   583     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   584             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   585         String functionalInterfaceClass = classSig(targetType);
   586         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   587         String functionalInterfaceMethodSignature = methodSig(types.erasure(samSym.type));
   588         String implClass = classSig(types.erasure(refSym.owner.type));
   589         String implMethodName = refSym.getQualifiedName().toString();
   590         String implMethodSignature = methodSig(types.erasure(refSym.type));
   592         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   593         ListBuffer<JCExpression> serArgs = ListBuffer.lb();
   594         int i = 0;
   595         for (Type t : indyType.getParameterTypes()) {
   596             List<JCExpression> indexAsArg = ListBuffer.<JCExpression>lb().append(make.Literal(i)).toList();
   597             List<Type> argTypes = ListBuffer.<Type>lb().append(syms.intType).toList();
   598             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   599             ++i;
   600         }
   601         JCStatement stmt = make.If(
   602                 deserTest(deserTest(deserTest(deserTest(deserTest(
   603                     kindTest,
   604                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   605                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   606                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   607                     "getImplClass", implClass),
   608                     "getImplMethodSignature", implMethodSignature),
   609                 make.Return(makeIndyCall(
   610                     pos,
   611                     syms.lambdaMetafactory,
   612                     names.altMetaFactory,
   613                     staticArgs, indyType, serArgs.toList())),
   614                 null);
   615         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   616         if (stmts == null) {
   617             stmts = ListBuffer.lb();
   618             kInfo.deserializeCases.put(implMethodName, stmts);
   619         }
   620         /****
   621         System.err.printf("+++++++++++++++++\n");
   622         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   623         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   624         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   625         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   626         System.err.printf("*implClass: '%s'\n", implClass);
   627         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   628         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   629         ****/
   630         stmts.append(stmt);
   631     }
   633     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   634         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   635         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   636         testExpr.setType(syms.booleanType);
   637         return testExpr;
   638     }
   640     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   641         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   642         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   643         JCMethodInvocation eqtest = make.Apply(
   644                 List.<JCExpression>nil(),
   645                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   646                 List.<JCExpression>of(make.Literal(lit)));
   647         eqtest.setType(syms.booleanType);
   648         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   649         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   650         compound.setType(syms.booleanType);
   651         return compound;
   652     }
   654     private JCExpression deserGetter(String func, Type type) {
   655         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   656     }
   658     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   659         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   660         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   661         return make.Apply(
   662                     List.<JCExpression>nil(),
   663                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   664                     args).setType(type);
   665     }
   667     /**
   668      * Create new synthetic method with given flags, name, type, owner
   669      */
   670     private MethodSymbol makeSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   671         return new MethodSymbol(flags | SYNTHETIC, name, type, owner);
   672     }
   674     /**
   675      * Create new synthetic variable with given flags, name, type, owner
   676      */
   677     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   678         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   679     }
   681     /**
   682      * Create new synthetic variable with given flags, name, type, owner
   683      */
   684     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   685         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   686     }
   688     /**
   689      * Set varargsElement field on a given tree (must be either a new class tree
   690      * or a method call tree)
   691      */
   692     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   693         if (varargsElement != null) {
   694             switch (tree.getTag()) {
   695                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   696                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   697                 default: throw new AssertionError();
   698             }
   699         }
   700     }
   702     /**
   703      * Convert method/constructor arguments by inserting appropriate cast
   704      * as required by type-erasure - this is needed when bridging a lambda/method
   705      * reference, as the bridged signature might require downcast to be compatible
   706      * with the generated signature.
   707      */
   708     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   709        Assert.check(meth.kind == Kinds.MTH);
   710        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   711        if (varargsElement != null) {
   712            Assert.check((meth.flags() & VARARGS) != 0);
   713        }
   714        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   715     }
   717     // </editor-fold>
   719     /**
   720      * Generate an adapter method "bridge" for a method reference which cannot
   721      * be used directly.
   722      */
   723     private class MemberReferenceBridger {
   725         private final JCMemberReference tree;
   726         private final ReferenceTranslationContext localContext;
   727         private final ListBuffer<JCExpression> args = ListBuffer.lb();
   728         private final ListBuffer<JCVariableDecl> params = ListBuffer.lb();
   730         MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
   731             this.tree = tree;
   732             this.localContext = localContext;
   733         }
   735         /**
   736          * Generate the bridge
   737          */
   738         JCMethodDecl bridge() {
   739             int prevPos = make.pos;
   740             try {
   741                 make.at(tree);
   742                 Type samDesc = localContext.bridgedRefSig();
   743                 List<Type> samPTypes = samDesc.getParameterTypes();
   745                 //an extra argument is prepended to the signature of the bridge in case
   746                 //the member reference is an instance method reference (in which case
   747                 //the receiver expression is passed to the bridge itself).
   748                 Type recType = null;
   749                 switch (tree.kind) {
   750                     case IMPLICIT_INNER:
   751                         recType = tree.sym.owner.type.getEnclosingType();
   752                         break;
   753                     case BOUND:
   754                         recType = tree.getQualifierExpression().type;
   755                         break;
   756                     case UNBOUND:
   757                         recType = samPTypes.head;
   758                         samPTypes = samPTypes.tail;
   759                         break;
   760                 }
   762                 //generate the parameter list for the bridged member reference - the
   763                 //bridge signature will match the signature of the target sam descriptor
   765                 VarSymbol rcvr = (recType == null)
   766                         ? null
   767                         : addParameter("rec$", recType, false);
   769                 List<Type> refPTypes = tree.sym.type.getParameterTypes();
   770                 int refSize = refPTypes.size();
   771                 int samSize = samPTypes.size();
   772                 // Last parameter to copy from referenced method
   773                 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
   775                 List<Type> l = refPTypes;
   776                 // Use parameter types of the referenced method, excluding final var args
   777                 for (int i = 0; l.nonEmpty() && i < last; ++i) {
   778                     addParameter("x$" + i, l.head, true);
   779                     l = l.tail;
   780                 }
   781                 // Flatten out the var args
   782                 for (int i = last; i < samSize; ++i) {
   783                     addParameter("xva$" + i, tree.varargsElement, true);
   784                 }
   786                 //generate the bridge method declaration
   787                 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
   788                         localContext.bridgeSym.name,
   789                         make.QualIdent(samDesc.getReturnType().tsym),
   790                         List.<JCTypeParameter>nil(),
   791                         params.toList(),
   792                         tree.sym.type.getThrownTypes() == null
   793                         ? List.<JCExpression>nil()
   794                         : make.Types(tree.sym.type.getThrownTypes()),
   795                         null,
   796                         null);
   797                 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
   798                 bridgeDecl.type = localContext.bridgeSym.type =
   799                         types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
   801                 //bridge method body generation - this can be either a method call or a
   802                 //new instance creation expression, depending on the member reference kind
   803                 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
   804                         ? bridgeExpressionInvoke(makeReceiver(rcvr))
   805                         : bridgeExpressionNew();
   807                 //the body is either a return expression containing a method call,
   808                 //or the method call itself, depending on whether the return type of
   809                 //the bridge is non-void/void.
   810                 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
   812                 return bridgeDecl;
   813             } finally {
   814                 make.at(prevPos);
   815             }
   816         }
   817         //where
   818             private JCExpression makeReceiver(VarSymbol rcvr) {
   819                 if (rcvr == null) return null;
   820                 JCExpression rcvrExpr = make.Ident(rcvr);
   821                 Type rcvrType = tree.sym.enclClass().type;
   822                 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   823                     rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   824                 }
   825                 return rcvrExpr;
   826             }
   828         /**
   829          * determine the receiver of the bridged method call - the receiver can
   830          * be either the synthetic receiver parameter or a type qualifier; the
   831          * original qualifier expression is never used here, as it might refer
   832          * to symbols not available in the static context of the bridge
   833          */
   834         private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
   835             JCExpression qualifier =
   836                     tree.sym.isStatic() ?
   837                         make.Type(tree.sym.owner.type) :
   838                         (rcvr != null) ?
   839                             rcvr :
   840                             tree.getQualifierExpression();
   842             //create the qualifier expression
   843             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   844             select.sym = tree.sym;
   845             select.type = tree.sym.erasure(types);
   847             //create the method call expression
   848             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   849                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   850                     setType(tree.sym.erasure(types).getReturnType());
   852             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   853             setVarargsIfNeeded(apply, tree.varargsElement);
   854             return apply;
   855         }
   857         /**
   858          * the enclosing expression is either 'null' (no enclosing type) or set
   859          * to the first bridge synthetic parameter
   860          */
   861         private JCExpression bridgeExpressionNew() {
   862             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   863                 //create the array creation expression
   864                 JCNewArray newArr = make.NewArray(
   865                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   866                         List.of(make.Ident(params.first())),
   867                         null);
   868                 newArr.type = tree.getQualifierExpression().type;
   869                 return newArr;
   870             } else {
   871                 JCExpression encl = null;
   872                 switch (tree.kind) {
   873                     case UNBOUND:
   874                     case IMPLICIT_INNER:
   875                         encl = make.Ident(params.first());
   876                 }
   878                 //create the instance creation expression
   879                 JCNewClass newClass = make.NewClass(encl,
   880                         List.<JCExpression>nil(),
   881                         make.Type(tree.getQualifierExpression().type),
   882                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   883                         null);
   884                 newClass.constructor = tree.sym;
   885                 newClass.constructorType = tree.sym.erasure(types);
   886                 newClass.type = tree.getQualifierExpression().type;
   887                 setVarargsIfNeeded(newClass, tree.varargsElement);
   888                 return newClass;
   889             }
   890         }
   892         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   893             VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
   894             params.append(make.VarDef(vsym, null));
   895             if (genArg) {
   896                 args.append(make.Ident(vsym));
   897             }
   898             return vsym;
   899         }
   900     }
   902     /**
   903      * Bridges a member reference - this is needed when:
   904      * * Var args in the referenced method need to be flattened away
   905      * * super is used
   906      */
   907     private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
   908         kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
   909     }
   911     /**
   912      * Generate an indy method call to the meta factory
   913      */
   914     private JCExpression makeMetaFactoryIndyCall(TranslationContext<?> context,
   915             int refKind, Symbol refSym, List<JCExpression> indy_args) {
   916         JCFunctionalExpression tree = context.tree;
   917         //determine the static bsm args
   918         Type mtype = types.erasure(tree.getDescriptorType(types));
   919         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   920         List<Object> staticArgs = List.<Object>of(
   921                 new Pool.MethodHandle(ClassFile.REF_invokeInterface,
   922                     types.findDescriptorSymbol(tree.type.tsym), types),
   923                 new Pool.MethodHandle(refKind, refSym, types),
   924                 new MethodType(mtype.getParameterTypes(),
   925                         mtype.getReturnType(),
   926                         mtype.getThrownTypes(),
   927                         syms.methodClass));
   929         //computed indy arg types
   930         ListBuffer<Type> indy_args_types = ListBuffer.lb();
   931         for (JCExpression arg : indy_args) {
   932             indy_args_types.append(arg.type);
   933         }
   935         //finally, compute the type of the indy call
   936         MethodType indyType = new MethodType(indy_args_types.toList(),
   937                 tree.type,
   938                 List.<Type>nil(),
   939                 syms.methodClass);
   941         Name metafactoryName = context.needsAltMetafactory() ?
   942                 names.altMetaFactory : names.metaFactory;
   944         if (context.needsAltMetafactory()) {
   945             ListBuffer<Object> markers = ListBuffer.lb();
   946             for (Type t : tree.targets.tail) {
   947                 if (t.tsym != syms.serializableType.tsym) {
   948                     markers.append(t.tsym);
   949                 }
   950             }
   951             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
   952             boolean hasMarkers = markers.nonEmpty();
   953             boolean hasBridges = context.bridges.nonEmpty();
   954             if (hasMarkers) {
   955                 flags |= FLAG_MARKERS;
   956             }
   957             if (hasBridges) {
   958                 flags |= FLAG_BRIDGES;
   959             }
   960             staticArgs = staticArgs.append(flags);
   961             if (hasMarkers) {
   962                 staticArgs = staticArgs.append(markers.length());
   963                 staticArgs = staticArgs.appendList(markers.toList());
   964             }
   965             if (hasBridges) {
   966                 staticArgs = staticArgs.append(context.bridges.length() - 1);
   967                 for (Symbol s : context.bridges) {
   968                     Type s_erasure = s.erasure(types);
   969                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
   970                         staticArgs = staticArgs.append(s.erasure(types));
   971                     }
   972                 }
   973             }
   974             if (context.isSerializable()) {
   975                 addDeserializationCase(refKind, refSym, tree.type, samSym,
   976                         tree, staticArgs, indyType);
   977             }
   978         }
   980         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
   981     }
   983     /**
   984      * Generate an indy method call with given name, type and static bootstrap
   985      * arguments types
   986      */
   987     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
   988             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
   989         int prevPos = make.pos;
   990         try {
   991             make.at(pos);
   992             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
   993                     syms.stringType,
   994                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
   996             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
   997                     bsmName, bsm_staticArgs, List.<Type>nil());
   999             DynamicMethodSymbol dynSym =
  1000                     new DynamicMethodSymbol(names.lambda,
  1001                                             syms.noSymbol,
  1002                                             bsm.isStatic() ?
  1003                                                 ClassFile.REF_invokeStatic :
  1004                                                 ClassFile.REF_invokeVirtual,
  1005                                             (MethodSymbol)bsm,
  1006                                             indyType,
  1007                                             staticArgs.toArray());
  1009             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1010             qualifier.sym = dynSym;
  1011             qualifier.type = indyType.getReturnType();
  1013             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
  1014             proxyCall.type = indyType.getReturnType();
  1015             return proxyCall;
  1016         } finally {
  1017             make.at(prevPos);
  1020     //where
  1021     private List<Type> bsmStaticArgToTypes(List<Object> args) {
  1022         ListBuffer<Type> argtypes = ListBuffer.lb();
  1023         for (Object arg : args) {
  1024             argtypes.append(bsmStaticArgToType(arg));
  1026         return argtypes.toList();
  1029     private Type bsmStaticArgToType(Object arg) {
  1030         Assert.checkNonNull(arg);
  1031         if (arg instanceof ClassSymbol) {
  1032             return syms.classType;
  1033         } else if (arg instanceof Integer) {
  1034             return syms.intType;
  1035         } else if (arg instanceof Long) {
  1036             return syms.longType;
  1037         } else if (arg instanceof Float) {
  1038             return syms.floatType;
  1039         } else if (arg instanceof Double) {
  1040             return syms.doubleType;
  1041         } else if (arg instanceof String) {
  1042             return syms.stringType;
  1043         } else if (arg instanceof Pool.MethodHandle) {
  1044             return syms.methodHandleType;
  1045         } else if (arg instanceof MethodType) {
  1046             return syms.methodTypeType;
  1047         } else {
  1048             Assert.error("bad static arg " + arg.getClass());
  1049             return null;
  1053     /**
  1054      * Get the opcode associated with this method reference
  1055      */
  1056     private int referenceKind(Symbol refSym) {
  1057         if (refSym.isConstructor()) {
  1058             return ClassFile.REF_newInvokeSpecial;
  1059         } else {
  1060             if (refSym.isStatic()) {
  1061                 return ClassFile.REF_invokeStatic;
  1062             } else if (refSym.enclClass().isInterface()) {
  1063                 return ClassFile.REF_invokeInterface;
  1064             } else {
  1065                 return (refSym.flags() & PRIVATE) != 0 ?
  1066                         ClassFile.REF_invokeSpecial :
  1067                         ClassFile.REF_invokeVirtual;
  1072     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1073     /**
  1074      * This visitor collects information about translation of a lambda expression.
  1075      * More specifically, it keeps track of the enclosing contexts and captured locals
  1076      * accessed by the lambda being translated (as well as other useful info).
  1077      * It also translates away problems for LambdaToMethod.
  1078      */
  1079     class LambdaAnalyzerPreprocessor extends TreeTranslator {
  1081         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1082         private List<Frame> frameStack;
  1084         /**
  1085          * keep the count of lambda expression (used to generate unambiguous
  1086          * names)
  1087          */
  1088         private int lambdaCount = 0;
  1090         /**
  1091          * keep the count of lambda expression defined in given context (used to
  1092          * generate unambiguous names for serializable lambdas)
  1093          */
  1094         private Map<String, Integer> serializableLambdaCounts =
  1095                 new HashMap<String, Integer>();
  1097         private Map<Symbol, JCClassDecl> localClassDefs;
  1099         /**
  1100          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1101          * a static var init context
  1102          */
  1103         private Map<ClassSymbol, Symbol> clinits =
  1104                 new HashMap<ClassSymbol, Symbol>();
  1106         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
  1107             frameStack = List.nil();
  1108             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1109             return translate(tree);
  1112         @Override
  1113         public void visitBlock(JCBlock tree) {
  1114             List<Frame> prevStack = frameStack;
  1115             try {
  1116                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1117                     frameStack = frameStack.prepend(new Frame(tree));
  1119                 super.visitBlock(tree);
  1121             finally {
  1122                 frameStack = prevStack;
  1126         @Override
  1127         public void visitClassDef(JCClassDecl tree) {
  1128             List<Frame> prevStack = frameStack;
  1129             Map<String, Integer> prevSerializableLambdaCount =
  1130                     serializableLambdaCounts;
  1131             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1132             DiagnosticSource prevSource = log.currentSource();
  1133             try {
  1134                 log.useSource(tree.sym.sourcefile);
  1135                 serializableLambdaCounts = new HashMap<String, Integer>();
  1136                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1137                 if (tree.sym.owner.kind == MTH) {
  1138                     localClassDefs.put(tree.sym, tree);
  1140                 if (directlyEnclosingLambda() != null) {
  1141                     tree.sym.owner = owner();
  1142                     if (tree.sym.hasOuterInstance()) {
  1143                         //if a class is defined within a lambda, the lambda must capture
  1144                         //its enclosing instance (if any)
  1145                         TranslationContext<?> localContext = context();
  1146                         while (localContext != null) {
  1147                             if (localContext.tree.getTag() == LAMBDA) {
  1148                                 ((LambdaTranslationContext)localContext)
  1149                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1151                             localContext = localContext.prev;
  1155                 frameStack = frameStack.prepend(new Frame(tree));
  1156                 super.visitClassDef(tree);
  1158             finally {
  1159                 log.useSource(prevSource.getFile());
  1160                 frameStack = prevStack;
  1161                 serializableLambdaCounts = prevSerializableLambdaCount;
  1162                 clinits = prevClinits;
  1166         @Override
  1167         public void visitIdent(JCIdent tree) {
  1168             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1169                 if (tree.sym.kind == VAR &&
  1170                         tree.sym.owner.kind == MTH &&
  1171                         tree.type.constValue() == null) {
  1172                     TranslationContext<?> localContext = context();
  1173                     while (localContext != null) {
  1174                         if (localContext.tree.getTag() == LAMBDA) {
  1175                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1176                             if (block == null) break;
  1177                             ((LambdaTranslationContext)localContext)
  1178                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1180                         localContext = localContext.prev;
  1182                 } else if (tree.sym.owner.kind == TYP) {
  1183                     TranslationContext<?> localContext = context();
  1184                     while (localContext != null) {
  1185                         if (localContext.tree.hasTag(LAMBDA)) {
  1186                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1187                             if (block == null) break;
  1188                             switch (block.getTag()) {
  1189                                 case CLASSDEF:
  1190                                     JCClassDecl cdecl = (JCClassDecl)block;
  1191                                     ((LambdaTranslationContext)localContext)
  1192                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1193                                     break;
  1194                                 default:
  1195                                     Assert.error("bad block kind");
  1198                         localContext = localContext.prev;
  1202             super.visitIdent(tree);
  1205         @Override
  1206         public void visitLambda(JCLambda tree) {
  1207             List<Frame> prevStack = frameStack;
  1208             try {
  1209                 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
  1210                 frameStack = frameStack.prepend(new Frame(tree));
  1211                 for (JCVariableDecl param : tree.params) {
  1212                     context.addSymbol(param.sym, PARAM);
  1213                     frameStack.head.addLocal(param.sym);
  1215                 contextMap.put(tree, context);
  1216                 super.visitLambda(tree);
  1217                 context.complete();
  1219             finally {
  1220                 frameStack = prevStack;
  1224         @Override
  1225         public void visitMethodDef(JCMethodDecl tree) {
  1226             List<Frame> prevStack = frameStack;
  1227             try {
  1228                 frameStack = frameStack.prepend(new Frame(tree));
  1229                 super.visitMethodDef(tree);
  1231             finally {
  1232                 frameStack = prevStack;
  1236         @Override
  1237         public void visitNewClass(JCNewClass tree) {
  1238             if (lambdaNewClassFilter(context(), tree)) {
  1239                 TranslationContext<?> localContext = context();
  1240                 while (localContext != null) {
  1241                     if (localContext.tree.getTag() == LAMBDA) {
  1242                         ((LambdaTranslationContext)localContext)
  1243                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1245                     localContext = localContext.prev;
  1248             if (context() != null && tree.type.tsym.owner.kind == MTH) {
  1249                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1250                 captureLocalClassDefs(tree.type.tsym, lambdaContext);
  1252             super.visitNewClass(tree);
  1254         //where
  1255             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1256                 JCClassDecl localCDef = localClassDefs.get(csym);
  1257                 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
  1258                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1259                         @Override
  1260                         void addFreeVars(ClassSymbol c) {
  1261                             captureLocalClassDefs(c, lambdaContext);
  1263                         @Override
  1264                         void visitSymbol(Symbol sym) {
  1265                             if (sym.kind == VAR &&
  1266                                     sym.owner.kind == MTH &&
  1267                                     ((VarSymbol)sym).getConstValue() == null) {
  1268                                 TranslationContext<?> localContext = context();
  1269                                 while (localContext != null) {
  1270                                     if (localContext.tree.getTag() == LAMBDA) {
  1271                                         JCTree block = capturedDecl(localContext.depth, sym);
  1272                                         if (block == null) break;
  1273                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1275                                     localContext = localContext.prev;
  1279                     };
  1280                     fvc.scan(localCDef);
  1284         /**
  1285          * Method references to local class constructors, may, if the local
  1286          * class references local variables, have implicit constructor
  1287          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1288          * information added in the LambdaToMethod pass will have the wrong
  1289          * signature. Hooks between Lower and LambdaToMethod have been added to
  1290          * handle normal "new" in this case. This visitor converts potentially
  1291          * effected method references into a lambda containing a normal "new" of
  1292          * the class.
  1294          * @param tree
  1295          */
  1296         @Override
  1297         public void visitReference(JCMemberReference tree) {
  1298             if (tree.getMode() == ReferenceMode.NEW
  1299                     && tree.kind != ReferenceKind.ARRAY_CTOR
  1300                     && tree.sym.owner.isLocal()) {
  1301                 MethodSymbol consSym = (MethodSymbol) tree.sym;
  1302                 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
  1303                 Type classType = consSym.owner.type;
  1305                 // Build lambda parameters
  1306                 // partially cloned from TreeMaker.Params until 8014021 is fixed
  1307                 Symbol owner = owner();
  1308                 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
  1309                 int i = 0;
  1310                 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
  1311                     paramBuff.append(make.Param(make.paramName(i++), l.head, owner));
  1313                 List<JCVariableDecl> params = paramBuff.toList();
  1315                 // Make new-class call
  1316                 JCNewClass nc = makeNewClass(classType, make.Idents(params));
  1317                 nc.pos = tree.pos;
  1319                 // Make lambda holding the new-class call
  1320                 JCLambda slam = make.Lambda(params, nc);
  1321                 slam.targets = tree.targets;
  1322                 slam.type = tree.type;
  1323                 slam.pos = tree.pos;
  1325                 // Now it is a lambda, process as such
  1326                 visitLambda(slam);
  1327             } else {
  1328                 super.visitReference(tree);
  1329                 contextMap.put(tree, makeReferenceContext(tree));
  1333         @Override
  1334         public void visitSelect(JCFieldAccess tree) {
  1335             if (context() != null && tree.sym.kind == VAR &&
  1336                         (tree.sym.name == names._this ||
  1337                          tree.sym.name == names._super)) {
  1338                 // A select of this or super means, if we are in a lambda,
  1339                 // we much have an instance context
  1340                 TranslationContext<?> localContext = context();
  1341                 while (localContext != null) {
  1342                     if (localContext.tree.hasTag(LAMBDA)) {
  1343                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1344                         if (clazz == null) break;
  1345                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1347                     localContext = localContext.prev;
  1350             super.visitSelect(tree);
  1353         @Override
  1354         public void visitVarDef(JCVariableDecl tree) {
  1355             TranslationContext<?> context = context();
  1356             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1357                     (LambdaTranslationContext)context :
  1358                     null;
  1359             if (ltc != null) {
  1360                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1361                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1363                 // Check for type variables (including as type arguments).
  1364                 // If they occur within class nested in a lambda, mark for erasure
  1365                 Type type = tree.sym.asType();
  1366                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1367                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1371             List<Frame> prevStack = frameStack;
  1372             try {
  1373                 if (tree.sym.owner.kind == MTH) {
  1374                     frameStack.head.addLocal(tree.sym);
  1376                 frameStack = frameStack.prepend(new Frame(tree));
  1377                 super.visitVarDef(tree);
  1379             finally {
  1380                 frameStack = prevStack;
  1384         private Name lambdaName() {
  1385             return names.lambda.append(names.fromString("" + lambdaCount++));
  1388         /**
  1389          * For a serializable lambda, generate a name which maximizes name
  1390          * stability across deserialization.
  1391          * @param owner
  1392          * @return Name to use for the synthetic lambda method name
  1393          */
  1394         private Name serializedLambdaName(Symbol owner) {
  1395             StringBuilder buf = new StringBuilder();
  1396             buf.append(names.lambda);
  1397             // Append the name of the method enclosing the lambda.
  1398             String methodName = owner.name.toString();
  1399             if (methodName.equals("<clinit>"))
  1400                 methodName = "static";
  1401             else if (methodName.equals("<init>"))
  1402                 methodName = "new";
  1403             buf.append(methodName);
  1404             buf.append('$');
  1405             // Append a hash of the enclosing method signature to differentiate
  1406             // overloaded enclosing methods.  For lambdas enclosed in lambdas,
  1407             // the generated lambda method will not have type yet, but the
  1408             // enclosing method's name will have been generated with this same
  1409             // method, so it will be unique and never be overloaded.
  1410             Assert.check(owner.type != null || directlyEnclosingLambda() != null);
  1411             if (owner.type != null) {
  1412                 int methTypeHash = methodSig(owner.type).hashCode();
  1413                 buf.append(Integer.toHexString(methTypeHash));
  1415             buf.append('$');
  1416             // The above appended name components may not be unique, append a
  1417             // count based on the above name components.
  1418             String temp = buf.toString();
  1419             Integer count = serializableLambdaCounts.get(temp);
  1420             if (count == null) {
  1421                 count = 0;
  1423             buf.append(count++);
  1424             serializableLambdaCounts.put(temp, count);
  1425             return names.fromString(buf.toString());
  1428         /**
  1429          * Return a valid owner given the current declaration stack
  1430          * (required to skip synthetic lambda symbols)
  1431          */
  1432         private Symbol owner() {
  1433             return owner(false);
  1436         @SuppressWarnings("fallthrough")
  1437         private Symbol owner(boolean skipLambda) {
  1438             List<Frame> frameStack2 = frameStack;
  1439             while (frameStack2.nonEmpty()) {
  1440                 switch (frameStack2.head.tree.getTag()) {
  1441                     case VARDEF:
  1442                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1443                             frameStack2 = frameStack2.tail;
  1444                             break;
  1446                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1447                         return initSym(cdecl.sym,
  1448                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1449                     case BLOCK:
  1450                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1451                         return initSym(cdecl2.sym,
  1452                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1453                     case CLASSDEF:
  1454                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1455                     case METHODDEF:
  1456                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1457                     case LAMBDA:
  1458                         if (!skipLambda)
  1459                             return ((LambdaTranslationContext)contextMap
  1460                                     .get(frameStack2.head.tree)).translatedSym;
  1461                     default:
  1462                         frameStack2 = frameStack2.tail;
  1465             Assert.error();
  1466             return null;
  1469         private Symbol initSym(ClassSymbol csym, long flags) {
  1470             boolean isStatic = (flags & STATIC) != 0;
  1471             if (isStatic) {
  1472                 //static clinits are generated in Gen - so we need to fake them
  1473                 Symbol clinit = clinits.get(csym);
  1474                 if (clinit == null) {
  1475                     clinit = makeSyntheticMethod(STATIC,
  1476                             names.clinit,
  1477                             new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
  1478                             csym);
  1479                     clinits.put(csym, clinit);
  1481                 return clinit;
  1482             } else {
  1483                 //get the first constructor and treat it as the instance init sym
  1484                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1485                     return s;
  1488             Assert.error("init not found");
  1489             return null;
  1492         private JCTree directlyEnclosingLambda() {
  1493             if (frameStack.isEmpty()) {
  1494                 return null;
  1496             List<Frame> frameStack2 = frameStack;
  1497             while (frameStack2.nonEmpty()) {
  1498                 switch (frameStack2.head.tree.getTag()) {
  1499                     case CLASSDEF:
  1500                     case METHODDEF:
  1501                         return null;
  1502                     case LAMBDA:
  1503                         return frameStack2.head.tree;
  1504                     default:
  1505                         frameStack2 = frameStack2.tail;
  1508             Assert.error();
  1509             return null;
  1512         private boolean inClassWithinLambda() {
  1513             if (frameStack.isEmpty()) {
  1514                 return false;
  1516             List<Frame> frameStack2 = frameStack;
  1517             boolean classFound = false;
  1518             while (frameStack2.nonEmpty()) {
  1519                 switch (frameStack2.head.tree.getTag()) {
  1520                     case LAMBDA:
  1521                         return classFound;
  1522                     case CLASSDEF:
  1523                         classFound = true;
  1524                         frameStack2 = frameStack2.tail;
  1525                         break;
  1526                     default:
  1527                         frameStack2 = frameStack2.tail;
  1530             // No lambda
  1531             return false;
  1534         /**
  1535          * Return the declaration corresponding to a symbol in the enclosing
  1536          * scope; the depth parameter is used to filter out symbols defined
  1537          * in nested scopes (which do not need to undergo capture).
  1538          */
  1539         private JCTree capturedDecl(int depth, Symbol sym) {
  1540             int currentDepth = frameStack.size() - 1;
  1541             for (Frame block : frameStack) {
  1542                 switch (block.tree.getTag()) {
  1543                     case CLASSDEF:
  1544                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1545                         if (sym.isMemberOf(clazz, types)) {
  1546                             return currentDepth > depth ? null : block.tree;
  1548                         break;
  1549                     case VARDEF:
  1550                         if (((JCVariableDecl)block.tree).sym == sym &&
  1551                                 sym.owner.kind == MTH) { //only locals are captured
  1552                             return currentDepth > depth ? null : block.tree;
  1554                         break;
  1555                     case BLOCK:
  1556                     case METHODDEF:
  1557                     case LAMBDA:
  1558                         if (block.locals != null && block.locals.contains(sym)) {
  1559                             return currentDepth > depth ? null : block.tree;
  1561                         break;
  1562                     default:
  1563                         Assert.error("bad decl kind " + block.tree.getTag());
  1565                 currentDepth--;
  1567             return null;
  1570         private TranslationContext<?> context() {
  1571             for (Frame frame : frameStack) {
  1572                 TranslationContext<?> context = contextMap.get(frame.tree);
  1573                 if (context != null) {
  1574                     return context;
  1577             return null;
  1580         /**
  1581          *  This is used to filter out those identifiers that needs to be adjusted
  1582          *  when translating away lambda expressions
  1583          */
  1584         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1585             return (sym.kind == VAR || sym.kind == MTH)
  1586                     && !sym.isStatic()
  1587                     && sym.name != names.init;
  1590         /**
  1591          * This is used to filter out those new class expressions that need to
  1592          * be qualified with an enclosing tree
  1593          */
  1594         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1595             if (context != null
  1596                     && tree.encl == null
  1597                     && tree.def == null
  1598                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1599                 Type encl = tree.type.getEnclosingType();
  1600                 Type current = context.owner.enclClass().type;
  1601                 while (!current.hasTag(NONE)) {
  1602                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1603                         return true;
  1605                     current = current.getEnclosingType();
  1607                 return false;
  1608             } else {
  1609                 return false;
  1613         private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
  1614             return new LambdaTranslationContext(tree);
  1617         private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
  1618             return new ReferenceTranslationContext(tree);
  1621         private class Frame {
  1622             final JCTree tree;
  1623             List<Symbol> locals;
  1625             public Frame(JCTree tree) {
  1626                 this.tree = tree;
  1629             void addLocal(Symbol sym) {
  1630                 if (locals == null) {
  1631                     locals = List.nil();
  1633                 locals = locals.prepend(sym);
  1637         /**
  1638          * This class is used to store important information regarding translation of
  1639          * lambda expression/method references (see subclasses).
  1640          */
  1641         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1643             /** the underlying (untranslated) tree */
  1644             T tree;
  1646             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1647             Symbol owner;
  1649             /** the depth of this lambda expression in the frame stack */
  1650             int depth;
  1652             /** the enclosing translation context (set for nested lambdas/mref) */
  1653             TranslationContext<?> prev;
  1655             /** list of methods to be bridged by the meta-factory */
  1656             List<Symbol> bridges;
  1658             TranslationContext(T tree) {
  1659                 this.tree = tree;
  1660                 this.owner = owner();
  1661                 this.depth = frameStack.size() - 1;
  1662                 this.prev = context();
  1663                 ClassSymbol csym =
  1664                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1665                 this.bridges = types.functionalInterfaceBridges(csym);
  1668             /** does this functional expression need to be created using alternate metafactory? */
  1669             boolean needsAltMetafactory() {
  1670                 return tree.targets.length() > 1 ||
  1671                         isSerializable() ||
  1672                         bridges.length() > 1;
  1675             /** does this functional expression require serialization support? */
  1676             boolean isSerializable() {
  1677                 for (Type target : tree.targets) {
  1678                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1679                         return true;
  1682                 return false;
  1686         /**
  1687          * This class retains all the useful information about a lambda expression;
  1688          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1689          * and the used by the main translation routines in order to adjust references
  1690          * to captured locals/members, etc.
  1691          */
  1692         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1694             /** variable in the enclosing context to which this lambda is assigned */
  1695             Symbol self;
  1697             /** map from original to translated lambda parameters */
  1698             Map<Symbol, Symbol> lambdaParams = new LinkedHashMap<Symbol, Symbol>();
  1700             /** map from original to translated lambda locals */
  1701             Map<Symbol, Symbol> lambdaLocals = new LinkedHashMap<Symbol, Symbol>();
  1703             /** map from variables in enclosing scope to translated synthetic parameters */
  1704             Map<Symbol, Symbol> capturedLocals  = new LinkedHashMap<Symbol, Symbol>();
  1706             /** map from class symbols to translated synthetic parameters (for captured member access) */
  1707             Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>();
  1709             /** map from original to translated lambda locals */
  1710             Map<Symbol, Symbol> typeVars = new LinkedHashMap<Symbol, Symbol>();
  1712             /** the synthetic symbol for the method hoisting the translated lambda */
  1713             Symbol translatedSym;
  1715             List<JCVariableDecl> syntheticParams;
  1717             LambdaTranslationContext(JCLambda tree) {
  1718                 super(tree);
  1719                 Frame frame = frameStack.head;
  1720                 if (frame.tree.hasTag(VARDEF)) {
  1721                     self = ((JCVariableDecl)frame.tree).sym;
  1723                 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName();
  1724                 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass());
  1725                 if (dumpLambdaToMethodStats) {
  1726                     log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym);
  1730             /**
  1731              * Translate a symbol of a given kind into something suitable for the
  1732              * synthetic lambda body
  1733              */
  1734             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1735                 Symbol ret;
  1736                 switch (skind) {
  1737                     case CAPTURED_THIS:
  1738                         ret = sym;  // self represented
  1739                         break;
  1740                     case TYPE_VAR:
  1741                         // Just erase the type var
  1742                         ret = new VarSymbol(sym.flags(), name,
  1743                                 types.erasure(sym.type), sym.owner);
  1744                         break;
  1745                     case CAPTURED_VAR:
  1746                         ret = new VarSymbol(SYNTHETIC | FINAL, name, types.erasure(sym.type), translatedSym) {
  1747                             @Override
  1748                             public Symbol baseSymbol() {
  1749                                 //keep mapping with original captured symbol
  1750                                 return sym;
  1752                         };
  1753                         break;
  1754                     default:
  1755                         ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1757                 if (ret != sym) {
  1758                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1759                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1761                 return ret;
  1764             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1765                 Map<Symbol, Symbol> transMap = null;
  1766                 Name preferredName;
  1767                 switch (skind) {
  1768                     case CAPTURED_THIS:
  1769                         transMap = capturedThis;
  1770                         preferredName = names.fromString("encl$" + capturedThis.size());
  1771                         break;
  1772                     case CAPTURED_VAR:
  1773                         transMap = capturedLocals;
  1774                         preferredName = names.fromString("cap$" + capturedLocals.size());
  1775                         break;
  1776                     case LOCAL_VAR:
  1777                         transMap = lambdaLocals;
  1778                         preferredName = sym.name;
  1779                         break;
  1780                     case PARAM:
  1781                         transMap = lambdaParams;
  1782                         preferredName = sym.name;
  1783                         break;
  1784                     case TYPE_VAR:
  1785                         transMap = typeVars;
  1786                         preferredName = sym.name;
  1787                         break;
  1788                     default: throw new AssertionError();
  1790                 if (!transMap.containsKey(sym)) {
  1791                     transMap.put(sym, translate(preferredName, sym, skind));
  1795             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind... skinds) {
  1796                 LinkedHashMap<Symbol, Symbol> translationMap = new LinkedHashMap<Symbol, Symbol>();
  1797                 for (LambdaSymbolKind skind : skinds) {
  1798                     switch (skind) {
  1799                         case CAPTURED_THIS:
  1800                             translationMap.putAll(capturedThis);
  1801                             break;
  1802                         case CAPTURED_VAR:
  1803                             translationMap.putAll(capturedLocals);
  1804                             break;
  1805                         case LOCAL_VAR:
  1806                             translationMap.putAll(lambdaLocals);
  1807                             break;
  1808                         case PARAM:
  1809                             translationMap.putAll(lambdaParams);
  1810                             break;
  1811                         case TYPE_VAR:
  1812                             translationMap.putAll(typeVars);
  1813                             break;
  1814                         default: throw new AssertionError();
  1817                 return translationMap;
  1820             /**
  1821              * The translatedSym is not complete/accurate until the analysis is
  1822              * finished.  Once the analysis is finished, the translatedSym is
  1823              * "completed" -- updated with type information, access modifiers,
  1824              * and full parameter list.
  1825              */
  1826             void complete() {
  1827                 if (syntheticParams != null) {
  1828                     return;
  1830                 boolean inInterface = translatedSym.owner.isInterface();
  1831                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1833                 // If instance access isn't needed, make it static.
  1834                 // Interface instance methods must be default methods.
  1835                 // Awaiting VM channges, default methods are public
  1836                 translatedSym.flags_field = SYNTHETIC |
  1837                         ((inInterface && thisReferenced)? PUBLIC : PRIVATE) |
  1838                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  1840                 //compute synthetic params
  1841                 ListBuffer<JCVariableDecl> params = ListBuffer.lb();
  1843                 // The signature of the method is augmented with the following
  1844                 // synthetic parameters:
  1845                 //
  1846                 // 1) reference to enclosing contexts captured by the lambda expression
  1847                 // 2) enclosing locals captured by the lambda expression
  1848                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR, PARAM).values()) {
  1849                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1852                 syntheticParams = params.toList();
  1854                 //prepend synthetic args to translated lambda method signature
  1855                 translatedSym.type = types.createMethodTypeWithParameters(
  1856                         generatedLambdaSig(),
  1857                         TreeInfo.types(syntheticParams));
  1860             Type generatedLambdaSig() {
  1861                 return types.erasure(tree.getDescriptorType(types));
  1865         /**
  1866          * This class retains all the useful information about a method reference;
  1867          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1868          * and the used by the main translation routines in order to adjust method
  1869          * references (i.e. in case a bridge is needed)
  1870          */
  1871         private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  1873             final boolean isSuper;
  1874             final Symbol bridgeSym;
  1876             ReferenceTranslationContext(JCMemberReference tree) {
  1877                 super(tree);
  1878                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  1879                 this.bridgeSym = needsBridge()
  1880                         ? makeSyntheticMethod(isSuper ? 0 : STATIC,
  1881                                               lambdaName().append(names.fromString("$bridge")), null,
  1882                                               owner.enclClass())
  1883                         : null;
  1884                 if (dumpLambdaToMethodStats) {
  1885                     String key = bridgeSym == null ?
  1886                             "mref.stat" : "mref.stat.1";
  1887                     log.note(tree, key, needsAltMetafactory(), bridgeSym);
  1891             /**
  1892              * Get the opcode associated with this method reference
  1893              */
  1894             int referenceKind() {
  1895                 return LambdaToMethod.this.referenceKind(needsBridge() ? bridgeSym : tree.sym);
  1898             boolean needsVarArgsConversion() {
  1899                 return tree.varargsElement != null;
  1902             /**
  1903              * @return Is this an array operation like clone()
  1904              */
  1905             boolean isArrayOp() {
  1906                 return tree.sym.owner == syms.arrayClass;
  1909             boolean isPrivateConstructor() {
  1910                 //hack needed to workaround 292 bug (8005122)
  1911                 //when 292 issue is fixed we should simply remove this
  1912                 return tree.sym.name == names.init &&
  1913                         (tree.sym.flags() & PRIVATE) != 0;
  1916             boolean receiverAccessible() {
  1917                 //hack needed to workaround 292 bug (7087658)
  1918                 //when 292 issue is fixed we should remove this and change the backend
  1919                 //code to always generate a method handle to an accessible method
  1920                 return tree.ownerAccessible;
  1923             /**
  1924              * Does this reference needs a bridge (i.e. var args need to be
  1925              * expanded or "super" is used)
  1926              */
  1927             final boolean needsBridge() {
  1928                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  1929                         isPrivateConstructor() || !receiverAccessible();
  1932             Type generatedRefSig() {
  1933                 return types.erasure(tree.sym.type);
  1936             Type bridgedRefSig() {
  1937                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  1941     // </editor-fold>
  1943     enum LambdaSymbolKind {
  1944         CAPTURED_VAR,
  1945         CAPTURED_THIS,
  1946         LOCAL_VAR,
  1947         PARAM,
  1948         TYPE_VAR;
  1951     /**
  1952      * ****************************************************************
  1953      * Signature Generation
  1954      * ****************************************************************
  1955      */
  1957     private String methodSig(Type type) {
  1958         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1959         sg.assembleSig(type);
  1960         return sg.toString();
  1963     private String classSig(Type type) {
  1964         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1965         sg.assembleClassSig(type);
  1966         return sg.toString();
  1969     /**
  1970      * Signature Generation
  1971      */
  1972     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  1974         /**
  1975          * An output buffer for type signatures.
  1976          */
  1977         StringBuilder sb = new StringBuilder();
  1979         L2MSignatureGenerator() {
  1980             super(types);
  1983         @Override
  1984         protected void append(char ch) {
  1985             sb.append(ch);
  1988         @Override
  1989         protected void append(byte[] ba) {
  1990             sb.append(new String(ba));
  1993         @Override
  1994         protected void append(Name name) {
  1995             sb.append(name.toString());
  1998         @Override
  1999         public String toString() {
  2000             return sb.toString();

mercurial