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