LambdaToMethod.java revision 2737:3c5de506a1f2
1/*
2 * Copyright (c) 2010, 2014, 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 */
25package com.sun.tools.javac.comp;
26
27import com.sun.tools.javac.tree.*;
28import com.sun.tools.javac.tree.JCTree.*;
29import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
30import com.sun.tools.javac.tree.TreeMaker;
31import com.sun.tools.javac.tree.TreeTranslator;
32import com.sun.tools.javac.code.Attribute;
33import com.sun.tools.javac.code.Scope.WriteableScope;
34import com.sun.tools.javac.code.Symbol;
35import com.sun.tools.javac.code.Symbol.ClassSymbol;
36import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
37import com.sun.tools.javac.code.Symbol.MethodSymbol;
38import com.sun.tools.javac.code.Symbol.TypeSymbol;
39import com.sun.tools.javac.code.Symbol.VarSymbol;
40import com.sun.tools.javac.code.Symtab;
41import com.sun.tools.javac.code.Type;
42import com.sun.tools.javac.code.Type.MethodType;
43import com.sun.tools.javac.code.Type.TypeVar;
44import com.sun.tools.javac.code.Types;
45import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
46import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
47import com.sun.tools.javac.jvm.*;
48import com.sun.tools.javac.util.*;
49import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
50import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
51
52import java.util.EnumMap;
53import java.util.HashMap;
54import java.util.HashSet;
55import java.util.LinkedHashMap;
56import java.util.Map;
57import java.util.Set;
58
59import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
60import static com.sun.tools.javac.code.Flags.*;
61import static com.sun.tools.javac.code.Kinds.Kind.*;
62import static com.sun.tools.javac.code.TypeTag.*;
63import static com.sun.tools.javac.tree.JCTree.Tag.*;
64import javax.lang.model.type.TypeKind;
65
66/**
67 * This pass desugars lambda expressions into static methods
68 *
69 *  <p><b>This is NOT part of any supported API.
70 *  If you write code that depends on this, you do so at your own risk.
71 *  This code and its internal interfaces are subject to change or
72 *  deletion without notice.</b>
73 */
74public class LambdaToMethod extends TreeTranslator {
75
76    private Attr attr;
77    private JCDiagnostic.Factory diags;
78    private Log log;
79    private Lower lower;
80    private Names names;
81    private Symtab syms;
82    private Resolve rs;
83    private TreeMaker make;
84    private Types types;
85    private TransTypes transTypes;
86    private Env<AttrContext> attrEnv;
87
88    /** the analyzer scanner */
89    private LambdaAnalyzerPreprocessor analyzer;
90
91    /** map from lambda trees to translation contexts */
92    private Map<JCTree, TranslationContext<?>> contextMap;
93
94    /** current translation context (visitor argument) */
95    private TranslationContext<?> context;
96
97    /** info about the current class being processed */
98    private KlassInfo kInfo;
99
100    /** dump statistics about lambda code generation */
101    private boolean dumpLambdaToMethodStats;
102
103    /** force serializable representation, for stress testing **/
104    private final boolean forceSerializable;
105
106    /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
107    public static final int FLAG_SERIALIZABLE = 1 << 0;
108
109    /** Flag for alternate metafactories indicating the lambda object has multiple targets */
110    public static final int FLAG_MARKERS = 1 << 1;
111
112    /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
113    public static final int FLAG_BRIDGES = 1 << 2;
114
115    // <editor-fold defaultstate="collapsed" desc="Instantiating">
116    protected static final Context.Key<LambdaToMethod> unlambdaKey = new Context.Key<>();
117
118    public static LambdaToMethod instance(Context context) {
119        LambdaToMethod instance = context.get(unlambdaKey);
120        if (instance == null) {
121            instance = new LambdaToMethod(context);
122        }
123        return instance;
124    }
125    private LambdaToMethod(Context context) {
126        context.put(unlambdaKey, this);
127        diags = JCDiagnostic.Factory.instance(context);
128        log = Log.instance(context);
129        lower = Lower.instance(context);
130        names = Names.instance(context);
131        syms = Symtab.instance(context);
132        rs = Resolve.instance(context);
133        make = TreeMaker.instance(context);
134        types = Types.instance(context);
135        transTypes = TransTypes.instance(context);
136        analyzer = new LambdaAnalyzerPreprocessor();
137        Options options = Options.instance(context);
138        dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats");
139        attr = Attr.instance(context);
140        forceSerializable = options.isSet("forceSerializable");
141    }
142    // </editor-fold>
143
144    private class KlassInfo {
145
146        /**
147         * list of methods to append
148         */
149        private ListBuffer<JCTree> appendedMethodList;
150
151        /**
152         * list of deserialization cases
153         */
154        private final Map<String, ListBuffer<JCStatement>> deserializeCases;
155
156       /**
157         * deserialize method symbol
158         */
159        private final MethodSymbol deserMethodSym;
160
161        /**
162         * deserialize method parameter symbol
163         */
164        private final VarSymbol deserParamSym;
165
166        private final JCClassDecl clazz;
167
168        private KlassInfo(JCClassDecl clazz) {
169            this.clazz = clazz;
170            appendedMethodList = new ListBuffer<>();
171            deserializeCases = new HashMap<>();
172            MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
173                    List.<Type>nil(), syms.methodClass);
174            deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
175            deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
176                    syms.serializedLambdaType, deserMethodSym);
177        }
178
179        private void addMethod(JCTree decl) {
180            appendedMethodList = appendedMethodList.prepend(decl);
181        }
182    }
183
184    // <editor-fold defaultstate="collapsed" desc="translate methods">
185    @Override
186    public <T extends JCTree> T translate(T tree) {
187        TranslationContext<?> newContext = contextMap.get(tree);
188        return translate(tree, newContext != null ? newContext : context);
189    }
190
191    <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
192        TranslationContext<?> prevContext = context;
193        try {
194            context = newContext;
195            return super.translate(tree);
196        }
197        finally {
198            context = prevContext;
199        }
200    }
201
202    <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
203        ListBuffer<T> buf = new ListBuffer<>();
204        for (T tree : trees) {
205            buf.append(translate(tree, newContext));
206        }
207        return buf.toList();
208    }
209
210    public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
211        this.make = make;
212        this.attrEnv = env;
213        this.context = null;
214        this.contextMap = new HashMap<>();
215        return translate(cdef);
216    }
217    // </editor-fold>
218
219    // <editor-fold defaultstate="collapsed" desc="visitor methods">
220    /**
221     * Visit a class.
222     * Maintain the translatedMethodList across nested classes.
223     * Append the translatedMethodList to the class after it is translated.
224     * @param tree
225     */
226    @Override
227    public void visitClassDef(JCClassDecl tree) {
228        if (tree.sym.owner.kind == PCK) {
229            //analyze class
230            tree = analyzer.analyzeAndPreprocessClass(tree);
231        }
232        KlassInfo prevKlassInfo = kInfo;
233        try {
234            kInfo = new KlassInfo(tree);
235            super.visitClassDef(tree);
236            if (!kInfo.deserializeCases.isEmpty()) {
237                int prevPos = make.pos;
238                try {
239                    make.at(tree);
240                    kInfo.addMethod(makeDeserializeMethod(tree.sym));
241                } finally {
242                    make.at(prevPos);
243                }
244            }
245            //add all translated instance methods here
246            List<JCTree> newMethods = kInfo.appendedMethodList.toList();
247            tree.defs = tree.defs.appendList(newMethods);
248            for (JCTree lambda : newMethods) {
249                tree.sym.members().enter(((JCMethodDecl)lambda).sym);
250            }
251            result = tree;
252        } finally {
253            kInfo = prevKlassInfo;
254        }
255    }
256
257    /**
258     * Translate a lambda into a method to be inserted into the class.
259     * Then replace the lambda site with an invokedynamic call of to lambda
260     * meta-factory, which will use the lambda method.
261     * @param tree
262     */
263    @Override
264    public void visitLambda(JCLambda tree) {
265        LambdaTranslationContext localContext = (LambdaTranslationContext)context;
266        MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
267        MethodType lambdaType = (MethodType) sym.type;
268
269        {
270            Symbol owner = localContext.owner;
271            ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
272            ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
273
274            for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
275                if (tc.position.onLambda == tree) {
276                    lambdaTypeAnnos.append(tc);
277                } else {
278                    ownerTypeAnnos.append(tc);
279                }
280            }
281            if (lambdaTypeAnnos.nonEmpty()) {
282                owner.setTypeAttributes(ownerTypeAnnos.toList());
283                sym.setTypeAttributes(lambdaTypeAnnos.toList());
284            }
285        }
286
287        //create the method declaration hoisting the lambda body
288        JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
289                sym.name,
290                make.QualIdent(lambdaType.getReturnType().tsym),
291                List.<JCTypeParameter>nil(),
292                localContext.syntheticParams,
293                lambdaType.getThrownTypes() == null ?
294                    List.<JCExpression>nil() :
295                    make.Types(lambdaType.getThrownTypes()),
296                null,
297                null);
298        lambdaDecl.sym = sym;
299        lambdaDecl.type = lambdaType;
300
301        //translate lambda body
302        //As the lambda body is translated, all references to lambda locals,
303        //captured variables, enclosing members are adjusted accordingly
304        //to refer to the static method parameters (rather than i.e. acessing to
305        //captured members directly).
306        lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
307
308        //Add the method to the list of methods to be added to this class.
309        kInfo.addMethod(lambdaDecl);
310
311        //now that we have generated a method for the lambda expression,
312        //we can translate the lambda into a method reference pointing to the newly
313        //created method.
314        //
315        //Note that we need to adjust the method handle so that it will match the
316        //signature of the SAM descriptor - this means that the method reference
317        //should be added the following synthetic arguments:
318        //
319        // * the "this" argument if it is an instance method
320        // * enclosing locals captured by the lambda expression
321
322        ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
323
324        if (localContext.methodReferenceReceiver != null) {
325            syntheticInits.append(localContext.methodReferenceReceiver);
326        } else if (!sym.isStatic()) {
327            syntheticInits.append(makeThis(
328                    sym.owner.enclClass().asType(),
329                    localContext.owner.enclClass()));
330        }
331
332        //add captured locals
333        for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
334            if (fv != localContext.self) {
335                JCTree captured_local = make.Ident(fv).setType(fv.type);
336                syntheticInits.append((JCExpression) captured_local);
337            }
338        }
339
340        //then, determine the arguments to the indy call
341        List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
342
343        //build a sam instance using an indy call to the meta-factory
344        int refKind = referenceKind(sym);
345
346        //convert to an invokedynamic call
347        result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
348    }
349
350    private JCIdent makeThis(Type type, Symbol owner) {
351        VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
352                names._this,
353                type,
354                owner);
355        return make.Ident(_this);
356    }
357
358    /**
359     * Translate a method reference into an invokedynamic call to the
360     * meta-factory.
361     * @param tree
362     */
363    @Override
364    public void visitReference(JCMemberReference tree) {
365        ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
366
367        //first determine the method symbol to be used to generate the sam instance
368        //this is either the method reference symbol, or the bridged reference symbol
369        Symbol refSym = localContext.isSignaturePolymorphic()
370                ? localContext.sigPolySym
371                : tree.sym;
372
373        //the qualifying expression is treated as a special captured arg
374        JCExpression init;
375        switch(tree.kind) {
376
377            case IMPLICIT_INNER:    /** Inner :: new */
378            case SUPER:             /** super :: instMethod */
379                init = makeThis(
380                    localContext.owner.enclClass().asType(),
381                    localContext.owner.enclClass());
382                break;
383
384            case BOUND:             /** Expr :: instMethod */
385                init = tree.getQualifierExpression();
386                init = attr.makeNullCheck(init);
387                break;
388
389            case UNBOUND:           /** Type :: instMethod */
390            case STATIC:            /** Type :: staticMethod */
391            case TOPLEVEL:          /** Top level :: new */
392            case ARRAY_CTOR:        /** ArrayType :: new */
393                init = null;
394                break;
395
396            default:
397                throw new InternalError("Should not have an invalid kind");
398        }
399
400        List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
401
402
403        //build a sam instance using an indy call to the meta-factory
404        result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
405    }
406
407    /**
408     * Translate identifiers within a lambda to the mapped identifier
409     * @param tree
410     */
411    @Override
412    public void visitIdent(JCIdent tree) {
413        if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
414            super.visitIdent(tree);
415        } else {
416            int prevPos = make.pos;
417            try {
418                make.at(tree);
419
420                LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
421                JCTree ltree = lambdaContext.translate(tree);
422                if (ltree != null) {
423                    result = ltree;
424                } else {
425                    //access to untranslated symbols (i.e. compile-time constants,
426                    //members defined inside the lambda body, etc.) )
427                    super.visitIdent(tree);
428                }
429            } finally {
430                make.at(prevPos);
431            }
432        }
433    }
434
435    @Override
436    public void visitVarDef(JCVariableDecl tree) {
437        LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
438        if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
439            tree.init = translate(tree.init);
440            tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
441            result = tree;
442        } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
443            JCExpression init = translate(tree.init);
444            VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
445            int prevPos = make.pos;
446            try {
447                result = make.at(tree).VarDef(xsym, init);
448            } finally {
449                make.at(prevPos);
450            }
451            // Replace the entered symbol for this variable
452            WriteableScope sc = tree.sym.owner.members();
453            if (sc != null) {
454                sc.remove(tree.sym);
455                sc.enter(xsym);
456            }
457        } else {
458            super.visitVarDef(tree);
459        }
460    }
461
462    // </editor-fold>
463
464    // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
465
466    private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
467        return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
468                makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
469                makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
470    }
471
472    private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
473        Type restype = lambdaMethodDecl.type.getReturnType();
474        boolean isLambda_void = expr.type.hasTag(VOID);
475        boolean isTarget_void = restype.hasTag(VOID);
476        boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
477        int prevPos = make.pos;
478        try {
479            if (isTarget_void) {
480                //target is void:
481                // BODY;
482                JCStatement stat = make.at(expr).Exec(expr);
483                return make.Block(0, List.<JCStatement>of(stat));
484            } else if (isLambda_void && isTarget_Void) {
485                //void to Void conversion:
486                // BODY; return null;
487                ListBuffer<JCStatement> stats = new ListBuffer<>();
488                stats.append(make.at(expr).Exec(expr));
489                stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
490                return make.Block(0, stats.toList());
491            } else {
492                //non-void to non-void conversion:
493                // return (TYPE)BODY;
494                JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
495                return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
496            }
497        } finally {
498            make.at(prevPos);
499        }
500    }
501
502    private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
503        final Type restype = lambdaMethodDecl.type.getReturnType();
504        final boolean isTarget_void = restype.hasTag(VOID);
505        boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
506
507        class LambdaBodyTranslator extends TreeTranslator {
508
509            @Override
510            public void visitClassDef(JCClassDecl tree) {
511                //do NOT recurse on any inner classes
512                result = tree;
513            }
514
515            @Override
516            public void visitLambda(JCLambda tree) {
517                //do NOT recurse on any nested lambdas
518                result = tree;
519            }
520
521            @Override
522            public void visitReturn(JCReturn tree) {
523                boolean isLambda_void = tree.expr == null;
524                if (isTarget_void && !isLambda_void) {
525                    //Void to void conversion:
526                    // { TYPE $loc = RET-EXPR; return; }
527                    VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
528                    JCVariableDecl varDef = make.VarDef(loc, tree.expr);
529                    result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
530                } else if (!isTarget_void || !isLambda_void) {
531                    //non-void to non-void conversion:
532                    // return (TYPE)RET-EXPR;
533                    tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
534                    result = tree;
535                } else {
536                    result = tree;
537                }
538
539            }
540        }
541
542        JCBlock trans_block = new LambdaBodyTranslator().translate(block);
543        if (completeNormally && isTarget_Void) {
544            //there's no return statement and the lambda (possibly inferred)
545            //return type is java.lang.Void; emit a synthetic return statement
546            trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
547        }
548        return trans_block;
549    }
550
551    private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
552        ListBuffer<JCCase> cases = new ListBuffer<>();
553        ListBuffer<JCBreak> breaks = new ListBuffer<>();
554        for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
555            JCBreak br = make.Break(null);
556            breaks.add(br);
557            List<JCStatement> stmts = entry.getValue().append(br).toList();
558            cases.add(make.Case(make.Literal(entry.getKey()), stmts));
559        }
560        JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
561        for (JCBreak br : breaks) {
562            br.target = sw;
563        }
564        JCBlock body = make.Block(0L, List.<JCStatement>of(
565                sw,
566                make.Throw(makeNewClass(
567                    syms.illegalArgumentExceptionType,
568                    List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
569        JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
570                        names.deserializeLambda,
571                        make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
572                        List.<JCTypeParameter>nil(),
573                        List.of(make.VarDef(kInfo.deserParamSym, null)),
574                        List.<JCExpression>nil(),
575                        body,
576                        null);
577        deser.sym = kInfo.deserMethodSym;
578        deser.type = kInfo.deserMethodSym.type;
579        //System.err.printf("DESER: '%s'\n", deser);
580        return deser;
581    }
582
583    /** Make an attributed class instance creation expression.
584     *  @param ctype    The class type.
585     *  @param args     The constructor arguments.
586     *  @param cons     The constructor symbol
587     */
588    JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
589        JCNewClass tree = make.NewClass(null,
590            null, make.QualIdent(ctype.tsym), args, null);
591        tree.constructor = cons;
592        tree.type = ctype;
593        return tree;
594    }
595
596    /** Make an attributed class instance creation expression.
597     *  @param ctype    The class type.
598     *  @param args     The constructor arguments.
599     */
600    JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
601        return makeNewClass(ctype, args,
602                rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
603     }
604
605    private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
606            DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
607        String functionalInterfaceClass = classSig(targetType);
608        String functionalInterfaceMethodName = samSym.getSimpleName().toString();
609        String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
610        String implClass = classSig(types.erasure(refSym.owner.type));
611        String implMethodName = refSym.getQualifiedName().toString();
612        String implMethodSignature = typeSig(types.erasure(refSym.type));
613
614        JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
615        ListBuffer<JCExpression> serArgs = new ListBuffer<>();
616        int i = 0;
617        for (Type t : indyType.getParameterTypes()) {
618            List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
619            List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
620            serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
621            ++i;
622        }
623        JCStatement stmt = make.If(
624                deserTest(deserTest(deserTest(deserTest(deserTest(
625                    kindTest,
626                    "getFunctionalInterfaceClass", functionalInterfaceClass),
627                    "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
628                    "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
629                    "getImplClass", implClass),
630                    "getImplMethodSignature", implMethodSignature),
631                make.Return(makeIndyCall(
632                    pos,
633                    syms.lambdaMetafactory,
634                    names.altMetafactory,
635                    staticArgs, indyType, serArgs.toList(), samSym.name)),
636                null);
637        ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
638        if (stmts == null) {
639            stmts = new ListBuffer<>();
640            kInfo.deserializeCases.put(implMethodName, stmts);
641        }
642        /****
643        System.err.printf("+++++++++++++++++\n");
644        System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
645        System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
646        System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
647        System.err.printf("*implMethodKind: %d\n", implMethodKind);
648        System.err.printf("*implClass: '%s'\n", implClass);
649        System.err.printf("*implMethodName: '%s'\n", implMethodName);
650        System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
651        ****/
652        stmts.append(stmt);
653    }
654
655    private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
656        JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
657        testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
658        testExpr.setType(syms.booleanType);
659        return testExpr;
660    }
661
662    private JCExpression deserTest(JCExpression prev, String func, String lit) {
663        MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
664        Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
665        JCMethodInvocation eqtest = make.Apply(
666                List.<JCExpression>nil(),
667                make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
668                List.<JCExpression>of(make.Literal(lit)));
669        eqtest.setType(syms.booleanType);
670        JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
671        compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
672        compound.setType(syms.booleanType);
673        return compound;
674    }
675
676    private JCExpression deserGetter(String func, Type type) {
677        return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
678    }
679
680    private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
681        MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
682        Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
683        return make.Apply(
684                    List.<JCExpression>nil(),
685                    make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
686                    args).setType(type);
687    }
688
689    /**
690     * Create new synthetic method with given flags, name, type, owner
691     */
692    private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
693        return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
694    }
695
696    /**
697     * Create new synthetic variable with given flags, name, type, owner
698     */
699    private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
700        return makeSyntheticVar(flags, names.fromString(name), type, owner);
701    }
702
703    /**
704     * Create new synthetic variable with given flags, name, type, owner
705     */
706    private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
707        return new VarSymbol(flags | SYNTHETIC, name, type, owner);
708    }
709
710    /**
711     * Set varargsElement field on a given tree (must be either a new class tree
712     * or a method call tree)
713     */
714    private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
715        if (varargsElement != null) {
716            switch (tree.getTag()) {
717                case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
718                case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
719                default: throw new AssertionError();
720            }
721        }
722    }
723
724    /**
725     * Convert method/constructor arguments by inserting appropriate cast
726     * as required by type-erasure - this is needed when bridging a lambda/method
727     * reference, as the bridged signature might require downcast to be compatible
728     * with the generated signature.
729     */
730    private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
731       Assert.check(meth.kind == MTH);
732       List<Type> formals = types.erasure(meth.type).getParameterTypes();
733       if (varargsElement != null) {
734           Assert.check((meth.flags() & VARARGS) != 0);
735       }
736       return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
737    }
738
739    // </editor-fold>
740
741    /**
742     * Converts a method reference which cannot be used directly into a lambda
743     */
744    private class MemberReferenceToLambda {
745
746        private final JCMemberReference tree;
747        private final ReferenceTranslationContext localContext;
748        private final Symbol owner;
749        private final ListBuffer<JCExpression> args = new ListBuffer<>();
750        private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
751
752        private JCExpression receiverExpression = null;
753
754        MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) {
755            this.tree = tree;
756            this.localContext = localContext;
757            this.owner = owner;
758        }
759
760        JCLambda lambda() {
761            int prevPos = make.pos;
762            try {
763                make.at(tree);
764
765                //body generation - this can be either a method call or a
766                //new instance creation expression, depending on the member reference kind
767                VarSymbol rcvr = addParametersReturnReceiver();
768                JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
769                        ? expressionInvoke(rcvr)
770                        : expressionNew();
771
772                JCLambda slam = make.Lambda(params.toList(), expr);
773                slam.targets = tree.targets;
774                slam.type = tree.type;
775                slam.pos = tree.pos;
776                return slam;
777            } finally {
778                make.at(prevPos);
779            }
780        }
781
782        /**
783         * Generate the parameter list for the converted member reference.
784         *
785         * @return The receiver variable symbol, if any
786         */
787        VarSymbol addParametersReturnReceiver() {
788            Type samDesc = localContext.bridgedRefSig();
789            List<Type> samPTypes = samDesc.getParameterTypes();
790            List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes();
791
792            // Determine the receiver, if any
793            VarSymbol rcvr;
794            switch (tree.kind) {
795                case BOUND:
796                    // The receiver is explicit in the method reference
797                    rcvr = addParameter("rec$", tree.getQualifierExpression().type, false);
798                    receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
799                    break;
800                case UNBOUND:
801                    // The receiver is the first parameter, extract it and
802                    // adjust the SAM and unerased type lists accordingly
803                    rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false);
804                    samPTypes = samPTypes.tail;
805                    descPTypes = descPTypes.tail;
806                    break;
807                default:
808                    rcvr = null;
809                    break;
810            }
811            List<Type> implPTypes = tree.sym.type.getParameterTypes();
812            int implSize = implPTypes.size();
813            int samSize = samPTypes.size();
814            // Last parameter to copy from referenced method, exclude final var args
815            int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize;
816
817            // Failsafe -- assure match-up
818            boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size();
819
820            // Use parameter types of the implementation method unless the unerased
821            // SAM parameter type is an intersection type, in that case use the
822            // erased SAM parameter type so that the supertype relationship
823            // the implementation method parameters is not obscured.
824            // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes
825            // are used as pointers to the current parameter type information
826            // and are thus not usable afterwards.
827            for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) {
828                // By default use the implementation method parmeter type
829                Type parmType = implPTypes.head;
830                // If the unerased parameter type is a type variable whose
831                // bound is an intersection (eg. <T extends A & B>) then
832                // use the SAM parameter type
833                if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) {
834                    TypeVar tv = (TypeVar) descPTypes.head;
835                    if (tv.bound.getKind() == TypeKind.INTERSECTION) {
836                        parmType = samPTypes.head;
837                    }
838                }
839                addParameter("x$" + i, parmType, true);
840
841                // Advance to the next parameter
842                implPTypes = implPTypes.tail;
843                samPTypes = samPTypes.tail;
844                descPTypes = descPTypes.tail;
845            }
846            // Flatten out the var args
847            for (int i = last; i < samSize; ++i) {
848                addParameter("xva$" + i, tree.varargsElement, true);
849            }
850
851            return rcvr;
852        }
853
854        JCExpression getReceiverExpression() {
855            return receiverExpression;
856        }
857
858        private JCExpression makeReceiver(VarSymbol rcvr) {
859            if (rcvr == null) return null;
860            JCExpression rcvrExpr = make.Ident(rcvr);
861            Type rcvrType = tree.sym.enclClass().type;
862            if (rcvrType == syms.arrayClass.type) {
863                // Map the receiver type to the actually type, not just "array"
864                rcvrType = tree.getQualifierExpression().type;
865            }
866            if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
867                rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
868            }
869            return rcvrExpr;
870        }
871
872        /**
873         * determine the receiver of the method call - the receiver can
874         * be a type qualifier, the synthetic receiver parameter or 'super'.
875         */
876        private JCExpression expressionInvoke(VarSymbol rcvr) {
877            JCExpression qualifier =
878                    tree.sym.isStatic() ?
879                        make.Type(tree.sym.owner.type) :
880                        (rcvr != null) ?
881                            makeReceiver(rcvr) :
882                            tree.getQualifierExpression();
883
884            //create the qualifier expression
885            JCFieldAccess select = make.Select(qualifier, tree.sym.name);
886            select.sym = tree.sym;
887            select.type = tree.sym.erasure(types);
888
889            //create the method call expression
890            JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
891                    convertArgs(tree.sym, args.toList(), tree.varargsElement)).
892                    setType(tree.sym.erasure(types).getReturnType());
893
894            apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
895            setVarargsIfNeeded(apply, tree.varargsElement);
896            return apply;
897        }
898
899        /**
900         * Lambda body to use for a 'new'.
901         */
902        private JCExpression expressionNew() {
903            if (tree.kind == ReferenceKind.ARRAY_CTOR) {
904                //create the array creation expression
905                JCNewArray newArr = make.NewArray(
906                        make.Type(types.elemtype(tree.getQualifierExpression().type)),
907                        List.of(make.Ident(params.first())),
908                        null);
909                newArr.type = tree.getQualifierExpression().type;
910                return newArr;
911            } else {
912                //create the instance creation expression
913                //note that method reference syntax does not allow an explicit
914                //enclosing class (so the enclosing class is null)
915                JCNewClass newClass = make.NewClass(null,
916                        List.<JCExpression>nil(),
917                        make.Type(tree.getQualifierExpression().type),
918                        convertArgs(tree.sym, args.toList(), tree.varargsElement),
919                        null);
920                newClass.constructor = tree.sym;
921                newClass.constructorType = tree.sym.erasure(types);
922                newClass.type = tree.getQualifierExpression().type;
923                setVarargsIfNeeded(newClass, tree.varargsElement);
924                return newClass;
925            }
926        }
927
928        private VarSymbol addParameter(String name, Type p, boolean genArg) {
929            VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
930            vsym.pos = tree.pos;
931            params.append(make.VarDef(vsym, null));
932            if (genArg) {
933                args.append(make.Ident(vsym));
934            }
935            return vsym;
936        }
937    }
938
939    private MethodType typeToMethodType(Type mt) {
940        Type type = types.erasure(mt);
941        return new MethodType(type.getParameterTypes(),
942                        type.getReturnType(),
943                        type.getThrownTypes(),
944                        syms.methodClass);
945    }
946
947    /**
948     * Generate an indy method call to the meta factory
949     */
950    private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
951            int refKind, Symbol refSym, List<JCExpression> indy_args) {
952        JCFunctionalExpression tree = context.tree;
953        //determine the static bsm args
954        MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
955        List<Object> staticArgs = List.<Object>of(
956                typeToMethodType(samSym.type),
957                new Pool.MethodHandle(refKind, refSym, types),
958                typeToMethodType(tree.getDescriptorType(types)));
959
960        //computed indy arg types
961        ListBuffer<Type> indy_args_types = new ListBuffer<>();
962        for (JCExpression arg : indy_args) {
963            indy_args_types.append(arg.type);
964        }
965
966        //finally, compute the type of the indy call
967        MethodType indyType = new MethodType(indy_args_types.toList(),
968                tree.type,
969                List.<Type>nil(),
970                syms.methodClass);
971
972        Name metafactoryName = context.needsAltMetafactory() ?
973                names.altMetafactory : names.metafactory;
974
975        if (context.needsAltMetafactory()) {
976            ListBuffer<Object> markers = new ListBuffer<>();
977            for (Type t : tree.targets.tail) {
978                if (t.tsym != syms.serializableType.tsym) {
979                    markers.append(t.tsym);
980                }
981            }
982            int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
983            boolean hasMarkers = markers.nonEmpty();
984            boolean hasBridges = context.bridges.nonEmpty();
985            if (hasMarkers) {
986                flags |= FLAG_MARKERS;
987            }
988            if (hasBridges) {
989                flags |= FLAG_BRIDGES;
990            }
991            staticArgs = staticArgs.append(flags);
992            if (hasMarkers) {
993                staticArgs = staticArgs.append(markers.length());
994                staticArgs = staticArgs.appendList(markers.toList());
995            }
996            if (hasBridges) {
997                staticArgs = staticArgs.append(context.bridges.length() - 1);
998                for (Symbol s : context.bridges) {
999                    Type s_erasure = s.erasure(types);
1000                    if (!types.isSameType(s_erasure, samSym.erasure(types))) {
1001                        staticArgs = staticArgs.append(s.erasure(types));
1002                    }
1003                }
1004            }
1005            if (context.isSerializable()) {
1006                int prevPos = make.pos;
1007                try {
1008                    make.at(kInfo.clazz);
1009                    addDeserializationCase(refKind, refSym, tree.type, samSym,
1010                            tree, staticArgs, indyType);
1011                } finally {
1012                    make.at(prevPos);
1013                }
1014            }
1015        }
1016
1017        return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
1018    }
1019
1020    /**
1021     * Generate an indy method call with given name, type and static bootstrap
1022     * arguments types
1023     */
1024    private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
1025            List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
1026            Name methName) {
1027        int prevPos = make.pos;
1028        try {
1029            make.at(pos);
1030            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
1031                    syms.stringType,
1032                    syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
1033
1034            Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
1035                    bsmName, bsm_staticArgs, List.<Type>nil());
1036
1037            DynamicMethodSymbol dynSym =
1038                    new DynamicMethodSymbol(methName,
1039                                            syms.noSymbol,
1040                                            bsm.isStatic() ?
1041                                                ClassFile.REF_invokeStatic :
1042                                                ClassFile.REF_invokeVirtual,
1043                                            (MethodSymbol)bsm,
1044                                            indyType,
1045                                            staticArgs.toArray());
1046
1047            JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
1048            qualifier.sym = dynSym;
1049            qualifier.type = indyType.getReturnType();
1050
1051            JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
1052            proxyCall.type = indyType.getReturnType();
1053            return proxyCall;
1054        } finally {
1055            make.at(prevPos);
1056        }
1057    }
1058    //where
1059    private List<Type> bsmStaticArgToTypes(List<Object> args) {
1060        ListBuffer<Type> argtypes = new ListBuffer<>();
1061        for (Object arg : args) {
1062            argtypes.append(bsmStaticArgToType(arg));
1063        }
1064        return argtypes.toList();
1065    }
1066
1067    private Type bsmStaticArgToType(Object arg) {
1068        Assert.checkNonNull(arg);
1069        if (arg instanceof ClassSymbol) {
1070            return syms.classType;
1071        } else if (arg instanceof Integer) {
1072            return syms.intType;
1073        } else if (arg instanceof Long) {
1074            return syms.longType;
1075        } else if (arg instanceof Float) {
1076            return syms.floatType;
1077        } else if (arg instanceof Double) {
1078            return syms.doubleType;
1079        } else if (arg instanceof String) {
1080            return syms.stringType;
1081        } else if (arg instanceof Pool.MethodHandle) {
1082            return syms.methodHandleType;
1083        } else if (arg instanceof MethodType) {
1084            return syms.methodTypeType;
1085        } else {
1086            Assert.error("bad static arg " + arg.getClass());
1087            return null;
1088        }
1089    }
1090
1091    /**
1092     * Get the opcode associated with this method reference
1093     */
1094    private int referenceKind(Symbol refSym) {
1095        if (refSym.isConstructor()) {
1096            return ClassFile.REF_newInvokeSpecial;
1097        } else {
1098            if (refSym.isStatic()) {
1099                return ClassFile.REF_invokeStatic;
1100            } else if ((refSym.flags() & PRIVATE) != 0) {
1101                return ClassFile.REF_invokeSpecial;
1102            } else if (refSym.enclClass().isInterface()) {
1103                return ClassFile.REF_invokeInterface;
1104            } else {
1105                return ClassFile.REF_invokeVirtual;
1106            }
1107        }
1108    }
1109
1110    // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1111    /**
1112     * This visitor collects information about translation of a lambda expression.
1113     * More specifically, it keeps track of the enclosing contexts and captured locals
1114     * accessed by the lambda being translated (as well as other useful info).
1115     * It also translates away problems for LambdaToMethod.
1116     */
1117    class LambdaAnalyzerPreprocessor extends TreeTranslator {
1118
1119        /** the frame stack - used to reconstruct translation info about enclosing scopes */
1120        private List<Frame> frameStack;
1121
1122        /**
1123         * keep the count of lambda expression (used to generate unambiguous
1124         * names)
1125         */
1126        private int lambdaCount = 0;
1127
1128        /**
1129         * keep the count of lambda expression defined in given context (used to
1130         * generate unambiguous names for serializable lambdas)
1131         */
1132        private class SyntheticMethodNameCounter {
1133            private Map<String, Integer> map = new HashMap<>();
1134            int getIndex(StringBuilder buf) {
1135                String temp = buf.toString();
1136                Integer count = map.get(temp);
1137                if (count == null) {
1138                    count = 0;
1139                }
1140                ++count;
1141                map.put(temp, count);
1142                return count;
1143            }
1144        }
1145        private SyntheticMethodNameCounter syntheticMethodNameCounts =
1146                new SyntheticMethodNameCounter();
1147
1148        private Map<Symbol, JCClassDecl> localClassDefs;
1149
1150        /**
1151         * maps for fake clinit symbols to be used as owners of lambda occurring in
1152         * a static var init context
1153         */
1154        private Map<ClassSymbol, Symbol> clinits = new HashMap<>();
1155
1156        private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
1157            frameStack = List.nil();
1158            localClassDefs = new HashMap<>();
1159            return translate(tree);
1160        }
1161
1162        @Override
1163        public void visitBlock(JCBlock tree) {
1164            List<Frame> prevStack = frameStack;
1165            try {
1166                if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
1167                    frameStack = frameStack.prepend(new Frame(tree));
1168                }
1169                super.visitBlock(tree);
1170            }
1171            finally {
1172                frameStack = prevStack;
1173            }
1174        }
1175
1176        @Override
1177        public void visitClassDef(JCClassDecl tree) {
1178            List<Frame> prevStack = frameStack;
1179            SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
1180                    syntheticMethodNameCounts;
1181            Map<ClassSymbol, Symbol> prevClinits = clinits;
1182            DiagnosticSource prevSource = log.currentSource();
1183            try {
1184                log.useSource(tree.sym.sourcefile);
1185                syntheticMethodNameCounts = new SyntheticMethodNameCounter();
1186                prevClinits = new HashMap<>();
1187                if (tree.sym.owner.kind == MTH) {
1188                    localClassDefs.put(tree.sym, tree);
1189                }
1190                if (directlyEnclosingLambda() != null) {
1191                    tree.sym.owner = owner();
1192                    if (tree.sym.hasOuterInstance()) {
1193                        //if a class is defined within a lambda, the lambda must capture
1194                        //its enclosing instance (if any)
1195                        TranslationContext<?> localContext = context();
1196                        while (localContext != null) {
1197                            if (localContext.tree.getTag() == LAMBDA) {
1198                                ((LambdaTranslationContext)localContext)
1199                                        .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
1200                            }
1201                            localContext = localContext.prev;
1202                        }
1203                    }
1204                }
1205                frameStack = frameStack.prepend(new Frame(tree));
1206                super.visitClassDef(tree);
1207            }
1208            finally {
1209                log.useSource(prevSource.getFile());
1210                frameStack = prevStack;
1211                syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
1212                clinits = prevClinits;
1213            }
1214        }
1215
1216        @Override
1217        public void visitIdent(JCIdent tree) {
1218            if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
1219                if (tree.sym.kind == VAR &&
1220                        tree.sym.owner.kind == MTH &&
1221                        tree.type.constValue() == null) {
1222                    TranslationContext<?> localContext = context();
1223                    while (localContext != null) {
1224                        if (localContext.tree.getTag() == LAMBDA) {
1225                            JCTree block = capturedDecl(localContext.depth, tree.sym);
1226                            if (block == null) break;
1227                            ((LambdaTranslationContext)localContext)
1228                                    .addSymbol(tree.sym, CAPTURED_VAR);
1229                        }
1230                        localContext = localContext.prev;
1231                    }
1232                } else if (tree.sym.owner.kind == TYP) {
1233                    TranslationContext<?> localContext = context();
1234                    while (localContext != null) {
1235                        if (localContext.tree.hasTag(LAMBDA)) {
1236                            JCTree block = capturedDecl(localContext.depth, tree.sym);
1237                            if (block == null) break;
1238                            switch (block.getTag()) {
1239                                case CLASSDEF:
1240                                    JCClassDecl cdecl = (JCClassDecl)block;
1241                                    ((LambdaTranslationContext)localContext)
1242                                            .addSymbol(cdecl.sym, CAPTURED_THIS);
1243                                    break;
1244                                default:
1245                                    Assert.error("bad block kind");
1246                            }
1247                        }
1248                        localContext = localContext.prev;
1249                    }
1250                }
1251            }
1252            super.visitIdent(tree);
1253        }
1254
1255        @Override
1256        public void visitLambda(JCLambda tree) {
1257            analyzeLambda(tree, "lambda.stat");
1258        }
1259
1260        private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) {
1261            // Translation of the receiver expression must occur first
1262            JCExpression rcvr = translate(methodReferenceReceiver);
1263            LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1");
1264            if (rcvr != null) {
1265                context.methodReferenceReceiver = rcvr;
1266            }
1267        }
1268
1269        private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) {
1270            List<Frame> prevStack = frameStack;
1271            try {
1272                LambdaTranslationContext context = new LambdaTranslationContext(tree);
1273                if (dumpLambdaToMethodStats) {
1274                    log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym);
1275                }
1276                frameStack = frameStack.prepend(new Frame(tree));
1277                for (JCVariableDecl param : tree.params) {
1278                    context.addSymbol(param.sym, PARAM);
1279                    frameStack.head.addLocal(param.sym);
1280                }
1281                contextMap.put(tree, context);
1282                super.visitLambda(tree);
1283                context.complete();
1284                return context;
1285            }
1286            finally {
1287                frameStack = prevStack;
1288            }
1289        }
1290
1291        @Override
1292        public void visitMethodDef(JCMethodDecl tree) {
1293            List<Frame> prevStack = frameStack;
1294            try {
1295                frameStack = frameStack.prepend(new Frame(tree));
1296                super.visitMethodDef(tree);
1297            }
1298            finally {
1299                frameStack = prevStack;
1300            }
1301        }
1302
1303        @Override
1304        public void visitNewClass(JCNewClass tree) {
1305            TypeSymbol def = tree.type.tsym;
1306            boolean inReferencedClass = currentlyInClass(def);
1307            boolean isLocal = def.isLocal();
1308            if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
1309                TranslationContext<?> localContext = context();
1310                while (localContext != null) {
1311                    if (localContext.tree.getTag() == LAMBDA) {
1312                        ((LambdaTranslationContext)localContext)
1313                                .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
1314                    }
1315                    localContext = localContext.prev;
1316                }
1317            }
1318            if (context() != null && !inReferencedClass && isLocal) {
1319                LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
1320                captureLocalClassDefs(def, lambdaContext);
1321            }
1322            super.visitNewClass(tree);
1323        }
1324        //where
1325            void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
1326                JCClassDecl localCDef = localClassDefs.get(csym);
1327                if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
1328                    BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
1329                        @Override
1330                        void addFreeVars(ClassSymbol c) {
1331                            captureLocalClassDefs(c, lambdaContext);
1332                        }
1333                        @Override
1334                        void visitSymbol(Symbol sym) {
1335                            if (sym.kind == VAR &&
1336                                    sym.owner.kind == MTH &&
1337                                    ((VarSymbol)sym).getConstValue() == null) {
1338                                TranslationContext<?> localContext = context();
1339                                while (localContext != null) {
1340                                    if (localContext.tree.getTag() == LAMBDA) {
1341                                        JCTree block = capturedDecl(localContext.depth, sym);
1342                                        if (block == null) break;
1343                                        ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
1344                                    }
1345                                    localContext = localContext.prev;
1346                                }
1347                            }
1348                        }
1349                    };
1350                    fvc.scan(localCDef);
1351                }
1352        }
1353        //where
1354        boolean currentlyInClass(Symbol csym) {
1355            for (Frame frame : frameStack) {
1356                if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
1357                    JCClassDecl cdef = (JCClassDecl) frame.tree;
1358                    if (cdef.sym == csym) {
1359                        return true;
1360                    }
1361                }
1362            }
1363            return false;
1364        }
1365
1366        /**
1367         * Method references to local class constructors, may, if the local
1368         * class references local variables, have implicit constructor
1369         * parameters added in Lower; As a result, the invokedynamic bootstrap
1370         * information added in the LambdaToMethod pass will have the wrong
1371         * signature. Hooks between Lower and LambdaToMethod have been added to
1372         * handle normal "new" in this case. This visitor converts potentially
1373         * affected method references into a lambda containing a normal
1374         * expression.
1375         *
1376         * @param tree
1377         */
1378        @Override
1379        public void visitReference(JCMemberReference tree) {
1380            ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree);
1381            contextMap.put(tree, rcontext);
1382            if (rcontext.needsConversionToLambda()) {
1383                 // Convert to a lambda, and process as such
1384                MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner());
1385                analyzeLambda(conv.lambda(), conv.getReceiverExpression());
1386            } else {
1387                super.visitReference(tree);
1388                if (dumpLambdaToMethodStats) {
1389                    log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null);
1390                }
1391            }
1392        }
1393
1394        @Override
1395        public void visitSelect(JCFieldAccess tree) {
1396            if (context() != null && tree.sym.kind == VAR &&
1397                        (tree.sym.name == names._this ||
1398                         tree.sym.name == names._super)) {
1399                // A select of this or super means, if we are in a lambda,
1400                // we much have an instance context
1401                TranslationContext<?> localContext = context();
1402                while (localContext != null) {
1403                    if (localContext.tree.hasTag(LAMBDA)) {
1404                        JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
1405                        if (clazz == null) break;
1406                        ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
1407                    }
1408                    localContext = localContext.prev;
1409                }
1410            }
1411            super.visitSelect(tree);
1412        }
1413
1414        @Override
1415        public void visitVarDef(JCVariableDecl tree) {
1416            TranslationContext<?> context = context();
1417            LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
1418                    (LambdaTranslationContext)context :
1419                    null;
1420            if (ltc != null) {
1421                if (frameStack.head.tree.hasTag(LAMBDA)) {
1422                    ltc.addSymbol(tree.sym, LOCAL_VAR);
1423                }
1424                // Check for type variables (including as type arguments).
1425                // If they occur within class nested in a lambda, mark for erasure
1426                Type type = tree.sym.asType();
1427                if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
1428                    ltc.addSymbol(tree.sym, TYPE_VAR);
1429                }
1430            }
1431
1432            List<Frame> prevStack = frameStack;
1433            try {
1434                if (tree.sym.owner.kind == MTH) {
1435                    frameStack.head.addLocal(tree.sym);
1436                }
1437                frameStack = frameStack.prepend(new Frame(tree));
1438                super.visitVarDef(tree);
1439            }
1440            finally {
1441                frameStack = prevStack;
1442            }
1443        }
1444
1445        /**
1446         * Return a valid owner given the current declaration stack
1447         * (required to skip synthetic lambda symbols)
1448         */
1449        private Symbol owner() {
1450            return owner(false);
1451        }
1452
1453        @SuppressWarnings("fallthrough")
1454        private Symbol owner(boolean skipLambda) {
1455            List<Frame> frameStack2 = frameStack;
1456            while (frameStack2.nonEmpty()) {
1457                switch (frameStack2.head.tree.getTag()) {
1458                    case VARDEF:
1459                        if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
1460                            frameStack2 = frameStack2.tail;
1461                            break;
1462                        }
1463                        JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
1464                        return initSym(cdecl.sym,
1465                                ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
1466                    case BLOCK:
1467                        JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
1468                        return initSym(cdecl2.sym,
1469                                ((JCBlock)frameStack2.head.tree).flags & STATIC);
1470                    case CLASSDEF:
1471                        return ((JCClassDecl)frameStack2.head.tree).sym;
1472                    case METHODDEF:
1473                        return ((JCMethodDecl)frameStack2.head.tree).sym;
1474                    case LAMBDA:
1475                        if (!skipLambda)
1476                            return ((LambdaTranslationContext)contextMap
1477                                    .get(frameStack2.head.tree)).translatedSym;
1478                    default:
1479                        frameStack2 = frameStack2.tail;
1480                }
1481            }
1482            Assert.error();
1483            return null;
1484        }
1485
1486        private Symbol initSym(ClassSymbol csym, long flags) {
1487            boolean isStatic = (flags & STATIC) != 0;
1488            if (isStatic) {
1489                /* static clinits are generated in Gen, so we need to use a fake
1490                 * one. Attr creates a fake clinit method while attributing
1491                 * lambda expressions used as initializers of static fields, so
1492                 * let's use that one.
1493                 */
1494                MethodSymbol clinit = attr.removeClinit(csym);
1495                if (clinit != null) {
1496                    clinits.put(csym, clinit);
1497                    return clinit;
1498                }
1499
1500                /* if no clinit is found at Attr, then let's try at clinits.
1501                 */
1502                clinit = (MethodSymbol)clinits.get(csym);
1503                if (clinit == null) {
1504                    /* no luck, let's create a new one
1505                     */
1506                    clinit = makePrivateSyntheticMethod(STATIC,
1507                            names.clinit,
1508                            new MethodType(List.<Type>nil(), syms.voidType,
1509                                List.<Type>nil(), syms.methodClass),
1510                            csym);
1511                    clinits.put(csym, clinit);
1512                }
1513                return clinit;
1514            } else {
1515                //get the first constructor and treat it as the instance init sym
1516                for (Symbol s : csym.members_field.getSymbolsByName(names.init)) {
1517                    return s;
1518                }
1519            }
1520            Assert.error("init not found");
1521            return null;
1522        }
1523
1524        private JCTree directlyEnclosingLambda() {
1525            if (frameStack.isEmpty()) {
1526                return null;
1527            }
1528            List<Frame> frameStack2 = frameStack;
1529            while (frameStack2.nonEmpty()) {
1530                switch (frameStack2.head.tree.getTag()) {
1531                    case CLASSDEF:
1532                    case METHODDEF:
1533                        return null;
1534                    case LAMBDA:
1535                        return frameStack2.head.tree;
1536                    default:
1537                        frameStack2 = frameStack2.tail;
1538                }
1539            }
1540            Assert.error();
1541            return null;
1542        }
1543
1544        private boolean inClassWithinLambda() {
1545            if (frameStack.isEmpty()) {
1546                return false;
1547            }
1548            List<Frame> frameStack2 = frameStack;
1549            boolean classFound = false;
1550            while (frameStack2.nonEmpty()) {
1551                switch (frameStack2.head.tree.getTag()) {
1552                    case LAMBDA:
1553                        return classFound;
1554                    case CLASSDEF:
1555                        classFound = true;
1556                        frameStack2 = frameStack2.tail;
1557                        break;
1558                    default:
1559                        frameStack2 = frameStack2.tail;
1560                }
1561            }
1562            // No lambda
1563            return false;
1564        }
1565
1566        /**
1567         * Return the declaration corresponding to a symbol in the enclosing
1568         * scope; the depth parameter is used to filter out symbols defined
1569         * in nested scopes (which do not need to undergo capture).
1570         */
1571        private JCTree capturedDecl(int depth, Symbol sym) {
1572            int currentDepth = frameStack.size() - 1;
1573            for (Frame block : frameStack) {
1574                switch (block.tree.getTag()) {
1575                    case CLASSDEF:
1576                        ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
1577                        if (sym.isMemberOf(clazz, types)) {
1578                            return currentDepth > depth ? null : block.tree;
1579                        }
1580                        break;
1581                    case VARDEF:
1582                        if (((JCVariableDecl)block.tree).sym == sym &&
1583                                sym.owner.kind == MTH) { //only locals are captured
1584                            return currentDepth > depth ? null : block.tree;
1585                        }
1586                        break;
1587                    case BLOCK:
1588                    case METHODDEF:
1589                    case LAMBDA:
1590                        if (block.locals != null && block.locals.contains(sym)) {
1591                            return currentDepth > depth ? null : block.tree;
1592                        }
1593                        break;
1594                    default:
1595                        Assert.error("bad decl kind " + block.tree.getTag());
1596                }
1597                currentDepth--;
1598            }
1599            return null;
1600        }
1601
1602        private TranslationContext<?> context() {
1603            for (Frame frame : frameStack) {
1604                TranslationContext<?> context = contextMap.get(frame.tree);
1605                if (context != null) {
1606                    return context;
1607                }
1608            }
1609            return null;
1610        }
1611
1612        /**
1613         *  This is used to filter out those identifiers that needs to be adjusted
1614         *  when translating away lambda expressions
1615         */
1616        private boolean lambdaIdentSymbolFilter(Symbol sym) {
1617            return (sym.kind == VAR || sym.kind == MTH)
1618                    && !sym.isStatic()
1619                    && sym.name != names.init;
1620        }
1621
1622        /**
1623         * This is used to filter out those new class expressions that need to
1624         * be qualified with an enclosing tree
1625         */
1626        private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
1627            if (context != null
1628                    && tree.encl == null
1629                    && tree.def == null
1630                    && !tree.type.getEnclosingType().hasTag(NONE)) {
1631                Type encl = tree.type.getEnclosingType();
1632                Type current = context.owner.enclClass().type;
1633                while (!current.hasTag(NONE)) {
1634                    if (current.tsym.isSubClass(encl.tsym, types)) {
1635                        return true;
1636                    }
1637                    current = current.getEnclosingType();
1638                }
1639                return false;
1640            } else {
1641                return false;
1642            }
1643        }
1644
1645        private class Frame {
1646            final JCTree tree;
1647            List<Symbol> locals;
1648
1649            public Frame(JCTree tree) {
1650                this.tree = tree;
1651            }
1652
1653            void addLocal(Symbol sym) {
1654                if (locals == null) {
1655                    locals = List.nil();
1656                }
1657                locals = locals.prepend(sym);
1658            }
1659        }
1660
1661        /**
1662         * This class is used to store important information regarding translation of
1663         * lambda expression/method references (see subclasses).
1664         */
1665        private abstract class TranslationContext<T extends JCFunctionalExpression> {
1666
1667            /** the underlying (untranslated) tree */
1668            final T tree;
1669
1670            /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
1671            final Symbol owner;
1672
1673            /** the depth of this lambda expression in the frame stack */
1674            final int depth;
1675
1676            /** the enclosing translation context (set for nested lambdas/mref) */
1677            final TranslationContext<?> prev;
1678
1679            /** list of methods to be bridged by the meta-factory */
1680            final List<Symbol> bridges;
1681
1682            TranslationContext(T tree) {
1683                this.tree = tree;
1684                this.owner = owner();
1685                this.depth = frameStack.size() - 1;
1686                this.prev = context();
1687                ClassSymbol csym =
1688                        types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
1689                this.bridges = types.functionalInterfaceBridges(csym);
1690            }
1691
1692            /** does this functional expression need to be created using alternate metafactory? */
1693            boolean needsAltMetafactory() {
1694                return tree.targets.length() > 1 ||
1695                        isSerializable() ||
1696                        bridges.length() > 1;
1697            }
1698
1699            /** does this functional expression require serialization support? */
1700            boolean isSerializable() {
1701                if (forceSerializable) {
1702                    return true;
1703                }
1704                for (Type target : tree.targets) {
1705                    if (types.asSuper(target, syms.serializableType.tsym) != null) {
1706                        return true;
1707                    }
1708                }
1709                return false;
1710            }
1711
1712            /**
1713             * @return Name of the enclosing method to be folded into synthetic
1714             * method name
1715             */
1716            String enclosingMethodName() {
1717                return syntheticMethodNameComponent(owner.name);
1718            }
1719
1720            /**
1721             * @return Method name in a form that can be folded into a
1722             * component of a synthetic method name
1723             */
1724            String syntheticMethodNameComponent(Name name) {
1725                if (name == null) {
1726                    return "null";
1727                }
1728                String methodName = name.toString();
1729                if (methodName.equals("<clinit>")) {
1730                    methodName = "static";
1731                } else if (methodName.equals("<init>")) {
1732                    methodName = "new";
1733                }
1734                return methodName;
1735            }
1736        }
1737
1738        /**
1739         * This class retains all the useful information about a lambda expression;
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 references
1742         * to captured locals/members, etc.
1743         */
1744        private class LambdaTranslationContext extends TranslationContext<JCLambda> {
1745
1746            /** variable in the enclosing context to which this lambda is assigned */
1747            final Symbol self;
1748
1749            /** variable in the enclosing context to which this lambda is assigned */
1750            final Symbol assignedTo;
1751
1752            Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
1753
1754            /** the synthetic symbol for the method hoisting the translated lambda */
1755            Symbol translatedSym;
1756
1757            List<JCVariableDecl> syntheticParams;
1758
1759            /**
1760             * to prevent recursion, track local classes processed
1761             */
1762            final Set<Symbol> freeVarProcessedLocalClasses;
1763
1764            /**
1765             * For method references converted to lambdas.  The method
1766             * reference receiver expression. Must be treated like a captured
1767             * variable.
1768             */
1769            JCExpression methodReferenceReceiver;
1770
1771            LambdaTranslationContext(JCLambda tree) {
1772                super(tree);
1773                Frame frame = frameStack.head;
1774                switch (frame.tree.getTag()) {
1775                    case VARDEF:
1776                        assignedTo = self = ((JCVariableDecl) frame.tree).sym;
1777                        break;
1778                    case ASSIGN:
1779                        self = null;
1780                        assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
1781                        break;
1782                    default:
1783                        assignedTo = self = null;
1784                        break;
1785                 }
1786
1787                // This symbol will be filled-in in complete
1788                this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
1789
1790                translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
1791
1792                translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
1793                translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
1794                translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
1795                translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
1796                translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
1797
1798                freeVarProcessedLocalClasses = new HashSet<>();
1799            }
1800
1801             /**
1802             * For a serializable lambda, generate a disambiguating string
1803             * which maximizes stability across deserialization.
1804             *
1805             * @return String to differentiate synthetic lambda method names
1806             */
1807            private String serializedLambdaDisambiguation() {
1808                StringBuilder buf = new StringBuilder();
1809                // Append the enclosing method signature to differentiate
1810                // overloaded enclosing methods.  For lambdas enclosed in
1811                // lambdas, the generated lambda method will not have type yet,
1812                // but the enclosing method's name will have been generated
1813                // with this same method, so it will be unique and never be
1814                // overloaded.
1815                Assert.check(
1816                        owner.type != null ||
1817                        directlyEnclosingLambda() != null);
1818                if (owner.type != null) {
1819                    buf.append(typeSig(owner.type));
1820                    buf.append(":");
1821                }
1822
1823                // Add target type info
1824                buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
1825                buf.append(" ");
1826
1827                // Add variable assigned to
1828                if (assignedTo != null) {
1829                    buf.append(assignedTo.flatName());
1830                    buf.append("=");
1831                }
1832                //add captured locals info: type, name, order
1833                for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
1834                    if (fv != self) {
1835                        buf.append(typeSig(fv.type));
1836                        buf.append(" ");
1837                        buf.append(fv.flatName());
1838                        buf.append(",");
1839                    }
1840                }
1841
1842                return buf.toString();
1843            }
1844
1845            /**
1846             * For a non-serializable lambda, generate a simple method.
1847             *
1848             * @return Name to use for the synthetic lambda method name
1849             */
1850            private Name lambdaName() {
1851                return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
1852            }
1853
1854            /**
1855             * For a serializable lambda, generate a method name which maximizes
1856             * name stability across deserialization.
1857             *
1858             * @return Name to use for the synthetic lambda method name
1859             */
1860            private Name serializedLambdaName() {
1861                StringBuilder buf = new StringBuilder();
1862                buf.append(names.lambda);
1863                // Append the name of the method enclosing the lambda.
1864                buf.append(enclosingMethodName());
1865                buf.append('$');
1866                // Append a hash of the disambiguating string : enclosing method
1867                // signature, etc.
1868                String disam = serializedLambdaDisambiguation();
1869                buf.append(Integer.toHexString(disam.hashCode()));
1870                buf.append('$');
1871                // The above appended name components may not be unique, append
1872                // a count based on the above name components.
1873                buf.append(syntheticMethodNameCounts.getIndex(buf));
1874                String result = buf.toString();
1875                //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
1876                return names.fromString(result);
1877            }
1878
1879            /**
1880             * Translate a symbol of a given kind into something suitable for the
1881             * synthetic lambda body
1882             */
1883            Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
1884                Symbol ret;
1885                switch (skind) {
1886                    case CAPTURED_THIS:
1887                        ret = sym;  // self represented
1888                        break;
1889                    case TYPE_VAR:
1890                        // Just erase the type var
1891                        ret = new VarSymbol(sym.flags(), name,
1892                                types.erasure(sym.type), sym.owner);
1893
1894                        /* this information should also be kept for LVT generation at Gen
1895                         * a Symbol with pos < startPos won't be tracked.
1896                         */
1897                        ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
1898                        break;
1899                    case CAPTURED_VAR:
1900                        ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
1901                            @Override
1902                            public Symbol baseSymbol() {
1903                                //keep mapping with original captured symbol
1904                                return sym;
1905                            }
1906                        };
1907                        break;
1908                    case LOCAL_VAR:
1909                        ret = new VarSymbol(sym.flags() & FINAL, name, sym.type, translatedSym);
1910                        ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1911                        break;
1912                    case PARAM:
1913                        ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, name, types.erasure(sym.type), translatedSym);
1914                        ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1915                        break;
1916                    default:
1917                        ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
1918                        ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1919                }
1920                if (ret != sym) {
1921                    ret.setDeclarationAttributes(sym.getRawAttributes());
1922                    ret.setTypeAttributes(sym.getRawTypeAttributes());
1923                }
1924                return ret;
1925            }
1926
1927            void addSymbol(Symbol sym, LambdaSymbolKind skind) {
1928                Map<Symbol, Symbol> transMap = getSymbolMap(skind);
1929                Name preferredName;
1930                switch (skind) {
1931                    case CAPTURED_THIS:
1932                        preferredName = names.fromString("encl$" + transMap.size());
1933                        break;
1934                    case CAPTURED_VAR:
1935                        preferredName = names.fromString("cap$" + transMap.size());
1936                        break;
1937                    case LOCAL_VAR:
1938                        preferredName = sym.name;
1939                        break;
1940                    case PARAM:
1941                        preferredName = sym.name;
1942                        break;
1943                    case TYPE_VAR:
1944                        preferredName = sym.name;
1945                        break;
1946                    default: throw new AssertionError();
1947                }
1948                if (!transMap.containsKey(sym)) {
1949                    transMap.put(sym, translate(preferredName, sym, skind));
1950                }
1951            }
1952
1953            Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
1954                Map<Symbol, Symbol> m = translatedSymbols.get(skind);
1955                Assert.checkNonNull(m);
1956                return m;
1957            }
1958
1959            JCTree translate(JCIdent lambdaIdent) {
1960                for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
1961                    if (m.containsKey(lambdaIdent.sym)) {
1962                        Symbol tSym = m.get(lambdaIdent.sym);
1963                        JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
1964                        tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
1965                        return t;
1966                    }
1967                }
1968                return null;
1969            }
1970
1971            /**
1972             * The translatedSym is not complete/accurate until the analysis is
1973             * finished.  Once the analysis is finished, the translatedSym is
1974             * "completed" -- updated with type information, access modifiers,
1975             * and full parameter list.
1976             */
1977            void complete() {
1978                if (syntheticParams != null) {
1979                    return;
1980                }
1981                boolean inInterface = translatedSym.owner.isInterface();
1982                boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
1983
1984                // If instance access isn't needed, make it static.
1985                // Interface instance methods must be default methods.
1986                // Lambda methods are private synthetic.
1987                // Inherit ACC_STRICT from the enclosing method, or, for clinit,
1988                // from the class.
1989                translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
1990                        owner.flags_field & STRICTFP |
1991                        owner.owner.flags_field & STRICTFP |
1992                        PRIVATE |
1993                        (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
1994
1995                //compute synthetic params
1996                ListBuffer<JCVariableDecl> params = new ListBuffer<>();
1997
1998                // The signature of the method is augmented with the following
1999                // synthetic parameters:
2000                //
2001                // 1) reference to enclosing contexts captured by the lambda expression
2002                // 2) enclosing locals captured by the lambda expression
2003                for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
2004                    params.append(make.VarDef((VarSymbol) thisSym, null));
2005                }
2006                if (methodReferenceReceiver != null) {
2007                    params.append(make.VarDef(
2008                            make.Modifiers(PARAMETER|FINAL),
2009                            names.fromString("$rcvr$"),
2010                            make.Type(methodReferenceReceiver.type),
2011                            null));
2012                }
2013                for (Symbol thisSym : getSymbolMap(PARAM).values()) {
2014                    params.append(make.VarDef((VarSymbol) thisSym, null));
2015                }
2016                syntheticParams = params.toList();
2017
2018                // Compute and set the lambda name
2019                translatedSym.name = isSerializable()
2020                        ? serializedLambdaName()
2021                        : lambdaName();
2022
2023                //prepend synthetic args to translated lambda method signature
2024                translatedSym.type = types.createMethodTypeWithParameters(
2025                        generatedLambdaSig(),
2026                        TreeInfo.types(syntheticParams));
2027            }
2028
2029            Type generatedLambdaSig() {
2030                return types.erasure(tree.getDescriptorType(types));
2031            }
2032        }
2033
2034        /**
2035         * This class retains all the useful information about a method reference;
2036         * the contents of this class are filled by the LambdaAnalyzer visitor,
2037         * and the used by the main translation routines in order to adjust method
2038         * references (i.e. in case a bridge is needed)
2039         */
2040        private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
2041
2042            final boolean isSuper;
2043            final Symbol sigPolySym;
2044
2045            ReferenceTranslationContext(JCMemberReference tree) {
2046                super(tree);
2047                this.isSuper = tree.hasKind(ReferenceKind.SUPER);
2048                this.sigPolySym = isSignaturePolymorphic()
2049                        ? makePrivateSyntheticMethod(tree.sym.flags(),
2050                                              tree.sym.name,
2051                                              bridgedRefSig(),
2052                                              tree.sym.enclClass())
2053                        : null;
2054            }
2055
2056            /**
2057             * Get the opcode associated with this method reference
2058             */
2059            int referenceKind() {
2060                return LambdaToMethod.this.referenceKind(tree.sym);
2061            }
2062
2063            boolean needsVarArgsConversion() {
2064                return tree.varargsElement != null;
2065            }
2066
2067            /**
2068             * @return Is this an array operation like clone()
2069             */
2070            boolean isArrayOp() {
2071                return tree.sym.owner == syms.arrayClass;
2072            }
2073
2074            boolean receiverAccessible() {
2075                //hack needed to workaround 292 bug (7087658)
2076                //when 292 issue is fixed we should remove this and change the backend
2077                //code to always generate a method handle to an accessible method
2078                return tree.ownerAccessible;
2079            }
2080
2081            /**
2082             * The VM does not support access across nested classes (8010319).
2083             * Were that ever to change, this should be removed.
2084             */
2085            boolean isPrivateInOtherClass() {
2086                return  (tree.sym.flags() & PRIVATE) != 0 &&
2087                        !types.isSameType(
2088                              types.erasure(tree.sym.enclClass().asType()),
2089                              types.erasure(owner.enclClass().asType()));
2090            }
2091
2092            /**
2093             * Signature polymorphic methods need special handling.
2094             * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
2095             */
2096            final boolean isSignaturePolymorphic() {
2097                return  tree.sym.kind == MTH &&
2098                        types.isSignaturePolymorphic((MethodSymbol)tree.sym);
2099            }
2100
2101            /**
2102             * Erasure destroys the implementation parameter subtype
2103             * relationship for intersection types
2104             */
2105            boolean interfaceParameterIsIntersectionType() {
2106                List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
2107                if (tree.kind == ReferenceKind.UNBOUND) {
2108                    tl = tl.tail;
2109                }
2110                for (; tl.nonEmpty(); tl = tl.tail) {
2111                    Type pt = tl.head;
2112                    if (pt.getKind() == TypeKind.TYPEVAR) {
2113                        TypeVar tv = (TypeVar) pt;
2114                        if (tv.bound.getKind() == TypeKind.INTERSECTION) {
2115                            return true;
2116                        }
2117                    }
2118                }
2119                return false;
2120            }
2121
2122            /**
2123             * Does this reference need to be converted to a lambda
2124             * (i.e. var args need to be expanded or "super" is used)
2125             */
2126            final boolean needsConversionToLambda() {
2127                return interfaceParameterIsIntersectionType() ||
2128                        isSuper ||
2129                        needsVarArgsConversion() ||
2130                        isArrayOp() ||
2131                        isPrivateInOtherClass() ||
2132                        !receiverAccessible() ||
2133                        (tree.getMode() == ReferenceMode.NEW &&
2134                          tree.kind != ReferenceKind.ARRAY_CTOR &&
2135                          (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
2136            }
2137
2138            Type generatedRefSig() {
2139                return types.erasure(tree.sym.type);
2140            }
2141
2142            Type bridgedRefSig() {
2143                return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
2144            }
2145        }
2146    }
2147    // </editor-fold>
2148
2149    /*
2150     * These keys provide mappings for various translated lambda symbols
2151     * and the prevailing order must be maintained.
2152     */
2153    enum LambdaSymbolKind {
2154        PARAM,          // original to translated lambda parameters
2155        LOCAL_VAR,      // original to translated lambda locals
2156        CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
2157        CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
2158        TYPE_VAR       // original to translated lambda type variables
2159    }
2160
2161    /**
2162     * ****************************************************************
2163     * Signature Generation
2164     * ****************************************************************
2165     */
2166
2167    private String typeSig(Type type) {
2168        L2MSignatureGenerator sg = new L2MSignatureGenerator();
2169        sg.assembleSig(type);
2170        return sg.toString();
2171    }
2172
2173    private String classSig(Type type) {
2174        L2MSignatureGenerator sg = new L2MSignatureGenerator();
2175        sg.assembleClassSig(type);
2176        return sg.toString();
2177    }
2178
2179    /**
2180     * Signature Generation
2181     */
2182    private class L2MSignatureGenerator extends Types.SignatureGenerator {
2183
2184        /**
2185         * An output buffer for type signatures.
2186         */
2187        StringBuilder sb = new StringBuilder();
2188
2189        L2MSignatureGenerator() {
2190            super(types);
2191        }
2192
2193        @Override
2194        protected void append(char ch) {
2195            sb.append(ch);
2196        }
2197
2198        @Override
2199        protected void append(byte[] ba) {
2200            sb.append(new String(ba));
2201        }
2202
2203        @Override
2204        protected void append(Name name) {
2205            sb.append(name.toString());
2206        }
2207
2208        @Override
2209        public String toString() {
2210            return sb.toString();
2211        }
2212    }
2213}
2214