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

Mon, 23 Sep 2013 10:42:38 +0200

author
alundblad
date
Mon, 23 Sep 2013 10:42:38 +0200
changeset 2047
5f915a0c9615
parent 2043
571f8ebc2d51
child 2107
1ce8405af5fe
permissions
-rw-r--r--

6386236: Please rename com.sun.tools.javac.util.ListBuffer.lb()
Summary: Static factory method ListBuffer.lb removed. Replaced by constructor calls.
Reviewed-by: jfranck, jjg

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

mercurial