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