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