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