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