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

Tue, 05 Mar 2013 14:19:49 +0000

author
mcimadamore
date
Tue, 05 Mar 2013 14:19:49 +0000
changeset 1615
12202e6ab78a
parent 1614
a708c5f1da06
child 1619
c98b3e96c726
permissions
-rw-r--r--

8009129: Illegal access error when calling method reference
Summary: Javac generates method handle referencing non public type
Reviewed-by: jjg, rfield

     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.*;
    30 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
    31 import com.sun.tools.javac.tree.TreeMaker;
    32 import com.sun.tools.javac.tree.TreeScanner;
    33 import com.sun.tools.javac.tree.TreeTranslator;
    34 import com.sun.tools.javac.code.Kinds;
    35 import com.sun.tools.javac.code.Scope;
    36 import com.sun.tools.javac.code.Symbol;
    37 import com.sun.tools.javac.code.Symbol.ClassSymbol;
    38 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
    39 import com.sun.tools.javac.code.Symbol.MethodSymbol;
    40 import com.sun.tools.javac.code.Symbol.VarSymbol;
    41 import com.sun.tools.javac.code.Symtab;
    42 import com.sun.tools.javac.code.Type;
    43 import com.sun.tools.javac.code.Type.ClassType;
    44 import com.sun.tools.javac.code.Type.MethodType;
    45 import com.sun.tools.javac.code.Types;
    46 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzer.*;
    47 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
    48 import com.sun.tools.javac.jvm.*;
    49 import com.sun.tools.javac.util.*;
    50 import com.sun.tools.javac.util.List;
    51 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    52 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
    54 import java.util.HashMap;
    55 import java.util.LinkedHashMap;
    56 import java.util.Map;
    58 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
    59 import static com.sun.tools.javac.code.Flags.*;
    60 import static com.sun.tools.javac.code.Kinds.*;
    61 import static com.sun.tools.javac.code.TypeTag.*;
    62 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    64 /**
    65  * This pass desugars lambda expressions into static methods
    66  *
    67  *  <p><b>This is NOT part of any supported API.
    68  *  If you write code that depends on this, you do so at your own risk.
    69  *  This code and its internal interfaces are subject to change or
    70  *  deletion without notice.</b>
    71  */
    72 public class LambdaToMethod extends TreeTranslator {
    74     private Lower lower;
    75     private Names names;
    76     private Symtab syms;
    77     private Resolve rs;
    78     private TreeMaker make;
    79     private Types types;
    80     private TransTypes transTypes;
    81     private Env<AttrContext> attrEnv;
    83     /** the analyzer scanner */
    84     private LambdaAnalyzer analyzer;
    86     /** map from lambda trees to translation contexts */
    87     private Map<JCTree, TranslationContext<?>> contextMap;
    89     /** current translation context (visitor argument) */
    90     private TranslationContext<?> context;
    92     /** info about the current class being processed */
    93     private KlassInfo kInfo;
    95     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
    96     public static final int FLAG_SERIALIZABLE = 1 << 0;
    98     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
    99     public static final int FLAG_MARKERS = 1 << 1;
   101     private class KlassInfo {
   103         /**
   104          * list of methods to append
   105          */
   106         private ListBuffer<JCTree> appendedMethodList;
   108         /**
   109          * list of deserialization cases
   110          */
   111         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   113        /**
   114          * deserialize method symbol
   115          */
   116         private final MethodSymbol deserMethodSym;
   118         /**
   119          * deserialize method parameter symbol
   120          */
   121         private final VarSymbol deserParamSym;
   123         private KlassInfo(Symbol kSym) {
   124             appendedMethodList = ListBuffer.lb();
   125             deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
   126             long flags = PRIVATE | STATIC | SYNTHETIC;
   127             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
   128                     List.<Type>nil(), syms.methodClass);
   129             deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym);
   130             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
   131                     syms.serializedLambdaType, deserMethodSym);
   132         }
   134         private void addMethod(JCTree decl) {
   135             appendedMethodList = appendedMethodList.prepend(decl);
   136         }
   137     }
   139     // <editor-fold defaultstate="collapsed" desc="Instantiating">
   140     private static final Context.Key<LambdaToMethod> unlambdaKey =
   141             new Context.Key<LambdaToMethod>();
   143     public static LambdaToMethod instance(Context context) {
   144         LambdaToMethod instance = context.get(unlambdaKey);
   145         if (instance == null) {
   146             instance = new LambdaToMethod(context);
   147         }
   148         return instance;
   149     }
   151     private LambdaToMethod(Context context) {
   152         lower = Lower.instance(context);
   153         names = Names.instance(context);
   154         syms = Symtab.instance(context);
   155         rs = Resolve.instance(context);
   156         make = TreeMaker.instance(context);
   157         types = Types.instance(context);
   158         transTypes = TransTypes.instance(context);
   159         analyzer = new LambdaAnalyzer();
   160     }
   161     // </editor-fold>
   163     // <editor-fold defaultstate="collapsed" desc="translate methods">
   164     @Override
   165     public <T extends JCTree> T translate(T tree) {
   166         TranslationContext<?> newContext = contextMap.get(tree);
   167         return translate(tree, newContext != null ? newContext : context);
   168     }
   170     public <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
   171         TranslationContext<?> prevContext = context;
   172         try {
   173             context = newContext;
   174             return super.translate(tree);
   175         }
   176         finally {
   177             context = prevContext;
   178         }
   179     }
   181     public <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
   182         ListBuffer<T> buf = ListBuffer.lb();
   183         for (T tree : trees) {
   184             buf.append(translate(tree, newContext));
   185         }
   186         return buf.toList();
   187     }
   189     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
   190         this.make = make;
   191         this.attrEnv = env;
   192         this.context = null;
   193         this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
   194         return translate(cdef);
   195     }
   196     // </editor-fold>
   198     // <editor-fold defaultstate="collapsed" desc="visitor methods">
   199     /**
   200      * Visit a class.
   201      * Maintain the translatedMethodList across nested classes.
   202      * Append the translatedMethodList to the class after it is translated.
   203      * @param tree
   204      */
   205     @Override
   206     public void visitClassDef(JCClassDecl tree) {
   207         if (tree.sym.owner.kind == PCK) {
   208             //analyze class
   209             analyzer.analyzeClass(tree);
   210         }
   211         KlassInfo prevKlassInfo = kInfo;
   212         try {
   213             kInfo = new KlassInfo(tree.sym);
   214             super.visitClassDef(tree);
   215             if (!kInfo.deserializeCases.isEmpty()) {
   216                 kInfo.addMethod(makeDeserializeMethod(tree.sym));
   217             }
   218             //add all translated instance methods here
   219             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
   220             tree.defs = tree.defs.appendList(newMethods);
   221             for (JCTree lambda : newMethods) {
   222                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
   223             }
   224             result = tree;
   225         } finally {
   226             kInfo = prevKlassInfo;
   227         }
   228     }
   230     /**
   231      * Translate a lambda into a method to be inserted into the class.
   232      * Then replace the lambda site with an invokedynamic call of to lambda
   233      * meta-factory, which will use the lambda method.
   234      * @param tree
   235      */
   236     @Override
   237     public void visitLambda(JCLambda tree) {
   238         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
   239         MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
   240         MethodType lambdaType = (MethodType) sym.type;
   242         //create the method declaration hoisting the lambda body
   243         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
   244                 sym.name,
   245                 make.QualIdent(lambdaType.getReturnType().tsym),
   246                 List.<JCTypeParameter>nil(),
   247                 localContext.syntheticParams,
   248                 lambdaType.getThrownTypes() == null ?
   249                     List.<JCExpression>nil() :
   250                     make.Types(lambdaType.getThrownTypes()),
   251                 null,
   252                 null);
   253         lambdaDecl.sym = sym;
   254         lambdaDecl.type = lambdaType;
   256         //translate lambda body
   257         //As the lambda body is translated, all references to lambda locals,
   258         //captured variables, enclosing members are adjusted accordingly
   259         //to refer to the static method parameters (rather than i.e. acessing to
   260         //captured members directly).
   261         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
   263         //Add the method to the list of methods to be added to this class.
   264         kInfo.addMethod(lambdaDecl);
   266         //now that we have generated a method for the lambda expression,
   267         //we can translate the lambda into a method reference pointing to the newly
   268         //created method.
   269         //
   270         //Note that we need to adjust the method handle so that it will match the
   271         //signature of the SAM descriptor - this means that the method reference
   272         //should be added the following synthetic arguments:
   273         //
   274         // * the "this" argument if it is an instance method
   275         // * enclosing locals captured by the lambda expression
   277         ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
   279         if (!sym.isStatic()) {
   280             syntheticInits.append(makeThis(
   281                     sym.owner.enclClass().asType(),
   282                     localContext.owner.enclClass()));
   283         }
   285         //add captured locals
   286         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
   287             if (fv != localContext.self) {
   288                 JCTree captured_local = make.Ident(fv).setType(fv.type);
   289                 syntheticInits.append((JCExpression) captured_local);
   290             }
   291         }
   293         //then, determine the arguments to the indy call
   294         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   296         //build a sam instance using an indy call to the meta-factory
   297         int refKind = referenceKind(sym);
   299         //convert to an invokedynamic call
   300         result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args);
   301     }
   303     private JCIdent makeThis(Type type, Symbol owner) {
   304         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
   305                 names._this,
   306                 type,
   307                 owner);
   308         return make.Ident(_this);
   309     }
   311     /**
   312      * Translate a method reference into an invokedynamic call to the
   313      * meta-factory.
   314      * @param tree
   315      */
   316     @Override
   317     public void visitReference(JCMemberReference tree) {
   318         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   320         //first determine the method symbol to be used to generate the sam instance
   321         //this is either the method reference symbol, or the bridged reference symbol
   322         Symbol refSym = localContext.needsBridge() ?
   323             localContext.bridgeSym :
   324             tree.sym;
   326         //build the bridge method, if needed
   327         if (localContext.needsBridge()) {
   328             bridgeMemberReference(tree, localContext);
   329         }
   331         //the qualifying expression is treated as a special captured arg
   332         JCExpression init;
   333         switch(tree.kind) {
   335             case IMPLICIT_INNER:    /** Inner :: new */
   336             case SUPER:             /** super :: instMethod */
   337                 init = makeThis(
   338                     localContext.owner.enclClass().asType(),
   339                     localContext.owner.enclClass());
   340                 break;
   342             case BOUND:             /** Expr :: instMethod */
   343                 init = tree.getQualifierExpression();
   344                 break;
   346             case UNBOUND:           /** Type :: instMethod */
   347             case STATIC:            /** Type :: staticMethod */
   348             case TOPLEVEL:          /** Top level :: new */
   349             case ARRAY_CTOR:        /** ArrayType :: new */
   350                 init = null;
   351                 break;
   353             default:
   354                 throw new InternalError("Should not have an invalid kind");
   355         }
   357         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
   360         //build a sam instance using an indy call to the meta-factory
   361         result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args);
   362     }
   364     /**
   365      * Translate identifiers within a lambda to the mapped identifier
   366      * @param tree
   367      */
   368     @Override
   369     public void visitIdent(JCIdent tree) {
   370         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
   371             super.visitIdent(tree);
   372         } else {
   373             LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
   374             if (lambdaContext.getSymbolMap(PARAM).containsKey(tree.sym)) {
   375                 Symbol translatedSym = lambdaContext.getSymbolMap(PARAM).get(tree.sym);
   376                 result = make.Ident(translatedSym).setType(tree.type);
   377             } else if (lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   378                 Symbol translatedSym = lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
   379                 result = make.Ident(translatedSym).setType(tree.type);
   380             } else if (lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   381                 Symbol translatedSym = lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   382                 result = make.Ident(translatedSym).setType(translatedSym.type);
   383             } else if (lambdaContext.getSymbolMap(CAPTURED_VAR).containsKey(tree.sym)) {
   384                 Symbol translatedSym = lambdaContext.getSymbolMap(CAPTURED_VAR).get(tree.sym);
   385                 result = make.Ident(translatedSym).setType(tree.type);
   386             } else {
   387                 if (tree.sym.owner.kind == Kinds.TYP) {
   388                     for (Map.Entry<Symbol, Symbol> encl_entry : lambdaContext.getSymbolMap(CAPTURED_THIS).entrySet()) {
   389                         if (tree.sym.isMemberOf((ClassSymbol) encl_entry.getKey(), types)) {
   390                             JCExpression enclRef = make.Ident(encl_entry.getValue());
   391                             result = tree.sym.name == names._this
   392                                     ? enclRef.setType(tree.type)
   393                                     : make.Select(enclRef, tree.sym).setType(tree.type);
   394                             result = tree;
   395                             return;
   396                         }
   397                     }
   398                 }
   399                 //access to untranslated symbols (i.e. compile-time constants,
   400                 //members defined inside the lambda body, etc.) )
   401                 super.visitIdent(tree);
   402             }
   403         }
   404     }
   406     @Override
   407     public void visitVarDef(JCVariableDecl tree) {
   408         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
   409         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   410             JCExpression init = translate(tree.init);
   411             result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
   412         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   413             JCExpression init = translate(tree.init);
   414             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   415             result = make.VarDef(xsym, init);
   416             // Replace the entered symbol for this variable
   417             Scope sc = tree.sym.owner.members();
   418             if (sc != null) {
   419                 sc.remove(tree.sym);
   420                 sc.enter(xsym);
   421             }
   422         } else {
   423             super.visitVarDef(tree);
   424         }
   425     }
   427     // </editor-fold>
   429     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   431     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   432         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   433                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   434                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   435     }
   437     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   438         Type restype = lambdaMethodDecl.type.getReturnType();
   439         boolean isLambda_void = expr.type.hasTag(VOID);
   440         boolean isTarget_void = restype.hasTag(VOID);
   441         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   442         if (isTarget_void) {
   443             //target is void:
   444             // BODY;
   445             JCStatement stat = make.Exec(expr);
   446             return make.Block(0, List.<JCStatement>of(stat));
   447         } else if (isLambda_void && isTarget_Void) {
   448             //void to Void conversion:
   449             // BODY; return null;
   450             ListBuffer<JCStatement> stats = ListBuffer.lb();
   451             stats.append(make.Exec(expr));
   452             stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   453             return make.Block(0, stats.toList());
   454         } else {
   455             //non-void to non-void conversion:
   456             // return (TYPE)BODY;
   457             JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   458             return make.Block(0, List.<JCStatement>of(make.Return(retExpr)));
   459         }
   460     }
   462     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   463         final Type restype = lambdaMethodDecl.type.getReturnType();
   464         final boolean isTarget_void = restype.hasTag(VOID);
   465         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   467         class LambdaBodyTranslator extends TreeTranslator {
   469             @Override
   470             public void visitClassDef(JCClassDecl tree) {
   471                 //do NOT recurse on any inner classes
   472                 result = tree;
   473             }
   475             @Override
   476             public void visitLambda(JCLambda tree) {
   477                 //do NOT recurse on any nested lambdas
   478                 result = tree;
   479             }
   481             @Override
   482             public void visitReturn(JCReturn tree) {
   483                 boolean isLambda_void = tree.expr == null;
   484                 if (isTarget_void && !isLambda_void) {
   485                     //Void to void conversion:
   486                     // { TYPE $loc = RET-EXPR; return; }
   487                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   488                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   489                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   490                 } else if (!isTarget_void || !isLambda_void) {
   491                     //non-void to non-void conversion:
   492                     // return (TYPE)RET-EXPR;
   493                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   494                     result = tree;
   495                 } else {
   496                     result = tree;
   497                 }
   499             }
   500         }
   502         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   503         if (completeNormally && isTarget_Void) {
   504             //there's no return statement and the lambda (possibly inferred)
   505             //return type is java.lang.Void; emit a synthetic return statement
   506             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   507         }
   508         return trans_block;
   509     }
   511     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   512         ListBuffer<JCCase> cases = ListBuffer.lb();
   513         ListBuffer<JCBreak> breaks = ListBuffer.lb();
   514         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   515             JCBreak br = make.Break(null);
   516             breaks.add(br);
   517             List<JCStatement> stmts = entry.getValue().append(br).toList();
   518             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   519         }
   520         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   521         for (JCBreak br : breaks) {
   522             br.target = sw;
   523         }
   524         JCBlock body = make.Block(0L, List.<JCStatement>of(
   525                 sw,
   526                 make.Throw(makeNewClass(
   527                     syms.illegalArgumentExceptionType,
   528                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   529         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   530                         names.deserializeLambda,
   531                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   532                         List.<JCTypeParameter>nil(),
   533                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   534                         List.<JCExpression>nil(),
   535                         body,
   536                         null);
   537         deser.sym = kInfo.deserMethodSym;
   538         deser.type = kInfo.deserMethodSym.type;
   539         //System.err.printf("DESER: '%s'\n", deser);
   540         return deser;
   541     }
   543     /** Make an attributed class instance creation expression.
   544      *  @param ctype    The class type.
   545      *  @param args     The constructor arguments.
   546      */
   547     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   548         JCNewClass tree = make.NewClass(null,
   549             null, make.QualIdent(ctype.tsym), args, null);
   550         tree.constructor = rs.resolveConstructor(
   551             null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil());
   552         tree.type = ctype;
   553         return tree;
   554     }
   556     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   557             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   558         String functionalInterfaceClass = classSig(targetType);
   559         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   560         String functionalInterfaceMethodSignature = methodSig(types.erasure(samSym.type));
   561         String implClass = classSig(refSym.owner.type);
   562         String implMethodName = refSym.getQualifiedName().toString();
   563         String implMethodSignature = methodSig(types.erasure(refSym.type));
   565         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   566         ListBuffer<JCExpression> serArgs = ListBuffer.lb();
   567         int i = 0;
   568         for (Type t : indyType.getParameterTypes()) {
   569             List<JCExpression> indexAsArg = ListBuffer.<JCExpression>lb().append(make.Literal(i)).toList();
   570             List<Type> argTypes = ListBuffer.<Type>lb().append(syms.intType).toList();
   571             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   572             ++i;
   573         }
   574         JCStatement stmt = make.If(
   575                 deserTest(deserTest(deserTest(deserTest(deserTest(
   576                     kindTest,
   577                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   578                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   579                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   580                     "getImplClass", implClass),
   581                     "getImplMethodSignature", implMethodSignature),
   582                 make.Return(makeIndyCall(
   583                     pos,
   584                     syms.lambdaMetafactory,
   585                     names.altMetaFactory,
   586                     staticArgs, indyType, serArgs.toList())),
   587                 null);
   588         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   589         if (stmts == null) {
   590             stmts = ListBuffer.lb();
   591             kInfo.deserializeCases.put(implMethodName, stmts);
   592         }
   593         /****
   594         System.err.printf("+++++++++++++++++\n");
   595         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   596         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   597         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   598         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   599         System.err.printf("*implClass: '%s'\n", implClass);
   600         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   601         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   602         ****/
   603         stmts.append(stmt);
   604     }
   606     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   607         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   608         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   609         testExpr.setType(syms.booleanType);
   610         return testExpr;
   611     }
   613     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   614         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   615         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   616         JCMethodInvocation eqtest = make.Apply(
   617                 List.<JCExpression>nil(),
   618                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   619                 List.<JCExpression>of(make.Literal(lit)));
   620         eqtest.setType(syms.booleanType);
   621         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   622         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   623         compound.setType(syms.booleanType);
   624         return compound;
   625     }
   627     private JCExpression deserGetter(String func, Type type) {
   628         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   629     }
   631     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   632         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   633         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   634         return make.Apply(
   635                     List.<JCExpression>nil(),
   636                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   637                     args).setType(type);
   638     }
   640     /**
   641      * Create new synthetic method with given flags, name, type, owner
   642      */
   643     private MethodSymbol makeSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   644         return new MethodSymbol(flags | SYNTHETIC, name, type, owner);
   645     }
   647     /**
   648      * Create new synthetic variable with given flags, name, type, owner
   649      */
   650     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   651         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   652     }
   654     /**
   655      * Create new synthetic variable with given flags, name, type, owner
   656      */
   657     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   658         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   659     }
   661     /**
   662      * Set varargsElement field on a given tree (must be either a new class tree
   663      * or a method call tree)
   664      */
   665     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   666         if (varargsElement != null) {
   667             switch (tree.getTag()) {
   668                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   669                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   670                 default: throw new AssertionError();
   671             }
   672         }
   673     }
   675     /**
   676      * Convert method/constructor arguments by inserting appropriate cast
   677      * as required by type-erasure - this is needed when bridging a lambda/method
   678      * reference, as the bridged signature might require downcast to be compatible
   679      * with the generated signature.
   680      */
   681     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   682        Assert.check(meth.kind == Kinds.MTH);
   683        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   684        if (varargsElement != null) {
   685            Assert.check((meth.flags() & VARARGS) != 0);
   686        }
   687        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   688     }
   690     // </editor-fold>
   692     /**
   693      * Generate an adapter method "bridge" for a method reference which cannot
   694      * be used directly.
   695      */
   696     private class MemberReferenceBridger {
   698         private final JCMemberReference tree;
   699         private final ReferenceTranslationContext localContext;
   700         private final ListBuffer<JCExpression> args = ListBuffer.lb();
   701         private final ListBuffer<JCVariableDecl> params = ListBuffer.lb();
   703         MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
   704             this.tree = tree;
   705             this.localContext = localContext;
   706         }
   708         /**
   709          * Generate the bridge
   710          */
   711         JCMethodDecl bridge() {
   712             int prevPos = make.pos;
   713             try {
   714                 make.at(tree);
   715                 Type samDesc = localContext.bridgedRefSig();
   716                 List<Type> samPTypes = samDesc.getParameterTypes();
   718                 //an extra argument is prepended to the signature of the bridge in case
   719                 //the member reference is an instance method reference (in which case
   720                 //the receiver expression is passed to the bridge itself).
   721                 Type recType = null;
   722                 switch (tree.kind) {
   723                     case IMPLICIT_INNER:
   724                         recType = tree.sym.owner.type.getEnclosingType();
   725                         break;
   726                     case BOUND:
   727                         recType = tree.getQualifierExpression().type;
   728                         break;
   729                     case UNBOUND:
   730                         recType = samPTypes.head;
   731                         samPTypes = samPTypes.tail;
   732                         break;
   733                 }
   735                 //generate the parameter list for the bridged member reference - the
   736                 //bridge signature will match the signature of the target sam descriptor
   738                 VarSymbol rcvr = (recType == null)
   739                         ? null
   740                         : addParameter("rec$", recType, false);
   742                 List<Type> refPTypes = tree.sym.type.getParameterTypes();
   743                 int refSize = refPTypes.size();
   744                 int samSize = samPTypes.size();
   745                 // Last parameter to copy from referenced method
   746                 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
   748                 List<Type> l = refPTypes;
   749                 // Use parameter types of the referenced method, excluding final var args
   750                 for (int i = 0; l.nonEmpty() && i < last; ++i) {
   751                     addParameter("x$" + i, l.head, true);
   752                     l = l.tail;
   753                 }
   754                 // Flatten out the var args
   755                 for (int i = last; i < samSize; ++i) {
   756                     addParameter("xva$" + i, tree.varargsElement, true);
   757                 }
   759                 //generate the bridge method declaration
   760                 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
   761                         localContext.bridgeSym.name,
   762                         make.QualIdent(samDesc.getReturnType().tsym),
   763                         List.<JCTypeParameter>nil(),
   764                         params.toList(),
   765                         tree.sym.type.getThrownTypes() == null
   766                         ? List.<JCExpression>nil()
   767                         : make.Types(tree.sym.type.getThrownTypes()),
   768                         null,
   769                         null);
   770                 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
   771                 bridgeDecl.type = localContext.bridgeSym.type =
   772                         types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
   774                 //bridge method body generation - this can be either a method call or a
   775                 //new instance creation expression, depending on the member reference kind
   776                 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
   777                         ? bridgeExpressionInvoke(makeReceiver(rcvr))
   778                         : bridgeExpressionNew();
   780                 //the body is either a return expression containing a method call,
   781                 //or the method call itself, depending on whether the return type of
   782                 //the bridge is non-void/void.
   783                 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
   785                 return bridgeDecl;
   786             } finally {
   787                 make.at(prevPos);
   788             }
   789         }
   790         //where
   791             private JCExpression makeReceiver(VarSymbol rcvr) {
   792                 if (rcvr == null) return null;
   793                 JCExpression rcvrExpr = make.Ident(rcvr);
   794                 Type rcvrType = tree.sym.enclClass().type;
   795                 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   796                     rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   797                 }
   798                 return rcvrExpr;
   799             }
   801         /**
   802          * determine the receiver of the bridged method call - the receiver can
   803          * be either the synthetic receiver parameter or a type qualifier; the
   804          * original qualifier expression is never used here, as it might refer
   805          * to symbols not available in the static context of the bridge
   806          */
   807         private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
   808             JCExpression qualifier =
   809                     tree.sym.isStatic() ?
   810                         make.Type(tree.sym.owner.type) :
   811                         (rcvr != null) ?
   812                             rcvr :
   813                             tree.getQualifierExpression();
   815             //create the qualifier expression
   816             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   817             select.sym = tree.sym;
   818             select.type = tree.sym.erasure(types);
   820             //create the method call expression
   821             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   822                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   823                     setType(tree.sym.erasure(types).getReturnType());
   825             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   826             setVarargsIfNeeded(apply, tree.varargsElement);
   827             return apply;
   828         }
   830         /**
   831          * the enclosing expression is either 'null' (no enclosing type) or set
   832          * to the first bridge synthetic parameter
   833          */
   834         private JCExpression bridgeExpressionNew() {
   835             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   836                 //create the array creation expression
   837                 JCNewArray newArr = make.NewArray(
   838                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   839                         List.of(make.Ident(params.first())),
   840                         null);
   841                 newArr.type = tree.getQualifierExpression().type;
   842                 return newArr;
   843             } else {
   844                 JCExpression encl = null;
   845                 switch (tree.kind) {
   846                     case UNBOUND:
   847                     case IMPLICIT_INNER:
   848                         encl = make.Ident(params.first());
   849                 }
   851                 //create the instance creation expression
   852                 JCNewClass newClass = make.NewClass(encl,
   853                         List.<JCExpression>nil(),
   854                         make.Type(tree.getQualifierExpression().type),
   855                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   856                         null);
   857                 newClass.constructor = tree.sym;
   858                 newClass.constructorType = tree.sym.erasure(types);
   859                 newClass.type = tree.getQualifierExpression().type;
   860                 setVarargsIfNeeded(newClass, tree.varargsElement);
   861                 return newClass;
   862             }
   863         }
   865         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   866             VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
   867             params.append(make.VarDef(vsym, null));
   868             if (genArg) {
   869                 args.append(make.Ident(vsym));
   870             }
   871             return vsym;
   872         }
   873     }
   875     /**
   876      * Bridges a member reference - this is needed when:
   877      * * Var args in the referenced method need to be flattened away
   878      * * super is used
   879      */
   880     private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
   881         kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
   882     }
   884     /**
   885      * Generate an indy method call to the meta factory
   886      */
   887     private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory,
   888             boolean isSerializable, int refKind, Symbol refSym, List<JCExpression> indy_args) {
   889         //determine the static bsm args
   890         Type mtype = types.erasure(tree.descriptorType);
   891         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   892         List<Object> staticArgs = List.<Object>of(
   893                 new Pool.MethodHandle(ClassFile.REF_invokeInterface,
   894                     types.findDescriptorSymbol(tree.type.tsym), types),
   895                 new Pool.MethodHandle(refKind, refSym, types),
   896                 new MethodType(mtype.getParameterTypes(),
   897                         mtype.getReturnType(),
   898                         mtype.getThrownTypes(),
   899                         syms.methodClass));
   901         //computed indy arg types
   902         ListBuffer<Type> indy_args_types = ListBuffer.lb();
   903         for (JCExpression arg : indy_args) {
   904             indy_args_types.append(arg.type);
   905         }
   907         //finally, compute the type of the indy call
   908         MethodType indyType = new MethodType(indy_args_types.toList(),
   909                 tree.type,
   910                 List.<Type>nil(),
   911                 syms.methodClass);
   913         Name metafactoryName = needsAltMetafactory ?
   914                 names.altMetaFactory : names.metaFactory;
   916         if (needsAltMetafactory) {
   917             ListBuffer<Object> markers = ListBuffer.lb();
   918             for (Symbol t : tree.targets.tail) {
   919                 if (t != syms.serializableType.tsym) {
   920                     markers.append(t);
   921                 }
   922             }
   923             int flags = isSerializable? FLAG_SERIALIZABLE : 0;
   924             boolean hasMarkers = markers.nonEmpty();
   925             flags |= hasMarkers ? FLAG_MARKERS : 0;
   926             staticArgs = staticArgs.append(flags);
   927             if (hasMarkers) {
   928                 staticArgs = staticArgs.append(markers.length());
   929                 staticArgs = staticArgs.appendList(markers.toList());
   930             }
   931             if (isSerializable) {
   932                 addDeserializationCase(refKind, refSym, tree.type, samSym,
   933                         tree, staticArgs, indyType);
   934             }
   935         }
   937         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
   938     }
   940     /**
   941      * Generate an indy method call with given name, type and static bootstrap
   942      * arguments types
   943      */
   944     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
   945             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
   946         int prevPos = make.pos;
   947         try {
   948             make.at(pos);
   949             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
   950                     syms.stringType,
   951                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
   953             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
   954                     bsmName, bsm_staticArgs, List.<Type>nil());
   956             DynamicMethodSymbol dynSym =
   957                     new DynamicMethodSymbol(names.lambda,
   958                                             syms.noSymbol,
   959                                             bsm.isStatic() ?
   960                                                 ClassFile.REF_invokeStatic :
   961                                                 ClassFile.REF_invokeVirtual,
   962                                             (MethodSymbol)bsm,
   963                                             indyType,
   964                                             staticArgs.toArray());
   966             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
   967             qualifier.sym = dynSym;
   968             qualifier.type = indyType.getReturnType();
   970             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
   971             proxyCall.type = indyType.getReturnType();
   972             return proxyCall;
   973         } finally {
   974             make.at(prevPos);
   975         }
   976     }
   977     //where
   978     private List<Type> bsmStaticArgToTypes(List<Object> args) {
   979         ListBuffer<Type> argtypes = ListBuffer.lb();
   980         for (Object arg : args) {
   981             argtypes.append(bsmStaticArgToType(arg));
   982         }
   983         return argtypes.toList();
   984     }
   986     private Type bsmStaticArgToType(Object arg) {
   987         Assert.checkNonNull(arg);
   988         if (arg instanceof ClassSymbol) {
   989             return syms.classType;
   990         } else if (arg instanceof Integer) {
   991             return syms.intType;
   992         } else if (arg instanceof Long) {
   993             return syms.longType;
   994         } else if (arg instanceof Float) {
   995             return syms.floatType;
   996         } else if (arg instanceof Double) {
   997             return syms.doubleType;
   998         } else if (arg instanceof String) {
   999             return syms.stringType;
  1000         } else if (arg instanceof Pool.MethodHandle) {
  1001             return syms.methodHandleType;
  1002         } else if (arg instanceof MethodType) {
  1003             return syms.methodTypeType;
  1004         } else {
  1005             Assert.error("bad static arg " + arg.getClass());
  1006             return null;
  1010     /**
  1011      * Get the opcode associated with this method reference
  1012      */
  1013     private int referenceKind(Symbol refSym) {
  1014         if (refSym.isConstructor()) {
  1015             return ClassFile.REF_newInvokeSpecial;
  1016         } else {
  1017             if (refSym.isStatic()) {
  1018                 return ClassFile.REF_invokeStatic;
  1019             } else if (refSym.enclClass().isInterface()) {
  1020                 return ClassFile.REF_invokeInterface;
  1021             } else {
  1022                 return ClassFile.REF_invokeVirtual;
  1027     // </editor-fold>
  1029     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">\
  1030     /**
  1031      * This visitor collects information about translation of a lambda expression.
  1032      * More specifically, it keeps track of the enclosing contexts and captured locals
  1033      * accessed by the lambda being translated (as well as other useful info).
  1034      */
  1035     class LambdaAnalyzer extends TreeScanner {
  1037         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1038         private List<Frame> frameStack;
  1040         /**
  1041          * keep the count of lambda expression (used to generate unambiguous
  1042          * names)
  1043          */
  1044         private int lambdaCount = 0;
  1046         /**
  1047          * keep the count of lambda expression defined in given context (used to
  1048          * generate unambiguous names for serializable lambdas)
  1049          */
  1050         private Map<String, Integer> serializableLambdaCounts =
  1051                 new HashMap<String, Integer>();
  1053         private Map<Symbol, JCClassDecl> localClassDefs;
  1055         /**
  1056          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1057          * a static var init context
  1058          */
  1059         private Map<ClassSymbol, Symbol> clinits =
  1060                 new HashMap<ClassSymbol, Symbol>();
  1062         private void analyzeClass(JCClassDecl tree) {
  1063             frameStack = List.nil();
  1064             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1065             scan(tree);
  1068         @Override
  1069         public void visitBlock(JCBlock tree) {
  1070             List<Frame> prevStack = frameStack;
  1071             try {
  1072                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1073                     frameStack = frameStack.prepend(new Frame(tree));
  1075                 super.visitBlock(tree);
  1077             finally {
  1078                 frameStack = prevStack;
  1082         @Override
  1083         public void visitClassDef(JCClassDecl tree) {
  1084             List<Frame> prevStack = frameStack;
  1085             Map<String, Integer> prevSerializableLambdaCount =
  1086                     serializableLambdaCounts;
  1087             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1088             try {
  1089                 serializableLambdaCounts = new HashMap<String, Integer>();
  1090                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1091                 if (tree.sym.owner.kind == MTH) {
  1092                     localClassDefs.put(tree.sym, tree);
  1094                 if (directlyEnclosingLambda() != null) {
  1095                     tree.sym.owner = owner();
  1096                     if (tree.sym.hasOuterInstance()) {
  1097                         //if a class is defined within a lambda, the lambda must capture
  1098                         //its enclosing instance (if any)
  1099                         TranslationContext<?> localContext = context();
  1100                         while (localContext != null) {
  1101                             if (localContext.tree.getTag() == LAMBDA) {
  1102                                 ((LambdaTranslationContext)localContext)
  1103                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1105                             localContext = localContext.prev;
  1109                 frameStack = frameStack.prepend(new Frame(tree));
  1110                 super.visitClassDef(tree);
  1112             finally {
  1113                 frameStack = prevStack;
  1114                 serializableLambdaCounts = prevSerializableLambdaCount;
  1115                 clinits = prevClinits;
  1119         @Override
  1120         public void visitIdent(JCIdent tree) {
  1121             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1122                 if (tree.sym.kind == VAR &&
  1123                         tree.sym.owner.kind == MTH &&
  1124                         tree.type.constValue() == null) {
  1125                     TranslationContext<?> localContext = context();
  1126                     while (localContext != null) {
  1127                         if (localContext.tree.getTag() == LAMBDA) {
  1128                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1129                             if (block == null) break;
  1130                             ((LambdaTranslationContext)localContext)
  1131                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1133                         localContext = localContext.prev;
  1135                 } else if (tree.sym.owner.kind == TYP) {
  1136                     TranslationContext<?> localContext = context();
  1137                     while (localContext != null) {
  1138                         if (localContext.tree.hasTag(LAMBDA)) {
  1139                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1140                             if (block == null) break;
  1141                             switch (block.getTag()) {
  1142                                 case CLASSDEF:
  1143                                     JCClassDecl cdecl = (JCClassDecl)block;
  1144                                     ((LambdaTranslationContext)localContext)
  1145                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1146                                     break;
  1147                                 default:
  1148                                     Assert.error("bad block kind");
  1151                         localContext = localContext.prev;
  1155             super.visitIdent(tree);
  1158         @Override
  1159         public void visitLambda(JCLambda tree) {
  1160             List<Frame> prevStack = frameStack;
  1161             try {
  1162                 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
  1163                 frameStack = frameStack.prepend(new Frame(tree));
  1164                 for (JCVariableDecl param : tree.params) {
  1165                     context.addSymbol(param.sym, PARAM);
  1166                     frameStack.head.addLocal(param.sym);
  1168                 contextMap.put(tree, context);
  1169                 scan(tree.body);
  1170                 context.complete();
  1172             finally {
  1173                 frameStack = prevStack;
  1177         @Override
  1178         public void visitMethodDef(JCMethodDecl tree) {
  1179             List<Frame> prevStack = frameStack;
  1180             try {
  1181                 frameStack = frameStack.prepend(new Frame(tree));
  1182                 super.visitMethodDef(tree);
  1184             finally {
  1185                 frameStack = prevStack;
  1189         @Override
  1190         public void visitNewClass(JCNewClass tree) {
  1191             if (lambdaNewClassFilter(context(), tree)) {
  1192                 TranslationContext<?> localContext = context();
  1193                 while (localContext != null) {
  1194                     if (localContext.tree.getTag() == LAMBDA) {
  1195                         ((LambdaTranslationContext)localContext)
  1196                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1198                     localContext = localContext.prev;
  1201             if (context() != null && tree.type.tsym.owner.kind == MTH) {
  1202                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1203                 captureLocalClassDefs(tree.type.tsym, lambdaContext);
  1205             super.visitNewClass(tree);
  1207         //where
  1208             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1209                 JCClassDecl localCDef = localClassDefs.get(csym);
  1210                 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
  1211                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1212                         @Override
  1213                         void addFreeVars(ClassSymbol c) {
  1214                             captureLocalClassDefs(c, lambdaContext);
  1216                         @Override
  1217                         void visitSymbol(Symbol sym) {
  1218                             if (sym.kind == VAR &&
  1219                                     sym.owner.kind == MTH &&
  1220                                     ((VarSymbol)sym).getConstValue() == null) {
  1221                                 TranslationContext<?> localContext = context();
  1222                                 while (localContext != null) {
  1223                                     if (localContext.tree.getTag() == LAMBDA) {
  1224                                         JCTree block = capturedDecl(localContext.depth, sym);
  1225                                         if (block == null) break;
  1226                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1228                                     localContext = localContext.prev;
  1232                     };
  1233                     fvc.scan(localCDef);
  1237         @Override
  1238         public void visitReference(JCMemberReference tree) {
  1239             scan(tree.getQualifierExpression());
  1240             contextMap.put(tree, makeReferenceContext(tree));
  1243         @Override
  1244         public void visitSelect(JCFieldAccess tree) {
  1245             if (context() != null && lambdaSelectSymbolFilter(tree.sym)) {
  1246                 TranslationContext<?> localContext = context();
  1247                 while (localContext != null) {
  1248                     if (localContext.tree.hasTag(LAMBDA)) {
  1249                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1250                         if (clazz == null) break;
  1251                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1253                     localContext = localContext.prev;
  1255                 scan(tree.selected);
  1256             } else {
  1257                 super.visitSelect(tree);
  1261         @Override
  1262         public void visitVarDef(JCVariableDecl tree) {
  1263             TranslationContext<?> context = context();
  1264             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1265                     (LambdaTranslationContext)context :
  1266                     null;
  1267             if (ltc != null) {
  1268                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1269                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1271                 // Check for type variables (including as type arguments).
  1272                 // If they occur within class nested in a lambda, mark for erasure
  1273                 Type type = tree.sym.asType();
  1274                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1275                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1279             List<Frame> prevStack = frameStack;
  1280             try {
  1281                 if (tree.sym.owner.kind == MTH) {
  1282                     frameStack.head.addLocal(tree.sym);
  1284                 frameStack = frameStack.prepend(new Frame(tree));
  1285                 super.visitVarDef(tree);
  1287             finally {
  1288                 frameStack = prevStack;
  1292         private Name lambdaName() {
  1293             return names.lambda.append(names.fromString("" + lambdaCount++));
  1296         private Name serializedLambdaName(Symbol owner) {
  1297             StringBuilder buf = new StringBuilder();
  1298             buf.append(names.lambda);
  1299             buf.append(owner.name);
  1300             buf.append('$');
  1301             int methTypeHash = methodSig(owner.type).hashCode();
  1302             buf.append(methTypeHash);
  1303             buf.append('$');
  1304             String temp = buf.toString();
  1305             Integer count = serializableLambdaCounts.get(temp);
  1306             if (count == null) {
  1307                 count = 0;
  1309             buf.append(count++);
  1310             serializableLambdaCounts.put(temp, count);
  1311             return names.fromString(buf.toString());
  1314         /**
  1315          * Return a valid owner given the current declaration stack
  1316          * (required to skip synthetic lambda symbols)
  1317          */
  1318         private Symbol owner() {
  1319             return owner(false);
  1322         @SuppressWarnings("fallthrough")
  1323         private Symbol owner(boolean skipLambda) {
  1324             List<Frame> frameStack2 = frameStack;
  1325             while (frameStack2.nonEmpty()) {
  1326                 switch (frameStack2.head.tree.getTag()) {
  1327                     case VARDEF:
  1328                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1329                             frameStack2 = frameStack2.tail;
  1330                             break;
  1332                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1333                         return initSym(cdecl.sym,
  1334                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1335                     case BLOCK:
  1336                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1337                         return initSym(cdecl2.sym,
  1338                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1339                     case CLASSDEF:
  1340                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1341                     case METHODDEF:
  1342                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1343                     case LAMBDA:
  1344                         if (!skipLambda)
  1345                             return ((LambdaTranslationContext)contextMap
  1346                                     .get(frameStack2.head.tree)).translatedSym;
  1347                     default:
  1348                         frameStack2 = frameStack2.tail;
  1351             Assert.error();
  1352             return null;
  1355         private Symbol initSym(ClassSymbol csym, long flags) {
  1356             boolean isStatic = (flags & STATIC) != 0;
  1357             if (isStatic) {
  1358                 //static clinits are generated in Gen - so we need to fake them
  1359                 Symbol clinit = clinits.get(csym);
  1360                 if (clinit == null) {
  1361                     clinit = makeSyntheticMethod(STATIC,
  1362                             names.clinit,
  1363                             new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
  1364                             csym);
  1365                     clinits.put(csym, clinit);
  1367                 return clinit;
  1368             } else {
  1369                 //get the first constructor and treat it as the instance init sym
  1370                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1371                     return s;
  1374             Assert.error("init not found");
  1375             return null;
  1378         private JCTree directlyEnclosingLambda() {
  1379             if (frameStack.isEmpty()) {
  1380                 return null;
  1382             List<Frame> frameStack2 = frameStack;
  1383             while (frameStack2.nonEmpty()) {
  1384                 switch (frameStack2.head.tree.getTag()) {
  1385                     case CLASSDEF:
  1386                     case METHODDEF:
  1387                         return null;
  1388                     case LAMBDA:
  1389                         return frameStack2.head.tree;
  1390                     default:
  1391                         frameStack2 = frameStack2.tail;
  1394             Assert.error();
  1395             return null;
  1398         private boolean inClassWithinLambda() {
  1399             if (frameStack.isEmpty()) {
  1400                 return false;
  1402             List<Frame> frameStack2 = frameStack;
  1403             boolean classFound = false;
  1404             while (frameStack2.nonEmpty()) {
  1405                 switch (frameStack2.head.tree.getTag()) {
  1406                     case LAMBDA:
  1407                         return classFound;
  1408                     case CLASSDEF:
  1409                         classFound = true;
  1410                         frameStack2 = frameStack2.tail;
  1411                         break;
  1412                     default:
  1413                         frameStack2 = frameStack2.tail;
  1416             // No lambda
  1417             return false;
  1420         /**
  1421          * Return the declaration corresponding to a symbol in the enclosing
  1422          * scope; the depth parameter is used to filter out symbols defined
  1423          * in nested scopes (which do not need to undergo capture).
  1424          */
  1425         private JCTree capturedDecl(int depth, Symbol sym) {
  1426             int currentDepth = frameStack.size() - 1;
  1427             for (Frame block : frameStack) {
  1428                 switch (block.tree.getTag()) {
  1429                     case CLASSDEF:
  1430                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1431                         if (sym.isMemberOf(clazz, types)) {
  1432                             return currentDepth > depth ? null : block.tree;
  1434                         break;
  1435                     case VARDEF:
  1436                         if (((JCVariableDecl)block.tree).sym == sym &&
  1437                                 sym.owner.kind == MTH) { //only locals are captured
  1438                             return currentDepth > depth ? null : block.tree;
  1440                         break;
  1441                     case BLOCK:
  1442                     case METHODDEF:
  1443                     case LAMBDA:
  1444                         if (block.locals != null && block.locals.contains(sym)) {
  1445                             return currentDepth > depth ? null : block.tree;
  1447                         break;
  1448                     default:
  1449                         Assert.error("bad decl kind " + block.tree.getTag());
  1451                 currentDepth--;
  1453             return null;
  1456         private TranslationContext<?> context() {
  1457             for (Frame frame : frameStack) {
  1458                 TranslationContext<?> context = contextMap.get(frame.tree);
  1459                 if (context != null) {
  1460                     return context;
  1463             return null;
  1466         /**
  1467          *  This is used to filter out those identifiers that needs to be adjusted
  1468          *  when translating away lambda expressions
  1469          */
  1470         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1471             return (sym.kind == VAR || sym.kind == MTH)
  1472                     && !sym.isStatic()
  1473                     && sym.name != names.init;
  1476         private boolean lambdaSelectSymbolFilter(Symbol sym) {
  1477             return (sym.kind == VAR || sym.kind == MTH) &&
  1478                         !sym.isStatic() &&
  1479                         (sym.name == names._this ||
  1480                         sym.name == names._super);
  1483         /**
  1484          * This is used to filter out those new class expressions that need to
  1485          * be qualified with an enclosing tree
  1486          */
  1487         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1488             if (context != null
  1489                     && tree.encl == null
  1490                     && tree.def == null
  1491                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1492                 Type encl = tree.type.getEnclosingType();
  1493                 Type current = context.owner.enclClass().type;
  1494                 while (!current.hasTag(NONE)) {
  1495                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1496                         return true;
  1498                     current = current.getEnclosingType();
  1500                 return false;
  1501             } else {
  1502                 return false;
  1506         private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
  1507             return new LambdaTranslationContext(tree);
  1510         private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
  1511             return new ReferenceTranslationContext(tree);
  1514         private class Frame {
  1515             final JCTree tree;
  1516             List<Symbol> locals;
  1518             public Frame(JCTree tree) {
  1519                 this.tree = tree;
  1522             void addLocal(Symbol sym) {
  1523                 if (locals == null) {
  1524                     locals = List.nil();
  1526                 locals = locals.prepend(sym);
  1530         /**
  1531          * This class is used to store important information regarding translation of
  1532          * lambda expression/method references (see subclasses).
  1533          */
  1534         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1536             /** the underlying (untranslated) tree */
  1537             T tree;
  1539             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1540             Symbol owner;
  1542             /** the depth of this lambda expression in the frame stack */
  1543             int depth;
  1545             /** the enclosing translation context (set for nested lambdas/mref) */
  1546             TranslationContext<?> prev;
  1548             TranslationContext(T tree) {
  1549                 this.tree = tree;
  1550                 this.owner = owner();
  1551                 this.depth = frameStack.size() - 1;
  1552                 this.prev = context();
  1555             /** does this functional expression need to be created using alternate metafactory? */
  1556             boolean needsAltMetafactory() {
  1557                 return (tree.targets.length() > 1 ||
  1558                         isSerializable());
  1561             /** does this functional expression require serialization support? */
  1562             boolean isSerializable() {
  1563                 for (Symbol target : tree.targets) {
  1564                     if (types.asSuper(target.type, syms.serializableType.tsym) != null) {
  1565                         return true;
  1568                 return false;
  1572         /**
  1573          * This class retains all the useful information about a lambda expression;
  1574          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1575          * and the used by the main translation routines in order to adjust references
  1576          * to captured locals/members, etc.
  1577          */
  1578         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1580             /** variable in the enclosing context to which this lambda is assigned */
  1581             Symbol self;
  1583             /** map from original to translated lambda parameters */
  1584             Map<Symbol, Symbol> lambdaParams = new LinkedHashMap<Symbol, Symbol>();
  1586             /** map from original to translated lambda locals */
  1587             Map<Symbol, Symbol> lambdaLocals = new LinkedHashMap<Symbol, Symbol>();
  1589             /** map from variables in enclosing scope to translated synthetic parameters */
  1590             Map<Symbol, Symbol> capturedLocals  = new LinkedHashMap<Symbol, Symbol>();
  1592             /** map from class symbols to translated synthetic parameters (for captured member access) */
  1593             Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>();
  1595             /** map from original to translated lambda locals */
  1596             Map<Symbol, Symbol> typeVars = new LinkedHashMap<Symbol, Symbol>();
  1598             /** the synthetic symbol for the method hoisting the translated lambda */
  1599             Symbol translatedSym;
  1601             List<JCVariableDecl> syntheticParams;
  1603             LambdaTranslationContext(JCLambda tree) {
  1604                 super(tree);
  1605                 Frame frame = frameStack.head;
  1606                 if (frame.tree.hasTag(VARDEF)) {
  1607                     self = ((JCVariableDecl)frame.tree).sym;
  1609                 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName();
  1610                 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass());
  1613             /**
  1614              * Translate a symbol of a given kind into something suitable for the
  1615              * synthetic lambda body
  1616              */
  1617             Symbol translate(String name, final Symbol sym, LambdaSymbolKind skind) {
  1618                 switch (skind) {
  1619                     case CAPTURED_THIS:
  1620                         return sym;  // self represented
  1621                     case TYPE_VAR:
  1622                         // Just erase the type var
  1623                         return new VarSymbol(sym.flags(), names.fromString(name),
  1624                                 types.erasure(sym.type), sym.owner);
  1625                     case CAPTURED_VAR:
  1626                         return new VarSymbol(SYNTHETIC | FINAL, names.fromString(name), types.erasure(sym.type), translatedSym) {
  1627                             @Override
  1628                             public Symbol baseSymbol() {
  1629                                 //keep mapping with original captured symbol
  1630                                 return sym;
  1632                         };
  1633                     default:
  1634                         return makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1638             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1639                 Map<Symbol, Symbol> transMap = null;
  1640                 String preferredName;
  1641                 switch (skind) {
  1642                     case CAPTURED_THIS:
  1643                         transMap = capturedThis;
  1644                         preferredName = "encl$" + capturedThis.size();
  1645                         break;
  1646                     case CAPTURED_VAR:
  1647                         transMap = capturedLocals;
  1648                         preferredName = "cap$" + capturedLocals.size();
  1649                         break;
  1650                     case LOCAL_VAR:
  1651                         transMap = lambdaLocals;
  1652                         preferredName = sym.name.toString();
  1653                         break;
  1654                     case PARAM:
  1655                         transMap = lambdaParams;
  1656                         preferredName = sym.name.toString();
  1657                         break;
  1658                     case TYPE_VAR:
  1659                         transMap = typeVars;
  1660                         preferredName = sym.name.toString();
  1661                         break;
  1662                     default: throw new AssertionError();
  1664                 if (!transMap.containsKey(sym)) {
  1665                     transMap.put(sym, translate(preferredName, sym, skind));
  1669             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind... skinds) {
  1670                 LinkedHashMap<Symbol, Symbol> translationMap = new LinkedHashMap<Symbol, Symbol>();
  1671                 for (LambdaSymbolKind skind : skinds) {
  1672                     switch (skind) {
  1673                         case CAPTURED_THIS:
  1674                             translationMap.putAll(capturedThis);
  1675                             break;
  1676                         case CAPTURED_VAR:
  1677                             translationMap.putAll(capturedLocals);
  1678                             break;
  1679                         case LOCAL_VAR:
  1680                             translationMap.putAll(lambdaLocals);
  1681                             break;
  1682                         case PARAM:
  1683                             translationMap.putAll(lambdaParams);
  1684                             break;
  1685                         case TYPE_VAR:
  1686                             translationMap.putAll(typeVars);
  1687                             break;
  1688                         default: throw new AssertionError();
  1691                 return translationMap;
  1694             /**
  1695              * The translatedSym is not complete/accurate until the analysis is
  1696              * finished.  Once the analysis is finished, the translatedSym is
  1697              * "completed" -- updated with type information, access modifiers,
  1698              * and full parameter list.
  1699              */
  1700             void complete() {
  1701                 if (syntheticParams != null) {
  1702                     return;
  1704                 boolean inInterface = translatedSym.owner.isInterface();
  1705                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1706                 boolean needInstance = thisReferenced || inInterface;
  1708                 // If instance access isn't needed, make it static
  1709                 // Interface methods much be public default methods, otherwise make it private
  1710                 translatedSym.flags_field = SYNTHETIC | (needInstance? 0 : STATIC) |
  1711                         (inInterface? PUBLIC | DEFAULT : PRIVATE);
  1713                 //compute synthetic params
  1714                 ListBuffer<JCVariableDecl> params = ListBuffer.lb();
  1716                 // The signature of the method is augmented with the following
  1717                 // synthetic parameters:
  1718                 //
  1719                 // 1) reference to enclosing contexts captured by the lambda expression
  1720                 // 2) enclosing locals captured by the lambda expression
  1721                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR, PARAM).values()) {
  1722                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1725                 syntheticParams = params.toList();
  1727                 //prepend synthetic args to translated lambda method signature
  1728                 translatedSym.type = types.createMethodTypeWithParameters(
  1729                         generatedLambdaSig(),
  1730                         TreeInfo.types(syntheticParams));
  1733             Type generatedLambdaSig() {
  1734                 return types.erasure(tree.descriptorType);
  1738         /**
  1739          * This class retains all the useful information about a method reference;
  1740          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1741          * and the used by the main translation routines in order to adjust method
  1742          * references (i.e. in case a bridge is needed)
  1743          */
  1744         private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  1746             final boolean isSuper;
  1747             final Symbol bridgeSym;
  1749             ReferenceTranslationContext(JCMemberReference tree) {
  1750                 super(tree);
  1751                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  1752                 this.bridgeSym = needsBridge()
  1753                         ? makeSyntheticMethod(isSuper ? 0 : STATIC,
  1754                                               lambdaName().append(names.fromString("$bridge")), null,
  1755                                               owner.enclClass())
  1756                         : null;
  1759             /**
  1760              * Get the opcode associated with this method reference
  1761              */
  1762             int referenceKind() {
  1763                 return LambdaToMethod.this.referenceKind(needsBridge() ? bridgeSym : tree.sym);
  1766             boolean needsVarArgsConversion() {
  1767                 return tree.varargsElement != null;
  1770             /**
  1771              * @return Is this an array operation like clone()
  1772              */
  1773             boolean isArrayOp() {
  1774                 return tree.sym.owner == syms.arrayClass;
  1777             boolean isPrivateConstructor() {
  1778                 //hack needed to workaround 292 bug (8005122)
  1779                 //when 292 issue is fixed we should simply remove this
  1780                 return tree.sym.name == names.init &&
  1781                         (tree.sym.flags() & PRIVATE) != 0;
  1784             boolean receiverAccessible() {
  1785                 //hack needed to workaround 292 bug (7087658)
  1786                 //when 292 issue is fixed we should remove this and change the backend
  1787                 //code to always generate a method handle to an accessible method
  1788                 return tree.ownerAccessible;
  1791             /**
  1792              * Does this reference needs a bridge (i.e. var args need to be
  1793              * expanded or "super" is used)
  1794              */
  1795             final boolean needsBridge() {
  1796                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  1797                         isPrivateConstructor() || !receiverAccessible();
  1800             Type generatedRefSig() {
  1801                 return types.erasure(tree.sym.type);
  1804             Type bridgedRefSig() {
  1805                 return types.erasure(types.findDescriptorSymbol(tree.targets.head).type);
  1809     // </editor-fold>
  1811     enum LambdaSymbolKind {
  1812         CAPTURED_VAR,
  1813         CAPTURED_THIS,
  1814         LOCAL_VAR,
  1815         PARAM,
  1816         TYPE_VAR;
  1819     /**
  1820      * ****************************************************************
  1821      * Signature Generation
  1822      * ****************************************************************
  1823      */
  1825     private String methodSig(Type type) {
  1826         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1827         sg.assembleSig(type);
  1828         return sg.toString();
  1831     private String classSig(Type type) {
  1832         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1833         sg.assembleClassSig(type);
  1834         return sg.toString();
  1837     /**
  1838      * Signature Generation
  1839      */
  1840     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  1842         /**
  1843          * An output buffer for type signatures.
  1844          */
  1845         StringBuilder sb = new StringBuilder();
  1847         L2MSignatureGenerator() {
  1848             super(types);
  1851         @Override
  1852         protected void append(char ch) {
  1853             sb.append(ch);
  1856         @Override
  1857         protected void append(byte[] ba) {
  1858             sb.append(new String(ba));
  1861         @Override
  1862         protected void append(Name name) {
  1863             sb.append(name.toString());
  1866         @Override
  1867         public String toString() {
  1868             return sb.toString();

mercurial