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

Thu, 08 Aug 2013 11:49:16 +0100

author
vromero
date
Thu, 08 Aug 2013 11:49:16 +0100
changeset 1940
b8610a65fbf9
parent 1882
39ec5d8a691b
child 1969
7de231613e4a
permissions
-rw-r--r--

8019486: javac, generates erroneous LVT for a test case with lambda code
Reviewed-by: mcimadamore

     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.at(retExpr).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(), samSym.name)),
   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     private MethodType typeToMethodType(Type mt) {
   912         Type type = types.erasure(mt);
   913         return new MethodType(type.getParameterTypes(),
   914                         type.getReturnType(),
   915                         type.getThrownTypes(),
   916                         syms.methodClass);
   917     }
   919     /**
   920      * Generate an indy method call to the meta factory
   921      */
   922     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
   923             int refKind, Symbol refSym, List<JCExpression> indy_args) {
   924         JCFunctionalExpression tree = context.tree;
   925         //determine the static bsm args
   926         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   927         List<Object> staticArgs = List.<Object>of(
   928                 typeToMethodType(samSym.type),
   929                 new Pool.MethodHandle(refKind, refSym, types),
   930                 typeToMethodType(tree.getDescriptorType(types)));
   932         //computed indy arg types
   933         ListBuffer<Type> indy_args_types = ListBuffer.lb();
   934         for (JCExpression arg : indy_args) {
   935             indy_args_types.append(arg.type);
   936         }
   938         //finally, compute the type of the indy call
   939         MethodType indyType = new MethodType(indy_args_types.toList(),
   940                 tree.type,
   941                 List.<Type>nil(),
   942                 syms.methodClass);
   944         Name metafactoryName = context.needsAltMetafactory() ?
   945                 names.altMetafactory : names.metafactory;
   947         if (context.needsAltMetafactory()) {
   948             ListBuffer<Object> markers = ListBuffer.lb();
   949             for (Type t : tree.targets.tail) {
   950                 if (t.tsym != syms.serializableType.tsym) {
   951                     markers.append(t.tsym);
   952                 }
   953             }
   954             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
   955             boolean hasMarkers = markers.nonEmpty();
   956             boolean hasBridges = context.bridges.nonEmpty();
   957             if (hasMarkers) {
   958                 flags |= FLAG_MARKERS;
   959             }
   960             if (hasBridges) {
   961                 flags |= FLAG_BRIDGES;
   962             }
   963             staticArgs = staticArgs.append(flags);
   964             if (hasMarkers) {
   965                 staticArgs = staticArgs.append(markers.length());
   966                 staticArgs = staticArgs.appendList(markers.toList());
   967             }
   968             if (hasBridges) {
   969                 staticArgs = staticArgs.append(context.bridges.length() - 1);
   970                 for (Symbol s : context.bridges) {
   971                     Type s_erasure = s.erasure(types);
   972                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
   973                         staticArgs = staticArgs.append(s.erasure(types));
   974                     }
   975                 }
   976             }
   977             if (context.isSerializable()) {
   978                 addDeserializationCase(refKind, refSym, tree.type, samSym,
   979                         tree, staticArgs, indyType);
   980             }
   981         }
   983         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
   984     }
   986     /**
   987      * Generate an indy method call with given name, type and static bootstrap
   988      * arguments types
   989      */
   990     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
   991             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
   992             Name methName) {
   993         int prevPos = make.pos;
   994         try {
   995             make.at(pos);
   996             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
   997                     syms.stringType,
   998                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
  1000             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
  1001                     bsmName, bsm_staticArgs, List.<Type>nil());
  1003             DynamicMethodSymbol dynSym =
  1004                     new DynamicMethodSymbol(methName,
  1005                                             syms.noSymbol,
  1006                                             bsm.isStatic() ?
  1007                                                 ClassFile.REF_invokeStatic :
  1008                                                 ClassFile.REF_invokeVirtual,
  1009                                             (MethodSymbol)bsm,
  1010                                             indyType,
  1011                                             staticArgs.toArray());
  1013             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1014             qualifier.sym = dynSym;
  1015             qualifier.type = indyType.getReturnType();
  1017             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
  1018             proxyCall.type = indyType.getReturnType();
  1019             return proxyCall;
  1020         } finally {
  1021             make.at(prevPos);
  1024     //where
  1025     private List<Type> bsmStaticArgToTypes(List<Object> args) {
  1026         ListBuffer<Type> argtypes = ListBuffer.lb();
  1027         for (Object arg : args) {
  1028             argtypes.append(bsmStaticArgToType(arg));
  1030         return argtypes.toList();
  1033     private Type bsmStaticArgToType(Object arg) {
  1034         Assert.checkNonNull(arg);
  1035         if (arg instanceof ClassSymbol) {
  1036             return syms.classType;
  1037         } else if (arg instanceof Integer) {
  1038             return syms.intType;
  1039         } else if (arg instanceof Long) {
  1040             return syms.longType;
  1041         } else if (arg instanceof Float) {
  1042             return syms.floatType;
  1043         } else if (arg instanceof Double) {
  1044             return syms.doubleType;
  1045         } else if (arg instanceof String) {
  1046             return syms.stringType;
  1047         } else if (arg instanceof Pool.MethodHandle) {
  1048             return syms.methodHandleType;
  1049         } else if (arg instanceof MethodType) {
  1050             return syms.methodTypeType;
  1051         } else {
  1052             Assert.error("bad static arg " + arg.getClass());
  1053             return null;
  1057     /**
  1058      * Get the opcode associated with this method reference
  1059      */
  1060     private int referenceKind(Symbol refSym) {
  1061         if (refSym.isConstructor()) {
  1062             return ClassFile.REF_newInvokeSpecial;
  1063         } else {
  1064             if (refSym.isStatic()) {
  1065                 return ClassFile.REF_invokeStatic;
  1066             } else if (refSym.enclClass().isInterface()) {
  1067                 return ClassFile.REF_invokeInterface;
  1068             } else {
  1069                 return (refSym.flags() & PRIVATE) != 0 ?
  1070                         ClassFile.REF_invokeSpecial :
  1071                         ClassFile.REF_invokeVirtual;
  1076     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1077     /**
  1078      * This visitor collects information about translation of a lambda expression.
  1079      * More specifically, it keeps track of the enclosing contexts and captured locals
  1080      * accessed by the lambda being translated (as well as other useful info).
  1081      * It also translates away problems for LambdaToMethod.
  1082      */
  1083     class LambdaAnalyzerPreprocessor extends TreeTranslator {
  1085         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1086         private List<Frame> frameStack;
  1088         /**
  1089          * keep the count of lambda expression (used to generate unambiguous
  1090          * names)
  1091          */
  1092         private int lambdaCount = 0;
  1094         /**
  1095          * keep the count of lambda expression defined in given context (used to
  1096          * generate unambiguous names for serializable lambdas)
  1097          */
  1098         private Map<String, Integer> serializableLambdaCounts =
  1099                 new HashMap<String, Integer>();
  1101         private Map<Symbol, JCClassDecl> localClassDefs;
  1103         /**
  1104          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1105          * a static var init context
  1106          */
  1107         private Map<ClassSymbol, Symbol> clinits =
  1108                 new HashMap<ClassSymbol, Symbol>();
  1110         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
  1111             frameStack = List.nil();
  1112             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1113             return translate(tree);
  1116         @Override
  1117         public void visitBlock(JCBlock tree) {
  1118             List<Frame> prevStack = frameStack;
  1119             try {
  1120                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1121                     frameStack = frameStack.prepend(new Frame(tree));
  1123                 super.visitBlock(tree);
  1125             finally {
  1126                 frameStack = prevStack;
  1130         @Override
  1131         public void visitClassDef(JCClassDecl tree) {
  1132             List<Frame> prevStack = frameStack;
  1133             Map<String, Integer> prevSerializableLambdaCount =
  1134                     serializableLambdaCounts;
  1135             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1136             DiagnosticSource prevSource = log.currentSource();
  1137             try {
  1138                 log.useSource(tree.sym.sourcefile);
  1139                 serializableLambdaCounts = new HashMap<String, Integer>();
  1140                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1141                 if (tree.sym.owner.kind == MTH) {
  1142                     localClassDefs.put(tree.sym, tree);
  1144                 if (directlyEnclosingLambda() != null) {
  1145                     tree.sym.owner = owner();
  1146                     if (tree.sym.hasOuterInstance()) {
  1147                         //if a class is defined within a lambda, the lambda must capture
  1148                         //its enclosing instance (if any)
  1149                         TranslationContext<?> localContext = context();
  1150                         while (localContext != null) {
  1151                             if (localContext.tree.getTag() == LAMBDA) {
  1152                                 ((LambdaTranslationContext)localContext)
  1153                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1155                             localContext = localContext.prev;
  1159                 frameStack = frameStack.prepend(new Frame(tree));
  1160                 super.visitClassDef(tree);
  1162             finally {
  1163                 log.useSource(prevSource.getFile());
  1164                 frameStack = prevStack;
  1165                 serializableLambdaCounts = prevSerializableLambdaCount;
  1166                 clinits = prevClinits;
  1170         @Override
  1171         public void visitIdent(JCIdent tree) {
  1172             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1173                 if (tree.sym.kind == VAR &&
  1174                         tree.sym.owner.kind == MTH &&
  1175                         tree.type.constValue() == null) {
  1176                     TranslationContext<?> localContext = context();
  1177                     while (localContext != null) {
  1178                         if (localContext.tree.getTag() == LAMBDA) {
  1179                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1180                             if (block == null) break;
  1181                             ((LambdaTranslationContext)localContext)
  1182                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1184                         localContext = localContext.prev;
  1186                 } else if (tree.sym.owner.kind == TYP) {
  1187                     TranslationContext<?> localContext = context();
  1188                     while (localContext != null) {
  1189                         if (localContext.tree.hasTag(LAMBDA)) {
  1190                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1191                             if (block == null) break;
  1192                             switch (block.getTag()) {
  1193                                 case CLASSDEF:
  1194                                     JCClassDecl cdecl = (JCClassDecl)block;
  1195                                     ((LambdaTranslationContext)localContext)
  1196                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1197                                     break;
  1198                                 default:
  1199                                     Assert.error("bad block kind");
  1202                         localContext = localContext.prev;
  1206             super.visitIdent(tree);
  1209         @Override
  1210         public void visitLambda(JCLambda tree) {
  1211             List<Frame> prevStack = frameStack;
  1212             try {
  1213                 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
  1214                 frameStack = frameStack.prepend(new Frame(tree));
  1215                 for (JCVariableDecl param : tree.params) {
  1216                     context.addSymbol(param.sym, PARAM);
  1217                     frameStack.head.addLocal(param.sym);
  1219                 contextMap.put(tree, context);
  1220                 super.visitLambda(tree);
  1221                 context.complete();
  1223             finally {
  1224                 frameStack = prevStack;
  1228         @Override
  1229         public void visitMethodDef(JCMethodDecl tree) {
  1230             List<Frame> prevStack = frameStack;
  1231             try {
  1232                 frameStack = frameStack.prepend(new Frame(tree));
  1233                 super.visitMethodDef(tree);
  1235             finally {
  1236                 frameStack = prevStack;
  1240         @Override
  1241         public void visitNewClass(JCNewClass tree) {
  1242             if (lambdaNewClassFilter(context(), tree)) {
  1243                 TranslationContext<?> localContext = context();
  1244                 while (localContext != null) {
  1245                     if (localContext.tree.getTag() == LAMBDA) {
  1246                         ((LambdaTranslationContext)localContext)
  1247                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1249                     localContext = localContext.prev;
  1252             if (context() != null && tree.type.tsym.owner.kind == MTH) {
  1253                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1254                 captureLocalClassDefs(tree.type.tsym, lambdaContext);
  1256             super.visitNewClass(tree);
  1258         //where
  1259             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1260                 JCClassDecl localCDef = localClassDefs.get(csym);
  1261                 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
  1262                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1263                         @Override
  1264                         void addFreeVars(ClassSymbol c) {
  1265                             captureLocalClassDefs(c, lambdaContext);
  1267                         @Override
  1268                         void visitSymbol(Symbol sym) {
  1269                             if (sym.kind == VAR &&
  1270                                     sym.owner.kind == MTH &&
  1271                                     ((VarSymbol)sym).getConstValue() == null) {
  1272                                 TranslationContext<?> localContext = context();
  1273                                 while (localContext != null) {
  1274                                     if (localContext.tree.getTag() == LAMBDA) {
  1275                                         JCTree block = capturedDecl(localContext.depth, sym);
  1276                                         if (block == null) break;
  1277                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1279                                     localContext = localContext.prev;
  1283                     };
  1284                     fvc.scan(localCDef);
  1288         /**
  1289          * Method references to local class constructors, may, if the local
  1290          * class references local variables, have implicit constructor
  1291          * parameters added in Lower; As a result, the invokedynamic bootstrap
  1292          * information added in the LambdaToMethod pass will have the wrong
  1293          * signature. Hooks between Lower and LambdaToMethod have been added to
  1294          * handle normal "new" in this case. This visitor converts potentially
  1295          * effected method references into a lambda containing a normal "new" of
  1296          * the class.
  1298          * @param tree
  1299          */
  1300         @Override
  1301         public void visitReference(JCMemberReference tree) {
  1302             if (tree.getMode() == ReferenceMode.NEW
  1303                     && tree.kind != ReferenceKind.ARRAY_CTOR
  1304                     && tree.sym.owner.isLocal()) {
  1305                 MethodSymbol consSym = (MethodSymbol) tree.sym;
  1306                 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
  1307                 Type classType = consSym.owner.type;
  1309                 // Build lambda parameters
  1310                 // partially cloned from TreeMaker.Params until 8014021 is fixed
  1311                 Symbol owner = owner();
  1312                 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
  1313                 int i = 0;
  1314                 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
  1315                     paramBuff.append(make.Param(make.paramName(i++), l.head, owner));
  1317                 List<JCVariableDecl> params = paramBuff.toList();
  1319                 // Make new-class call
  1320                 JCNewClass nc = makeNewClass(classType, make.Idents(params));
  1321                 nc.pos = tree.pos;
  1323                 // Make lambda holding the new-class call
  1324                 JCLambda slam = make.Lambda(params, nc);
  1325                 slam.targets = tree.targets;
  1326                 slam.type = tree.type;
  1327                 slam.pos = tree.pos;
  1329                 // Now it is a lambda, process as such
  1330                 visitLambda(slam);
  1331             } else {
  1332                 super.visitReference(tree);
  1333                 contextMap.put(tree, makeReferenceContext(tree));
  1337         @Override
  1338         public void visitSelect(JCFieldAccess tree) {
  1339             if (context() != null && tree.sym.kind == VAR &&
  1340                         (tree.sym.name == names._this ||
  1341                          tree.sym.name == names._super)) {
  1342                 // A select of this or super means, if we are in a lambda,
  1343                 // we much have an instance context
  1344                 TranslationContext<?> localContext = context();
  1345                 while (localContext != null) {
  1346                     if (localContext.tree.hasTag(LAMBDA)) {
  1347                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1348                         if (clazz == null) break;
  1349                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1351                     localContext = localContext.prev;
  1354             super.visitSelect(tree);
  1357         @Override
  1358         public void visitVarDef(JCVariableDecl tree) {
  1359             TranslationContext<?> context = context();
  1360             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1361                     (LambdaTranslationContext)context :
  1362                     null;
  1363             if (ltc != null) {
  1364                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1365                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1367                 // Check for type variables (including as type arguments).
  1368                 // If they occur within class nested in a lambda, mark for erasure
  1369                 Type type = tree.sym.asType();
  1370                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1371                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1375             List<Frame> prevStack = frameStack;
  1376             try {
  1377                 if (tree.sym.owner.kind == MTH) {
  1378                     frameStack.head.addLocal(tree.sym);
  1380                 frameStack = frameStack.prepend(new Frame(tree));
  1381                 super.visitVarDef(tree);
  1383             finally {
  1384                 frameStack = prevStack;
  1388         private Name lambdaName() {
  1389             return names.lambda.append(names.fromString("" + lambdaCount++));
  1392         /**
  1393          * For a serializable lambda, generate a name which maximizes name
  1394          * stability across deserialization.
  1395          * @param owner
  1396          * @return Name to use for the synthetic lambda method name
  1397          */
  1398         private Name serializedLambdaName(Symbol owner) {
  1399             StringBuilder buf = new StringBuilder();
  1400             buf.append(names.lambda);
  1401             // Append the name of the method enclosing the lambda.
  1402             String methodName = owner.name.toString();
  1403             if (methodName.equals("<clinit>"))
  1404                 methodName = "static";
  1405             else if (methodName.equals("<init>"))
  1406                 methodName = "new";
  1407             buf.append(methodName);
  1408             buf.append('$');
  1409             // Append a hash of the enclosing method signature to differentiate
  1410             // overloaded enclosing methods.  For lambdas enclosed in lambdas,
  1411             // the generated lambda method will not have type yet, but the
  1412             // enclosing method's name will have been generated with this same
  1413             // method, so it will be unique and never be overloaded.
  1414             Assert.check(owner.type != null || directlyEnclosingLambda() != null);
  1415             if (owner.type != null) {
  1416                 int methTypeHash = methodSig(owner.type).hashCode();
  1417                 buf.append(Integer.toHexString(methTypeHash));
  1419             buf.append('$');
  1420             // The above appended name components may not be unique, append a
  1421             // count based on the above name components.
  1422             String temp = buf.toString();
  1423             Integer count = serializableLambdaCounts.get(temp);
  1424             if (count == null) {
  1425                 count = 0;
  1427             buf.append(count++);
  1428             serializableLambdaCounts.put(temp, count);
  1429             return names.fromString(buf.toString());
  1432         /**
  1433          * Return a valid owner given the current declaration stack
  1434          * (required to skip synthetic lambda symbols)
  1435          */
  1436         private Symbol owner() {
  1437             return owner(false);
  1440         @SuppressWarnings("fallthrough")
  1441         private Symbol owner(boolean skipLambda) {
  1442             List<Frame> frameStack2 = frameStack;
  1443             while (frameStack2.nonEmpty()) {
  1444                 switch (frameStack2.head.tree.getTag()) {
  1445                     case VARDEF:
  1446                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1447                             frameStack2 = frameStack2.tail;
  1448                             break;
  1450                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1451                         return initSym(cdecl.sym,
  1452                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1453                     case BLOCK:
  1454                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1455                         return initSym(cdecl2.sym,
  1456                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1457                     case CLASSDEF:
  1458                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1459                     case METHODDEF:
  1460                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1461                     case LAMBDA:
  1462                         if (!skipLambda)
  1463                             return ((LambdaTranslationContext)contextMap
  1464                                     .get(frameStack2.head.tree)).translatedSym;
  1465                     default:
  1466                         frameStack2 = frameStack2.tail;
  1469             Assert.error();
  1470             return null;
  1473         private Symbol initSym(ClassSymbol csym, long flags) {
  1474             boolean isStatic = (flags & STATIC) != 0;
  1475             if (isStatic) {
  1476                 //static clinits are generated in Gen - so we need to fake them
  1477                 Symbol clinit = clinits.get(csym);
  1478                 if (clinit == null) {
  1479                     clinit = makeSyntheticMethod(STATIC,
  1480                             names.clinit,
  1481                             new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
  1482                             csym);
  1483                     clinits.put(csym, clinit);
  1485                 return clinit;
  1486             } else {
  1487                 //get the first constructor and treat it as the instance init sym
  1488                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1489                     return s;
  1492             Assert.error("init not found");
  1493             return null;
  1496         private JCTree directlyEnclosingLambda() {
  1497             if (frameStack.isEmpty()) {
  1498                 return null;
  1500             List<Frame> frameStack2 = frameStack;
  1501             while (frameStack2.nonEmpty()) {
  1502                 switch (frameStack2.head.tree.getTag()) {
  1503                     case CLASSDEF:
  1504                     case METHODDEF:
  1505                         return null;
  1506                     case LAMBDA:
  1507                         return frameStack2.head.tree;
  1508                     default:
  1509                         frameStack2 = frameStack2.tail;
  1512             Assert.error();
  1513             return null;
  1516         private boolean inClassWithinLambda() {
  1517             if (frameStack.isEmpty()) {
  1518                 return false;
  1520             List<Frame> frameStack2 = frameStack;
  1521             boolean classFound = false;
  1522             while (frameStack2.nonEmpty()) {
  1523                 switch (frameStack2.head.tree.getTag()) {
  1524                     case LAMBDA:
  1525                         return classFound;
  1526                     case CLASSDEF:
  1527                         classFound = true;
  1528                         frameStack2 = frameStack2.tail;
  1529                         break;
  1530                     default:
  1531                         frameStack2 = frameStack2.tail;
  1534             // No lambda
  1535             return false;
  1538         /**
  1539          * Return the declaration corresponding to a symbol in the enclosing
  1540          * scope; the depth parameter is used to filter out symbols defined
  1541          * in nested scopes (which do not need to undergo capture).
  1542          */
  1543         private JCTree capturedDecl(int depth, Symbol sym) {
  1544             int currentDepth = frameStack.size() - 1;
  1545             for (Frame block : frameStack) {
  1546                 switch (block.tree.getTag()) {
  1547                     case CLASSDEF:
  1548                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1549                         if (sym.isMemberOf(clazz, types)) {
  1550                             return currentDepth > depth ? null : block.tree;
  1552                         break;
  1553                     case VARDEF:
  1554                         if (((JCVariableDecl)block.tree).sym == sym &&
  1555                                 sym.owner.kind == MTH) { //only locals are captured
  1556                             return currentDepth > depth ? null : block.tree;
  1558                         break;
  1559                     case BLOCK:
  1560                     case METHODDEF:
  1561                     case LAMBDA:
  1562                         if (block.locals != null && block.locals.contains(sym)) {
  1563                             return currentDepth > depth ? null : block.tree;
  1565                         break;
  1566                     default:
  1567                         Assert.error("bad decl kind " + block.tree.getTag());
  1569                 currentDepth--;
  1571             return null;
  1574         private TranslationContext<?> context() {
  1575             for (Frame frame : frameStack) {
  1576                 TranslationContext<?> context = contextMap.get(frame.tree);
  1577                 if (context != null) {
  1578                     return context;
  1581             return null;
  1584         /**
  1585          *  This is used to filter out those identifiers that needs to be adjusted
  1586          *  when translating away lambda expressions
  1587          */
  1588         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1589             return (sym.kind == VAR || sym.kind == MTH)
  1590                     && !sym.isStatic()
  1591                     && sym.name != names.init;
  1594         /**
  1595          * This is used to filter out those new class expressions that need to
  1596          * be qualified with an enclosing tree
  1597          */
  1598         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1599             if (context != null
  1600                     && tree.encl == null
  1601                     && tree.def == null
  1602                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1603                 Type encl = tree.type.getEnclosingType();
  1604                 Type current = context.owner.enclClass().type;
  1605                 while (!current.hasTag(NONE)) {
  1606                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1607                         return true;
  1609                     current = current.getEnclosingType();
  1611                 return false;
  1612             } else {
  1613                 return false;
  1617         private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
  1618             return new LambdaTranslationContext(tree);
  1621         private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
  1622             return new ReferenceTranslationContext(tree);
  1625         private class Frame {
  1626             final JCTree tree;
  1627             List<Symbol> locals;
  1629             public Frame(JCTree tree) {
  1630                 this.tree = tree;
  1633             void addLocal(Symbol sym) {
  1634                 if (locals == null) {
  1635                     locals = List.nil();
  1637                 locals = locals.prepend(sym);
  1641         /**
  1642          * This class is used to store important information regarding translation of
  1643          * lambda expression/method references (see subclasses).
  1644          */
  1645         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1647             /** the underlying (untranslated) tree */
  1648             T tree;
  1650             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1651             Symbol owner;
  1653             /** the depth of this lambda expression in the frame stack */
  1654             int depth;
  1656             /** the enclosing translation context (set for nested lambdas/mref) */
  1657             TranslationContext<?> prev;
  1659             /** list of methods to be bridged by the meta-factory */
  1660             List<Symbol> bridges;
  1662             TranslationContext(T tree) {
  1663                 this.tree = tree;
  1664                 this.owner = owner();
  1665                 this.depth = frameStack.size() - 1;
  1666                 this.prev = context();
  1667                 ClassSymbol csym =
  1668                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
  1669                 this.bridges = types.functionalInterfaceBridges(csym);
  1672             /** does this functional expression need to be created using alternate metafactory? */
  1673             boolean needsAltMetafactory() {
  1674                 return tree.targets.length() > 1 ||
  1675                         isSerializable() ||
  1676                         bridges.length() > 1;
  1679             /** does this functional expression require serialization support? */
  1680             boolean isSerializable() {
  1681                 for (Type target : tree.targets) {
  1682                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
  1683                         return true;
  1686                 return false;
  1690         /**
  1691          * This class retains all the useful information about a lambda expression;
  1692          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1693          * and the used by the main translation routines in order to adjust references
  1694          * to captured locals/members, etc.
  1695          */
  1696         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1698             /** variable in the enclosing context to which this lambda is assigned */
  1699             Symbol self;
  1701             /** map from original to translated lambda parameters */
  1702             Map<Symbol, Symbol> lambdaParams = new LinkedHashMap<Symbol, Symbol>();
  1704             /** map from original to translated lambda locals */
  1705             Map<Symbol, Symbol> lambdaLocals = new LinkedHashMap<Symbol, Symbol>();
  1707             /** map from variables in enclosing scope to translated synthetic parameters */
  1708             Map<Symbol, Symbol> capturedLocals  = new LinkedHashMap<Symbol, Symbol>();
  1710             /** map from class symbols to translated synthetic parameters (for captured member access) */
  1711             Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>();
  1713             /** map from original to translated lambda locals */
  1714             Map<Symbol, Symbol> typeVars = new LinkedHashMap<Symbol, Symbol>();
  1716             /** the synthetic symbol for the method hoisting the translated lambda */
  1717             Symbol translatedSym;
  1719             List<JCVariableDecl> syntheticParams;
  1721             LambdaTranslationContext(JCLambda tree) {
  1722                 super(tree);
  1723                 Frame frame = frameStack.head;
  1724                 if (frame.tree.hasTag(VARDEF)) {
  1725                     self = ((JCVariableDecl)frame.tree).sym;
  1727                 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName();
  1728                 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass());
  1729                 if (dumpLambdaToMethodStats) {
  1730                     log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym);
  1734             /**
  1735              * Translate a symbol of a given kind into something suitable for the
  1736              * synthetic lambda body
  1737              */
  1738             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1739                 Symbol ret;
  1740                 switch (skind) {
  1741                     case CAPTURED_THIS:
  1742                         ret = sym;  // self represented
  1743                         break;
  1744                     case TYPE_VAR:
  1745                         // Just erase the type var
  1746                         ret = new VarSymbol(sym.flags(), name,
  1747                                 types.erasure(sym.type), sym.owner);
  1748                         break;
  1749                     case CAPTURED_VAR:
  1750                         ret = new VarSymbol(SYNTHETIC | FINAL, name, types.erasure(sym.type), translatedSym) {
  1751                             @Override
  1752                             public Symbol baseSymbol() {
  1753                                 //keep mapping with original captured symbol
  1754                                 return sym;
  1756                         };
  1757                         break;
  1758                     default:
  1759                         ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1761                 if (ret != sym) {
  1762                     ret.setDeclarationAttributes(sym.getRawAttributes());
  1763                     ret.setTypeAttributes(sym.getRawTypeAttributes());
  1765                 return ret;
  1768             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1769                 Map<Symbol, Symbol> transMap = null;
  1770                 Name preferredName;
  1771                 switch (skind) {
  1772                     case CAPTURED_THIS:
  1773                         transMap = capturedThis;
  1774                         preferredName = names.fromString("encl$" + capturedThis.size());
  1775                         break;
  1776                     case CAPTURED_VAR:
  1777                         transMap = capturedLocals;
  1778                         preferredName = names.fromString("cap$" + capturedLocals.size());
  1779                         break;
  1780                     case LOCAL_VAR:
  1781                         transMap = lambdaLocals;
  1782                         preferredName = sym.name;
  1783                         break;
  1784                     case PARAM:
  1785                         transMap = lambdaParams;
  1786                         preferredName = sym.name;
  1787                         break;
  1788                     case TYPE_VAR:
  1789                         transMap = typeVars;
  1790                         preferredName = sym.name;
  1791                         break;
  1792                     default: throw new AssertionError();
  1794                 if (!transMap.containsKey(sym)) {
  1795                     transMap.put(sym, translate(preferredName, sym, skind));
  1799             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind... skinds) {
  1800                 LinkedHashMap<Symbol, Symbol> translationMap = new LinkedHashMap<Symbol, Symbol>();
  1801                 for (LambdaSymbolKind skind : skinds) {
  1802                     switch (skind) {
  1803                         case CAPTURED_THIS:
  1804                             translationMap.putAll(capturedThis);
  1805                             break;
  1806                         case CAPTURED_VAR:
  1807                             translationMap.putAll(capturedLocals);
  1808                             break;
  1809                         case LOCAL_VAR:
  1810                             translationMap.putAll(lambdaLocals);
  1811                             break;
  1812                         case PARAM:
  1813                             translationMap.putAll(lambdaParams);
  1814                             break;
  1815                         case TYPE_VAR:
  1816                             translationMap.putAll(typeVars);
  1817                             break;
  1818                         default: throw new AssertionError();
  1821                 return translationMap;
  1824             /**
  1825              * The translatedSym is not complete/accurate until the analysis is
  1826              * finished.  Once the analysis is finished, the translatedSym is
  1827              * "completed" -- updated with type information, access modifiers,
  1828              * and full parameter list.
  1829              */
  1830             void complete() {
  1831                 if (syntheticParams != null) {
  1832                     return;
  1834                 boolean inInterface = translatedSym.owner.isInterface();
  1835                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1837                 // If instance access isn't needed, make it static.
  1838                 // Interface instance methods must be default methods.
  1839                 // Awaiting VM channges, default methods are public
  1840                 translatedSym.flags_field = SYNTHETIC |
  1841                         ((inInterface && thisReferenced)? PUBLIC : PRIVATE) |
  1842                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
  1844                 //compute synthetic params
  1845                 ListBuffer<JCVariableDecl> params = ListBuffer.lb();
  1847                 // The signature of the method is augmented with the following
  1848                 // synthetic parameters:
  1849                 //
  1850                 // 1) reference to enclosing contexts captured by the lambda expression
  1851                 // 2) enclosing locals captured by the lambda expression
  1852                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR, PARAM).values()) {
  1853                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1856                 syntheticParams = params.toList();
  1858                 //prepend synthetic args to translated lambda method signature
  1859                 translatedSym.type = types.createMethodTypeWithParameters(
  1860                         generatedLambdaSig(),
  1861                         TreeInfo.types(syntheticParams));
  1864             Type generatedLambdaSig() {
  1865                 return types.erasure(tree.getDescriptorType(types));
  1869         /**
  1870          * This class retains all the useful information about a method reference;
  1871          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1872          * and the used by the main translation routines in order to adjust method
  1873          * references (i.e. in case a bridge is needed)
  1874          */
  1875         private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  1877             final boolean isSuper;
  1878             final Symbol bridgeSym;
  1880             ReferenceTranslationContext(JCMemberReference tree) {
  1881                 super(tree);
  1882                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  1883                 this.bridgeSym = needsBridge()
  1884                         ? makeSyntheticMethod(isSuper ? 0 : STATIC,
  1885                                               lambdaName().append(names.fromString("$bridge")), null,
  1886                                               owner.enclClass())
  1887                         : null;
  1888                 if (dumpLambdaToMethodStats) {
  1889                     String key = bridgeSym == null ?
  1890                             "mref.stat" : "mref.stat.1";
  1891                     log.note(tree, key, needsAltMetafactory(), bridgeSym);
  1895             /**
  1896              * Get the opcode associated with this method reference
  1897              */
  1898             int referenceKind() {
  1899                 return LambdaToMethod.this.referenceKind(needsBridge() ? bridgeSym : tree.sym);
  1902             boolean needsVarArgsConversion() {
  1903                 return tree.varargsElement != null;
  1906             /**
  1907              * @return Is this an array operation like clone()
  1908              */
  1909             boolean isArrayOp() {
  1910                 return tree.sym.owner == syms.arrayClass;
  1913             boolean isPrivateConstructor() {
  1914                 //hack needed to workaround 292 bug (8005122)
  1915                 //when 292 issue is fixed we should simply remove this
  1916                 return tree.sym.name == names.init &&
  1917                         (tree.sym.flags() & PRIVATE) != 0;
  1920             boolean receiverAccessible() {
  1921                 //hack needed to workaround 292 bug (7087658)
  1922                 //when 292 issue is fixed we should remove this and change the backend
  1923                 //code to always generate a method handle to an accessible method
  1924                 return tree.ownerAccessible;
  1927             /**
  1928              * Does this reference needs a bridge (i.e. var args need to be
  1929              * expanded or "super" is used)
  1930              */
  1931             final boolean needsBridge() {
  1932                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  1933                         isPrivateConstructor() || !receiverAccessible();
  1936             Type generatedRefSig() {
  1937                 return types.erasure(tree.sym.type);
  1940             Type bridgedRefSig() {
  1941                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
  1945     // </editor-fold>
  1947     enum LambdaSymbolKind {
  1948         CAPTURED_VAR,
  1949         CAPTURED_THIS,
  1950         LOCAL_VAR,
  1951         PARAM,
  1952         TYPE_VAR;
  1955     /**
  1956      * ****************************************************************
  1957      * Signature Generation
  1958      * ****************************************************************
  1959      */
  1961     private String methodSig(Type type) {
  1962         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1963         sg.assembleSig(type);
  1964         return sg.toString();
  1967     private String classSig(Type type) {
  1968         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1969         sg.assembleClassSig(type);
  1970         return sg.toString();
  1973     /**
  1974      * Signature Generation
  1975      */
  1976     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  1978         /**
  1979          * An output buffer for type signatures.
  1980          */
  1981         StringBuilder sb = new StringBuilder();
  1983         L2MSignatureGenerator() {
  1984             super(types);
  1987         @Override
  1988         protected void append(char ch) {
  1989             sb.append(ch);
  1992         @Override
  1993         protected void append(byte[] ba) {
  1994             sb.append(new String(ba));
  1997         @Override
  1998         protected void append(Name name) {
  1999             sb.append(name.toString());
  2002         @Override
  2003         public String toString() {
  2004             return sb.toString();

mercurial