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

Sat, 01 Jun 2013 21:57:56 +0100

author
vromero
date
Sat, 01 Jun 2013 21:57:56 +0100
changeset 1791
e9855150c5b0
parent 1762
31ef33db5e0e
child 1802
8fb68f73d4b1
permissions
-rw-r--r--

8010737: javac, known parameter's names should be copied to automatically generated constructors for inner classes
Reviewed-by: mcimadamore

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

mercurial