Tue, 05 Apr 2016 10:40:01 -0700
Merge
1 /*
2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.sun.tools.javac.comp;
27 import com.sun.tools.javac.tree.*;
28 import com.sun.tools.javac.tree.JCTree.*;
29 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
30 import com.sun.tools.javac.tree.TreeMaker;
31 import com.sun.tools.javac.tree.TreeTranslator;
32 import com.sun.tools.javac.code.Attribute;
33 import com.sun.tools.javac.code.Kinds;
34 import com.sun.tools.javac.code.Scope;
35 import com.sun.tools.javac.code.Symbol;
36 import com.sun.tools.javac.code.Symbol.ClassSymbol;
37 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
38 import com.sun.tools.javac.code.Symbol.MethodSymbol;
39 import com.sun.tools.javac.code.Symbol.TypeSymbol;
40 import com.sun.tools.javac.code.Symbol.VarSymbol;
41 import com.sun.tools.javac.code.Symtab;
42 import com.sun.tools.javac.code.Type;
43 import com.sun.tools.javac.code.Type.MethodType;
44 import com.sun.tools.javac.code.Type.TypeVar;
45 import com.sun.tools.javac.code.Types;
46 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
47 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
48 import com.sun.tools.javac.jvm.*;
49 import com.sun.tools.javac.util.*;
50 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
51 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
53 import java.util.EnumMap;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.LinkedHashMap;
57 import java.util.Map;
58 import java.util.Set;
60 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
61 import static com.sun.tools.javac.code.Flags.*;
62 import static com.sun.tools.javac.code.Kinds.*;
63 import static com.sun.tools.javac.code.TypeTag.*;
64 import static com.sun.tools.javac.tree.JCTree.Tag.*;
65 import javax.lang.model.type.TypeKind;
67 /**
68 * This pass desugars lambda expressions into static methods
69 *
70 * <p><b>This is NOT part of any supported API.
71 * If you write code that depends on this, you do so at your own risk.
72 * This code and its internal interfaces are subject to change or
73 * deletion without notice.</b>
74 */
75 public class LambdaToMethod extends TreeTranslator {
77 private Attr attr;
78 private JCDiagnostic.Factory diags;
79 private Log log;
80 private Lower lower;
81 private Names names;
82 private Symtab syms;
83 private Resolve rs;
84 private TreeMaker make;
85 private Types types;
86 private TransTypes transTypes;
87 private Env<AttrContext> attrEnv;
89 /** the analyzer scanner */
90 private LambdaAnalyzerPreprocessor analyzer;
92 /** map from lambda trees to translation contexts */
93 private Map<JCTree, TranslationContext<?>> contextMap;
95 /** current translation context (visitor argument) */
96 private TranslationContext<?> context;
98 /** info about the current class being processed */
99 private KlassInfo kInfo;
101 /** dump statistics about lambda code generation */
102 private boolean dumpLambdaToMethodStats;
104 /** force serializable representation, for stress testing **/
105 private final boolean forceSerializable;
107 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
108 public static final int FLAG_SERIALIZABLE = 1 << 0;
110 /** Flag for alternate metafactories indicating the lambda object has multiple targets */
111 public static final int FLAG_MARKERS = 1 << 1;
113 /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
114 public static final int FLAG_BRIDGES = 1 << 2;
116 // <editor-fold defaultstate="collapsed" desc="Instantiating">
117 protected static final Context.Key<LambdaToMethod> unlambdaKey =
118 new Context.Key<LambdaToMethod>();
120 public static LambdaToMethod instance(Context context) {
121 LambdaToMethod instance = context.get(unlambdaKey);
122 if (instance == null) {
123 instance = new LambdaToMethod(context);
124 }
125 return instance;
126 }
127 private LambdaToMethod(Context context) {
128 context.put(unlambdaKey, this);
129 diags = JCDiagnostic.Factory.instance(context);
130 log = Log.instance(context);
131 lower = Lower.instance(context);
132 names = Names.instance(context);
133 syms = Symtab.instance(context);
134 rs = Resolve.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>
146 private class KlassInfo {
148 /**
149 * list of methods to append
150 */
151 private ListBuffer<JCTree> appendedMethodList;
153 /**
154 * list of deserialization cases
155 */
156 private final Map<String, ListBuffer<JCStatement>> deserializeCases;
158 /**
159 * deserialize method symbol
160 */
161 private final MethodSymbol deserMethodSym;
163 /**
164 * deserialize method parameter symbol
165 */
166 private final VarSymbol deserParamSym;
168 private final JCClassDecl clazz;
170 private KlassInfo(JCClassDecl clazz) {
171 this.clazz = clazz;
172 appendedMethodList = new ListBuffer<>();
173 deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
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 }
181 private void addMethod(JCTree decl) {
182 appendedMethodList = appendedMethodList.prepend(decl);
183 }
184 }
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 }
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 }
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 }
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<JCTree, TranslationContext<?>>();
217 return translate(cdef);
218 }
219 // </editor-fold>
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 }
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;
271 {
272 Symbol owner = localContext.owner;
273 ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
274 ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
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 }
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;
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));
310 //Add the method to the list of methods to be added to this class.
311 kInfo.addMethod(lambdaDecl);
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
324 ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
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 }
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 }
342 //then, determine the arguments to the indy call
343 List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
345 //build a sam instance using an indy call to the meta-factory
346 int refKind = referenceKind(sym);
348 //convert to an invokedynamic call
349 result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
350 }
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 }
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;
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;
375 //the qualifying expression is treated as a special captured arg
376 JCExpression init;
377 switch(tree.kind) {
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;
386 case BOUND: /** Expr :: instMethod */
387 init = tree.getQualifierExpression();
388 init = attr.makeNullCheck(init);
389 break;
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;
398 default:
399 throw new InternalError("Should not have an invalid kind");
400 }
402 List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
405 //build a sam instance using an indy call to the meta-factory
406 result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
407 }
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);
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 }
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 Scope 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 }
464 // </editor-fold>
466 // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
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 }
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 }
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);
509 class LambdaBodyTranslator extends TreeTranslator {
511 @Override
512 public void visitClassDef(JCClassDecl tree) {
513 //do NOT recurse on any inner classes
514 result = tree;
515 }
517 @Override
518 public void visitLambda(JCLambda tree) {
519 //do NOT recurse on any nested lambdas
520 result = tree;
521 }
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 }
541 }
542 }
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 }
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 }
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 }
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 }
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));
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 }
657 private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
658 JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
659 testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
660 testExpr.setType(syms.booleanType);
661 return testExpr;
662 }
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 = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
674 compound.setType(syms.booleanType);
675 return compound;
676 }
678 private JCExpression deserGetter(String func, Type type) {
679 return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
680 }
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 }
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 }
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 }
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 }
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 }
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 == Kinds.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 }
741 // </editor-fold>
743 /**
744 * Converts a method reference which cannot be used directly into a lambda
745 */
746 private class MemberReferenceToLambda {
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<>();
754 private JCExpression receiverExpression = null;
756 MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) {
757 this.tree = tree;
758 this.localContext = localContext;
759 this.owner = owner;
760 }
762 JCLambda lambda() {
763 int prevPos = make.pos;
764 try {
765 make.at(tree);
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();
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 }
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();
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;
819 // Failsafe -- assure match-up
820 boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size();
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);
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 }
853 return rcvr;
854 }
856 JCExpression getReceiverExpression() {
857 return receiverExpression;
858 }
860 private JCExpression makeReceiver(VarSymbol rcvr) {
861 if (rcvr == null) return null;
862 JCExpression rcvrExpr = make.Ident(rcvr);
863 Type rcvrType = tree.ownerAccessible ? tree.sym.enclClass().type : tree.expr.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 }
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();
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);
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());
894 apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
895 setVarargsIfNeeded(apply, tree.varargsElement);
896 return apply;
897 }
899 /**
900 * Lambda body to use for a 'new'.
901 */
902 private JCExpression expressionNew() {
903 if (tree.kind == ReferenceKind.ARRAY_CTOR) {
904 //create the array creation expression
905 JCNewArray newArr = make.NewArray(
906 make.Type(types.elemtype(tree.getQualifierExpression().type)),
907 List.of(make.Ident(params.first())),
908 null);
909 newArr.type = tree.getQualifierExpression().type;
910 return newArr;
911 } else {
912 //create the instance creation expression
913 //note that method reference syntax does not allow an explicit
914 //enclosing class (so the enclosing class is null)
915 JCNewClass newClass = make.NewClass(null,
916 List.<JCExpression>nil(),
917 make.Type(tree.getQualifierExpression().type),
918 convertArgs(tree.sym, args.toList(), tree.varargsElement),
919 null);
920 newClass.constructor = tree.sym;
921 newClass.constructorType = tree.sym.erasure(types);
922 newClass.type = tree.getQualifierExpression().type;
923 setVarargsIfNeeded(newClass, tree.varargsElement);
924 return newClass;
925 }
926 }
928 private VarSymbol addParameter(String name, Type p, boolean genArg) {
929 VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
930 vsym.pos = tree.pos;
931 params.append(make.VarDef(vsym, null));
932 if (genArg) {
933 args.append(make.Ident(vsym));
934 }
935 return vsym;
936 }
937 }
939 private MethodType typeToMethodType(Type mt) {
940 Type type = types.erasure(mt);
941 return new MethodType(type.getParameterTypes(),
942 type.getReturnType(),
943 type.getThrownTypes(),
944 syms.methodClass);
945 }
947 /**
948 * Generate an indy method call to the meta factory
949 */
950 private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
951 int refKind, Symbol refSym, List<JCExpression> indy_args) {
952 JCFunctionalExpression tree = context.tree;
953 //determine the static bsm args
954 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
955 List<Object> staticArgs = List.<Object>of(
956 typeToMethodType(samSym.type),
957 new Pool.MethodHandle(refKind, refSym, types),
958 typeToMethodType(tree.getDescriptorType(types)));
960 //computed indy arg types
961 ListBuffer<Type> indy_args_types = new ListBuffer<>();
962 for (JCExpression arg : indy_args) {
963 indy_args_types.append(arg.type);
964 }
966 //finally, compute the type of the indy call
967 MethodType indyType = new MethodType(indy_args_types.toList(),
968 tree.type,
969 List.<Type>nil(),
970 syms.methodClass);
972 Name metafactoryName = context.needsAltMetafactory() ?
973 names.altMetafactory : names.metafactory;
975 if (context.needsAltMetafactory()) {
976 ListBuffer<Object> markers = new ListBuffer<>();
977 for (Type t : tree.targets.tail) {
978 if (t.tsym != syms.serializableType.tsym) {
979 markers.append(t.tsym);
980 }
981 }
982 int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
983 boolean hasMarkers = markers.nonEmpty();
984 boolean hasBridges = context.bridges.nonEmpty();
985 if (hasMarkers) {
986 flags |= FLAG_MARKERS;
987 }
988 if (hasBridges) {
989 flags |= FLAG_BRIDGES;
990 }
991 staticArgs = staticArgs.append(flags);
992 if (hasMarkers) {
993 staticArgs = staticArgs.append(markers.length());
994 staticArgs = staticArgs.appendList(markers.toList());
995 }
996 if (hasBridges) {
997 staticArgs = staticArgs.append(context.bridges.length() - 1);
998 for (Symbol s : context.bridges) {
999 Type s_erasure = s.erasure(types);
1000 if (!types.isSameType(s_erasure, samSym.erasure(types))) {
1001 staticArgs = staticArgs.append(s.erasure(types));
1002 }
1003 }
1004 }
1005 if (context.isSerializable()) {
1006 int prevPos = make.pos;
1007 try {
1008 make.at(kInfo.clazz);
1009 addDeserializationCase(refKind, refSym, tree.type, samSym,
1010 tree, staticArgs, indyType);
1011 } finally {
1012 make.at(prevPos);
1013 }
1014 }
1015 }
1017 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
1018 }
1020 /**
1021 * Generate an indy method call with given name, type and static bootstrap
1022 * arguments types
1023 */
1024 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
1025 List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
1026 Name methName) {
1027 int prevPos = make.pos;
1028 try {
1029 make.at(pos);
1030 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
1031 syms.stringType,
1032 syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
1034 Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
1035 bsmName, bsm_staticArgs, List.<Type>nil());
1037 DynamicMethodSymbol dynSym =
1038 new DynamicMethodSymbol(methName,
1039 syms.noSymbol,
1040 bsm.isStatic() ?
1041 ClassFile.REF_invokeStatic :
1042 ClassFile.REF_invokeVirtual,
1043 (MethodSymbol)bsm,
1044 indyType,
1045 staticArgs.toArray());
1047 JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
1048 qualifier.sym = dynSym;
1049 qualifier.type = indyType.getReturnType();
1051 JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
1052 proxyCall.type = indyType.getReturnType();
1053 return proxyCall;
1054 } finally {
1055 make.at(prevPos);
1056 }
1057 }
1058 //where
1059 private List<Type> bsmStaticArgToTypes(List<Object> args) {
1060 ListBuffer<Type> argtypes = new ListBuffer<>();
1061 for (Object arg : args) {
1062 argtypes.append(bsmStaticArgToType(arg));
1063 }
1064 return argtypes.toList();
1065 }
1067 private Type bsmStaticArgToType(Object arg) {
1068 Assert.checkNonNull(arg);
1069 if (arg instanceof ClassSymbol) {
1070 return syms.classType;
1071 } else if (arg instanceof Integer) {
1072 return syms.intType;
1073 } else if (arg instanceof Long) {
1074 return syms.longType;
1075 } else if (arg instanceof Float) {
1076 return syms.floatType;
1077 } else if (arg instanceof Double) {
1078 return syms.doubleType;
1079 } else if (arg instanceof String) {
1080 return syms.stringType;
1081 } else if (arg instanceof Pool.MethodHandle) {
1082 return syms.methodHandleType;
1083 } else if (arg instanceof MethodType) {
1084 return syms.methodTypeType;
1085 } else {
1086 Assert.error("bad static arg " + arg.getClass());
1087 return null;
1088 }
1089 }
1091 /**
1092 * Get the opcode associated with this method reference
1093 */
1094 private int referenceKind(Symbol refSym) {
1095 if (refSym.isConstructor()) {
1096 return ClassFile.REF_newInvokeSpecial;
1097 } else {
1098 if (refSym.isStatic()) {
1099 return ClassFile.REF_invokeStatic;
1100 } else if ((refSym.flags() & PRIVATE) != 0) {
1101 return ClassFile.REF_invokeSpecial;
1102 } else if (refSym.enclClass().isInterface()) {
1103 return ClassFile.REF_invokeInterface;
1104 } else {
1105 return ClassFile.REF_invokeVirtual;
1106 }
1107 }
1108 }
1110 // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1111 /**
1112 * This visitor collects information about translation of a lambda expression.
1113 * More specifically, it keeps track of the enclosing contexts and captured locals
1114 * accessed by the lambda being translated (as well as other useful info).
1115 * It also translates away problems for LambdaToMethod.
1116 */
1117 class LambdaAnalyzerPreprocessor extends TreeTranslator {
1119 /** the frame stack - used to reconstruct translation info about enclosing scopes */
1120 private List<Frame> frameStack;
1122 /**
1123 * keep the count of lambda expression (used to generate unambiguous
1124 * names)
1125 */
1126 private int lambdaCount = 0;
1128 /**
1129 * keep the count of lambda expression defined in given context (used to
1130 * generate unambiguous names for serializable lambdas)
1131 */
1132 private class SyntheticMethodNameCounter {
1133 private Map<String, Integer> map = new HashMap<>();
1134 int getIndex(StringBuilder buf) {
1135 String temp = buf.toString();
1136 Integer count = map.get(temp);
1137 if (count == null) {
1138 count = 0;
1139 }
1140 ++count;
1141 map.put(temp, count);
1142 return count;
1143 }
1144 }
1145 private SyntheticMethodNameCounter syntheticMethodNameCounts =
1146 new SyntheticMethodNameCounter();
1148 private Map<Symbol, JCClassDecl> localClassDefs;
1150 /**
1151 * maps for fake clinit symbols to be used as owners of lambda occurring in
1152 * a static var init context
1153 */
1154 private Map<ClassSymbol, Symbol> clinits =
1155 new HashMap<ClassSymbol, Symbol>();
1157 private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
1158 frameStack = List.nil();
1159 localClassDefs = new HashMap<Symbol, JCClassDecl>();
1160 return translate(tree);
1161 }
1163 @Override
1164 public void visitBlock(JCBlock tree) {
1165 List<Frame> prevStack = frameStack;
1166 try {
1167 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
1168 frameStack = frameStack.prepend(new Frame(tree));
1169 }
1170 super.visitBlock(tree);
1171 }
1172 finally {
1173 frameStack = prevStack;
1174 }
1175 }
1177 @Override
1178 public void visitClassDef(JCClassDecl tree) {
1179 List<Frame> prevStack = frameStack;
1180 int prevLambdaCount = lambdaCount;
1181 SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
1182 syntheticMethodNameCounts;
1183 Map<ClassSymbol, Symbol> prevClinits = clinits;
1184 DiagnosticSource prevSource = log.currentSource();
1185 try {
1186 log.useSource(tree.sym.sourcefile);
1187 lambdaCount = 0;
1188 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
1189 prevClinits = new HashMap<ClassSymbol, Symbol>();
1190 if (tree.sym.owner.kind == MTH) {
1191 localClassDefs.put(tree.sym, tree);
1192 }
1193 if (directlyEnclosingLambda() != null) {
1194 tree.sym.owner = owner();
1195 if (tree.sym.hasOuterInstance()) {
1196 //if a class is defined within a lambda, the lambda must capture
1197 //its enclosing instance (if any)
1198 TranslationContext<?> localContext = context();
1199 while (localContext != null) {
1200 if (localContext.tree.getTag() == LAMBDA) {
1201 ((LambdaTranslationContext)localContext)
1202 .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
1203 }
1204 localContext = localContext.prev;
1205 }
1206 }
1207 }
1208 frameStack = frameStack.prepend(new Frame(tree));
1209 super.visitClassDef(tree);
1210 }
1211 finally {
1212 log.useSource(prevSource.getFile());
1213 frameStack = prevStack;
1214 lambdaCount = prevLambdaCount;
1215 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
1216 clinits = prevClinits;
1217 }
1218 }
1220 @Override
1221 public void visitIdent(JCIdent tree) {
1222 if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
1223 if (tree.sym.kind == VAR &&
1224 tree.sym.owner.kind == MTH &&
1225 tree.type.constValue() == null) {
1226 TranslationContext<?> localContext = context();
1227 while (localContext != null) {
1228 if (localContext.tree.getTag() == LAMBDA) {
1229 JCTree block = capturedDecl(localContext.depth, tree.sym);
1230 if (block == null) break;
1231 ((LambdaTranslationContext)localContext)
1232 .addSymbol(tree.sym, CAPTURED_VAR);
1233 }
1234 localContext = localContext.prev;
1235 }
1236 } else if (tree.sym.owner.kind == TYP) {
1237 TranslationContext<?> localContext = context();
1238 while (localContext != null) {
1239 if (localContext.tree.hasTag(LAMBDA)) {
1240 JCTree block = capturedDecl(localContext.depth, tree.sym);
1241 if (block == null) break;
1242 switch (block.getTag()) {
1243 case CLASSDEF:
1244 JCClassDecl cdecl = (JCClassDecl)block;
1245 ((LambdaTranslationContext)localContext)
1246 .addSymbol(cdecl.sym, CAPTURED_THIS);
1247 break;
1248 default:
1249 Assert.error("bad block kind");
1250 }
1251 }
1252 localContext = localContext.prev;
1253 }
1254 }
1255 }
1256 super.visitIdent(tree);
1257 }
1259 @Override
1260 public void visitLambda(JCLambda tree) {
1261 analyzeLambda(tree, "lambda.stat");
1262 }
1264 private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) {
1265 // Translation of the receiver expression must occur first
1266 JCExpression rcvr = translate(methodReferenceReceiver);
1267 LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1");
1268 if (rcvr != null) {
1269 context.methodReferenceReceiver = rcvr;
1270 }
1271 }
1273 private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) {
1274 List<Frame> prevStack = frameStack;
1275 try {
1276 LambdaTranslationContext context = new LambdaTranslationContext(tree);
1277 if (dumpLambdaToMethodStats) {
1278 log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym);
1279 }
1280 frameStack = frameStack.prepend(new Frame(tree));
1281 for (JCVariableDecl param : tree.params) {
1282 context.addSymbol(param.sym, PARAM);
1283 frameStack.head.addLocal(param.sym);
1284 }
1285 contextMap.put(tree, context);
1286 super.visitLambda(tree);
1287 context.complete();
1288 return context;
1289 }
1290 finally {
1291 frameStack = prevStack;
1292 }
1293 }
1295 @Override
1296 public void visitMethodDef(JCMethodDecl tree) {
1297 List<Frame> prevStack = frameStack;
1298 try {
1299 frameStack = frameStack.prepend(new Frame(tree));
1300 super.visitMethodDef(tree);
1301 }
1302 finally {
1303 frameStack = prevStack;
1304 }
1305 }
1307 @Override
1308 public void visitNewClass(JCNewClass tree) {
1309 TypeSymbol def = tree.type.tsym;
1310 boolean inReferencedClass = currentlyInClass(def);
1311 boolean isLocal = def.isLocal();
1312 if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
1313 TranslationContext<?> localContext = context();
1314 while (localContext != null) {
1315 if (localContext.tree.getTag() == LAMBDA) {
1316 ((LambdaTranslationContext)localContext)
1317 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
1318 }
1319 localContext = localContext.prev;
1320 }
1321 }
1322 if (context() != null && !inReferencedClass && isLocal) {
1323 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
1324 captureLocalClassDefs(def, lambdaContext);
1325 }
1326 super.visitNewClass(tree);
1327 }
1328 //where
1329 void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
1330 JCClassDecl localCDef = localClassDefs.get(csym);
1331 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
1332 BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
1333 @Override
1334 void addFreeVars(ClassSymbol c) {
1335 captureLocalClassDefs(c, lambdaContext);
1336 }
1337 @Override
1338 void visitSymbol(Symbol sym) {
1339 if (sym.kind == VAR &&
1340 sym.owner.kind == MTH &&
1341 ((VarSymbol)sym).getConstValue() == null) {
1342 TranslationContext<?> localContext = context();
1343 while (localContext != null) {
1344 if (localContext.tree.getTag() == LAMBDA) {
1345 JCTree block = capturedDecl(localContext.depth, sym);
1346 if (block == null) break;
1347 ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
1348 }
1349 localContext = localContext.prev;
1350 }
1351 }
1352 }
1353 };
1354 fvc.scan(localCDef);
1355 }
1356 }
1357 //where
1358 boolean currentlyInClass(Symbol csym) {
1359 for (Frame frame : frameStack) {
1360 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
1361 JCClassDecl cdef = (JCClassDecl) frame.tree;
1362 if (cdef.sym == csym) {
1363 return true;
1364 }
1365 }
1366 }
1367 return false;
1368 }
1370 /**
1371 * Method references to local class constructors, may, if the local
1372 * class references local variables, have implicit constructor
1373 * parameters added in Lower; As a result, the invokedynamic bootstrap
1374 * information added in the LambdaToMethod pass will have the wrong
1375 * signature. Hooks between Lower and LambdaToMethod have been added to
1376 * handle normal "new" in this case. This visitor converts potentially
1377 * affected method references into a lambda containing a normal
1378 * expression.
1379 *
1380 * @param tree
1381 */
1382 @Override
1383 public void visitReference(JCMemberReference tree) {
1384 ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree);
1385 contextMap.put(tree, rcontext);
1386 if (rcontext.needsConversionToLambda()) {
1387 // Convert to a lambda, and process as such
1388 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner());
1389 analyzeLambda(conv.lambda(), conv.getReceiverExpression());
1390 } else {
1391 super.visitReference(tree);
1392 if (dumpLambdaToMethodStats) {
1393 log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null);
1394 }
1395 }
1396 }
1398 @Override
1399 public void visitSelect(JCFieldAccess tree) {
1400 if (context() != null && tree.sym.kind == VAR &&
1401 (tree.sym.name == names._this ||
1402 tree.sym.name == names._super)) {
1403 // A select of this or super means, if we are in a lambda,
1404 // we much have an instance context
1405 TranslationContext<?> localContext = context();
1406 while (localContext != null) {
1407 if (localContext.tree.hasTag(LAMBDA)) {
1408 JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
1409 if (clazz == null) break;
1410 ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
1411 }
1412 localContext = localContext.prev;
1413 }
1414 }
1415 super.visitSelect(tree);
1416 }
1418 @Override
1419 public void visitVarDef(JCVariableDecl tree) {
1420 TranslationContext<?> context = context();
1421 LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
1422 (LambdaTranslationContext)context :
1423 null;
1424 if (ltc != null) {
1425 if (frameStack.head.tree.hasTag(LAMBDA)) {
1426 ltc.addSymbol(tree.sym, LOCAL_VAR);
1427 }
1428 // Check for type variables (including as type arguments).
1429 // If they occur within class nested in a lambda, mark for erasure
1430 Type type = tree.sym.asType();
1431 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
1432 ltc.addSymbol(tree.sym, TYPE_VAR);
1433 }
1434 }
1436 List<Frame> prevStack = frameStack;
1437 try {
1438 if (tree.sym.owner.kind == MTH) {
1439 frameStack.head.addLocal(tree.sym);
1440 }
1441 frameStack = frameStack.prepend(new Frame(tree));
1442 super.visitVarDef(tree);
1443 }
1444 finally {
1445 frameStack = prevStack;
1446 }
1447 }
1449 /**
1450 * Return a valid owner given the current declaration stack
1451 * (required to skip synthetic lambda symbols)
1452 */
1453 private Symbol owner() {
1454 return owner(false);
1455 }
1457 @SuppressWarnings("fallthrough")
1458 private Symbol owner(boolean skipLambda) {
1459 List<Frame> frameStack2 = frameStack;
1460 while (frameStack2.nonEmpty()) {
1461 switch (frameStack2.head.tree.getTag()) {
1462 case VARDEF:
1463 if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
1464 frameStack2 = frameStack2.tail;
1465 break;
1466 }
1467 JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
1468 return initSym(cdecl.sym,
1469 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
1470 case BLOCK:
1471 JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
1472 return initSym(cdecl2.sym,
1473 ((JCBlock)frameStack2.head.tree).flags & STATIC);
1474 case CLASSDEF:
1475 return ((JCClassDecl)frameStack2.head.tree).sym;
1476 case METHODDEF:
1477 return ((JCMethodDecl)frameStack2.head.tree).sym;
1478 case LAMBDA:
1479 if (!skipLambda)
1480 return ((LambdaTranslationContext)contextMap
1481 .get(frameStack2.head.tree)).translatedSym;
1482 default:
1483 frameStack2 = frameStack2.tail;
1484 }
1485 }
1486 Assert.error();
1487 return null;
1488 }
1490 private Symbol initSym(ClassSymbol csym, long flags) {
1491 boolean isStatic = (flags & STATIC) != 0;
1492 if (isStatic) {
1493 /* static clinits are generated in Gen, so we need to use a fake
1494 * one. Attr creates a fake clinit method while attributing
1495 * lambda expressions used as initializers of static fields, so
1496 * let's use that one.
1497 */
1498 MethodSymbol clinit = attr.removeClinit(csym);
1499 if (clinit != null) {
1500 clinits.put(csym, clinit);
1501 return clinit;
1502 }
1504 /* if no clinit is found at Attr, then let's try at clinits.
1505 */
1506 clinit = (MethodSymbol)clinits.get(csym);
1507 if (clinit == null) {
1508 /* no luck, let's create a new one
1509 */
1510 clinit = makePrivateSyntheticMethod(STATIC,
1511 names.clinit,
1512 new MethodType(List.<Type>nil(), syms.voidType,
1513 List.<Type>nil(), syms.methodClass),
1514 csym);
1515 clinits.put(csym, clinit);
1516 }
1517 return clinit;
1518 } else {
1519 //get the first constructor and treat it as the instance init sym
1520 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
1521 return s;
1522 }
1523 }
1524 Assert.error("init not found");
1525 return null;
1526 }
1528 private JCTree directlyEnclosingLambda() {
1529 if (frameStack.isEmpty()) {
1530 return null;
1531 }
1532 List<Frame> frameStack2 = frameStack;
1533 while (frameStack2.nonEmpty()) {
1534 switch (frameStack2.head.tree.getTag()) {
1535 case CLASSDEF:
1536 case METHODDEF:
1537 return null;
1538 case LAMBDA:
1539 return frameStack2.head.tree;
1540 default:
1541 frameStack2 = frameStack2.tail;
1542 }
1543 }
1544 Assert.error();
1545 return null;
1546 }
1548 private boolean inClassWithinLambda() {
1549 if (frameStack.isEmpty()) {
1550 return false;
1551 }
1552 List<Frame> frameStack2 = frameStack;
1553 boolean classFound = false;
1554 while (frameStack2.nonEmpty()) {
1555 switch (frameStack2.head.tree.getTag()) {
1556 case LAMBDA:
1557 return classFound;
1558 case CLASSDEF:
1559 classFound = true;
1560 frameStack2 = frameStack2.tail;
1561 break;
1562 default:
1563 frameStack2 = frameStack2.tail;
1564 }
1565 }
1566 // No lambda
1567 return false;
1568 }
1570 /**
1571 * Return the declaration corresponding to a symbol in the enclosing
1572 * scope; the depth parameter is used to filter out symbols defined
1573 * in nested scopes (which do not need to undergo capture).
1574 */
1575 private JCTree capturedDecl(int depth, Symbol sym) {
1576 int currentDepth = frameStack.size() - 1;
1577 for (Frame block : frameStack) {
1578 switch (block.tree.getTag()) {
1579 case CLASSDEF:
1580 ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
1581 if (sym.isMemberOf(clazz, types)) {
1582 return currentDepth > depth ? null : block.tree;
1583 }
1584 break;
1585 case VARDEF:
1586 if (((JCVariableDecl)block.tree).sym == sym &&
1587 sym.owner.kind == MTH) { //only locals are captured
1588 return currentDepth > depth ? null : block.tree;
1589 }
1590 break;
1591 case BLOCK:
1592 case METHODDEF:
1593 case LAMBDA:
1594 if (block.locals != null && block.locals.contains(sym)) {
1595 return currentDepth > depth ? null : block.tree;
1596 }
1597 break;
1598 default:
1599 Assert.error("bad decl kind " + block.tree.getTag());
1600 }
1601 currentDepth--;
1602 }
1603 return null;
1604 }
1606 private TranslationContext<?> context() {
1607 for (Frame frame : frameStack) {
1608 TranslationContext<?> context = contextMap.get(frame.tree);
1609 if (context != null) {
1610 return context;
1611 }
1612 }
1613 return null;
1614 }
1616 /**
1617 * This is used to filter out those identifiers that needs to be adjusted
1618 * when translating away lambda expressions
1619 */
1620 private boolean lambdaIdentSymbolFilter(Symbol sym) {
1621 return (sym.kind == VAR || sym.kind == MTH)
1622 && !sym.isStatic()
1623 && sym.name != names.init;
1624 }
1626 /**
1627 * This is used to filter out those new class expressions that need to
1628 * be qualified with an enclosing tree
1629 */
1630 private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
1631 if (context != null
1632 && tree.encl == null
1633 && tree.def == null
1634 && !tree.type.getEnclosingType().hasTag(NONE)) {
1635 Type encl = tree.type.getEnclosingType();
1636 Type current = context.owner.enclClass().type;
1637 while (!current.hasTag(NONE)) {
1638 if (current.tsym.isSubClass(encl.tsym, types)) {
1639 return true;
1640 }
1641 current = current.getEnclosingType();
1642 }
1643 return false;
1644 } else {
1645 return false;
1646 }
1647 }
1649 private class Frame {
1650 final JCTree tree;
1651 List<Symbol> locals;
1653 public Frame(JCTree tree) {
1654 this.tree = tree;
1655 }
1657 void addLocal(Symbol sym) {
1658 if (locals == null) {
1659 locals = List.nil();
1660 }
1661 locals = locals.prepend(sym);
1662 }
1663 }
1665 /**
1666 * This class is used to store important information regarding translation of
1667 * lambda expression/method references (see subclasses).
1668 */
1669 private abstract class TranslationContext<T extends JCFunctionalExpression> {
1671 /** the underlying (untranslated) tree */
1672 final T tree;
1674 /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
1675 final Symbol owner;
1677 /** the depth of this lambda expression in the frame stack */
1678 final int depth;
1680 /** the enclosing translation context (set for nested lambdas/mref) */
1681 final TranslationContext<?> prev;
1683 /** list of methods to be bridged by the meta-factory */
1684 final List<Symbol> bridges;
1686 TranslationContext(T tree) {
1687 this.tree = tree;
1688 this.owner = owner();
1689 this.depth = frameStack.size() - 1;
1690 this.prev = context();
1691 ClassSymbol csym =
1692 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
1693 this.bridges = types.functionalInterfaceBridges(csym);
1694 }
1696 /** does this functional expression need to be created using alternate metafactory? */
1697 boolean needsAltMetafactory() {
1698 return tree.targets.length() > 1 ||
1699 isSerializable() ||
1700 bridges.length() > 1;
1701 }
1703 /** does this functional expression require serialization support? */
1704 boolean isSerializable() {
1705 if (forceSerializable) {
1706 return true;
1707 }
1708 for (Type target : tree.targets) {
1709 if (types.asSuper(target, syms.serializableType.tsym) != null) {
1710 return true;
1711 }
1712 }
1713 return false;
1714 }
1716 /**
1717 * @return Name of the enclosing method to be folded into synthetic
1718 * method name
1719 */
1720 String enclosingMethodName() {
1721 return syntheticMethodNameComponent(owner.name);
1722 }
1724 /**
1725 * @return Method name in a form that can be folded into a
1726 * component of a synthetic method name
1727 */
1728 String syntheticMethodNameComponent(Name name) {
1729 if (name == null) {
1730 return "null";
1731 }
1732 String methodName = name.toString();
1733 if (methodName.equals("<clinit>")) {
1734 methodName = "static";
1735 } else if (methodName.equals("<init>")) {
1736 methodName = "new";
1737 }
1738 return methodName;
1739 }
1740 }
1742 /**
1743 * This class retains all the useful information about a lambda expression;
1744 * the contents of this class are filled by the LambdaAnalyzer visitor,
1745 * and the used by the main translation routines in order to adjust references
1746 * to captured locals/members, etc.
1747 */
1748 private class LambdaTranslationContext extends TranslationContext<JCLambda> {
1750 /** variable in the enclosing context to which this lambda is assigned */
1751 final Symbol self;
1753 /** variable in the enclosing context to which this lambda is assigned */
1754 final Symbol assignedTo;
1756 Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
1758 /** the synthetic symbol for the method hoisting the translated lambda */
1759 MethodSymbol translatedSym;
1761 List<JCVariableDecl> syntheticParams;
1763 /**
1764 * to prevent recursion, track local classes processed
1765 */
1766 final Set<Symbol> freeVarProcessedLocalClasses;
1768 /**
1769 * For method references converted to lambdas. The method
1770 * reference receiver expression. Must be treated like a captured
1771 * variable.
1772 */
1773 JCExpression methodReferenceReceiver;
1775 LambdaTranslationContext(JCLambda tree) {
1776 super(tree);
1777 Frame frame = frameStack.head;
1778 switch (frame.tree.getTag()) {
1779 case VARDEF:
1780 assignedTo = self = ((JCVariableDecl) frame.tree).sym;
1781 break;
1782 case ASSIGN:
1783 self = null;
1784 assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
1785 break;
1786 default:
1787 assignedTo = self = null;
1788 break;
1789 }
1791 // This symbol will be filled-in in complete
1792 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
1794 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
1796 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
1797 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
1798 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
1799 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
1800 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
1802 freeVarProcessedLocalClasses = new HashSet<>();
1803 }
1805 /**
1806 * For a serializable lambda, generate a disambiguating string
1807 * which maximizes stability across deserialization.
1808 *
1809 * @return String to differentiate synthetic lambda method names
1810 */
1811 private String serializedLambdaDisambiguation() {
1812 StringBuilder buf = new StringBuilder();
1813 // Append the enclosing method signature to differentiate
1814 // overloaded enclosing methods. For lambdas enclosed in
1815 // lambdas, the generated lambda method will not have type yet,
1816 // but the enclosing method's name will have been generated
1817 // with this same method, so it will be unique and never be
1818 // overloaded.
1819 Assert.check(
1820 owner.type != null ||
1821 directlyEnclosingLambda() != null);
1822 if (owner.type != null) {
1823 buf.append(typeSig(owner.type));
1824 buf.append(":");
1825 }
1827 // Add target type info
1828 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
1829 buf.append(" ");
1831 // Add variable assigned to
1832 if (assignedTo != null) {
1833 buf.append(assignedTo.flatName());
1834 buf.append("=");
1835 }
1836 //add captured locals info: type, name, order
1837 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
1838 if (fv != self) {
1839 buf.append(typeSig(fv.type));
1840 buf.append(" ");
1841 buf.append(fv.flatName());
1842 buf.append(",");
1843 }
1844 }
1846 return buf.toString();
1847 }
1849 /**
1850 * For a non-serializable lambda, generate a simple method.
1851 *
1852 * @return Name to use for the synthetic lambda method name
1853 */
1854 private Name lambdaName() {
1855 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
1856 }
1858 /**
1859 * For a serializable lambda, generate a method name which maximizes
1860 * name stability across deserialization.
1861 *
1862 * @return Name to use for the synthetic lambda method name
1863 */
1864 private Name serializedLambdaName() {
1865 StringBuilder buf = new StringBuilder();
1866 buf.append(names.lambda);
1867 // Append the name of the method enclosing the lambda.
1868 buf.append(enclosingMethodName());
1869 buf.append('$');
1870 // Append a hash of the disambiguating string : enclosing method
1871 // signature, etc.
1872 String disam = serializedLambdaDisambiguation();
1873 buf.append(Integer.toHexString(disam.hashCode()));
1874 buf.append('$');
1875 // The above appended name components may not be unique, append
1876 // a count based on the above name components.
1877 buf.append(syntheticMethodNameCounts.getIndex(buf));
1878 String result = buf.toString();
1879 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
1880 return names.fromString(result);
1881 }
1883 /**
1884 * Translate a symbol of a given kind into something suitable for the
1885 * synthetic lambda body
1886 */
1887 Symbol translate(final Symbol sym, LambdaSymbolKind skind) {
1888 Symbol ret;
1889 switch (skind) {
1890 case CAPTURED_THIS:
1891 ret = sym; // self represented
1892 break;
1893 case TYPE_VAR:
1894 // Just erase the type var
1895 ret = new VarSymbol(sym.flags(), sym.name,
1896 types.erasure(sym.type), sym.owner);
1898 /* this information should also be kept for LVT generation at Gen
1899 * a Symbol with pos < startPos won't be tracked.
1900 */
1901 ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
1902 break;
1903 case CAPTURED_VAR:
1904 ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
1905 @Override
1906 public Symbol baseSymbol() {
1907 //keep mapping with original captured symbol
1908 return sym;
1909 }
1910 };
1911 break;
1912 case LOCAL_VAR:
1913 ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
1914 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1915 break;
1916 case PARAM:
1917 ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym);
1918 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1919 break;
1920 default:
1921 Assert.error(skind.name());
1922 throw new AssertionError();
1923 }
1924 if (ret != sym) {
1925 ret.setDeclarationAttributes(sym.getRawAttributes());
1926 ret.setTypeAttributes(sym.getRawTypeAttributes());
1927 }
1928 return ret;
1929 }
1931 void addSymbol(Symbol sym, LambdaSymbolKind skind) {
1932 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
1933 if (!transMap.containsKey(sym)) {
1934 transMap.put(sym, translate(sym, skind));
1935 }
1936 }
1938 Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
1939 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
1940 Assert.checkNonNull(m);
1941 return m;
1942 }
1944 JCTree translate(JCIdent lambdaIdent) {
1945 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
1946 if (m.containsKey(lambdaIdent.sym)) {
1947 Symbol tSym = m.get(lambdaIdent.sym);
1948 JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
1949 tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
1950 return t;
1951 }
1952 }
1953 return null;
1954 }
1956 /**
1957 * The translatedSym is not complete/accurate until the analysis is
1958 * finished. Once the analysis is finished, the translatedSym is
1959 * "completed" -- updated with type information, access modifiers,
1960 * and full parameter list.
1961 */
1962 void complete() {
1963 if (syntheticParams != null) {
1964 return;
1965 }
1966 boolean inInterface = translatedSym.owner.isInterface();
1967 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
1969 // If instance access isn't needed, make it static.
1970 // Interface instance methods must be default methods.
1971 // Lambda methods are private synthetic.
1972 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
1973 // from the class.
1974 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
1975 owner.flags_field & STRICTFP |
1976 owner.owner.flags_field & STRICTFP |
1977 PRIVATE |
1978 (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
1980 //compute synthetic params
1981 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
1982 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>();
1984 // The signature of the method is augmented with the following
1985 // synthetic parameters:
1986 //
1987 // 1) reference to enclosing contexts captured by the lambda expression
1988 // 2) enclosing locals captured by the lambda expression
1989 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
1990 params.append(make.VarDef((VarSymbol) thisSym, null));
1991 parameterSymbols.append((VarSymbol) thisSym);
1992 }
1993 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
1994 params.append(make.VarDef((VarSymbol) thisSym, null));
1995 parameterSymbols.append((VarSymbol) thisSym);
1996 }
1997 syntheticParams = params.toList();
1999 translatedSym.params = parameterSymbols.toList();
2001 // Compute and set the lambda name
2002 translatedSym.name = isSerializable()
2003 ? serializedLambdaName()
2004 : lambdaName();
2006 //prepend synthetic args to translated lambda method signature
2007 translatedSym.type = types.createMethodTypeWithParameters(
2008 generatedLambdaSig(),
2009 TreeInfo.types(syntheticParams));
2010 }
2012 Type generatedLambdaSig() {
2013 return types.erasure(tree.getDescriptorType(types));
2014 }
2015 }
2017 /**
2018 * This class retains all the useful information about a method reference;
2019 * the contents of this class are filled by the LambdaAnalyzer visitor,
2020 * and the used by the main translation routines in order to adjust method
2021 * references (i.e. in case a bridge is needed)
2022 */
2023 private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
2025 final boolean isSuper;
2026 final Symbol sigPolySym;
2028 ReferenceTranslationContext(JCMemberReference tree) {
2029 super(tree);
2030 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
2031 this.sigPolySym = isSignaturePolymorphic()
2032 ? makePrivateSyntheticMethod(tree.sym.flags(),
2033 tree.sym.name,
2034 bridgedRefSig(),
2035 tree.sym.enclClass())
2036 : null;
2037 }
2039 /**
2040 * Get the opcode associated with this method reference
2041 */
2042 int referenceKind() {
2043 return LambdaToMethod.this.referenceKind(tree.sym);
2044 }
2046 boolean needsVarArgsConversion() {
2047 return tree.varargsElement != null;
2048 }
2050 /**
2051 * @return Is this an array operation like clone()
2052 */
2053 boolean isArrayOp() {
2054 return tree.sym.owner == syms.arrayClass;
2055 }
2057 boolean receiverAccessible() {
2058 //hack needed to workaround 292 bug (7087658)
2059 //when 292 issue is fixed we should remove this and change the backend
2060 //code to always generate a method handle to an accessible method
2061 return tree.ownerAccessible;
2062 }
2064 /**
2065 * The VM does not support access across nested classes (8010319).
2066 * Were that ever to change, this should be removed.
2067 */
2068 boolean isPrivateInOtherClass() {
2069 return (tree.sym.flags() & PRIVATE) != 0 &&
2070 !types.isSameType(
2071 types.erasure(tree.sym.enclClass().asType()),
2072 types.erasure(owner.enclClass().asType()));
2073 }
2075 /**
2076 * Signature polymorphic methods need special handling.
2077 * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
2078 */
2079 final boolean isSignaturePolymorphic() {
2080 return tree.sym.kind == MTH &&
2081 types.isSignaturePolymorphic((MethodSymbol)tree.sym);
2082 }
2084 /**
2085 * Erasure destroys the implementation parameter subtype
2086 * relationship for intersection types
2087 */
2088 boolean interfaceParameterIsIntersectionType() {
2089 List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
2090 if (tree.kind == ReferenceKind.UNBOUND) {
2091 tl = tl.tail;
2092 }
2093 for (; tl.nonEmpty(); tl = tl.tail) {
2094 Type pt = tl.head;
2095 if (pt.getKind() == TypeKind.TYPEVAR) {
2096 TypeVar tv = (TypeVar) pt;
2097 if (tv.bound.getKind() == TypeKind.INTERSECTION) {
2098 return true;
2099 }
2100 }
2101 }
2102 return false;
2103 }
2105 /**
2106 * Does this reference need to be converted to a lambda
2107 * (i.e. var args need to be expanded or "super" is used)
2108 */
2109 final boolean needsConversionToLambda() {
2110 return interfaceParameterIsIntersectionType() ||
2111 isSuper ||
2112 needsVarArgsConversion() ||
2113 isArrayOp() ||
2114 isPrivateInOtherClass() ||
2115 !receiverAccessible() ||
2116 (tree.getMode() == ReferenceMode.NEW &&
2117 tree.kind != ReferenceKind.ARRAY_CTOR &&
2118 (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
2119 }
2121 Type generatedRefSig() {
2122 return types.erasure(tree.sym.type);
2123 }
2125 Type bridgedRefSig() {
2126 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
2127 }
2128 }
2129 }
2130 // </editor-fold>
2132 /*
2133 * These keys provide mappings for various translated lambda symbols
2134 * and the prevailing order must be maintained.
2135 */
2136 enum LambdaSymbolKind {
2137 PARAM, // original to translated lambda parameters
2138 LOCAL_VAR, // original to translated lambda locals
2139 CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters
2140 CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access)
2141 TYPE_VAR; // original to translated lambda type variables
2142 }
2144 /**
2145 * ****************************************************************
2146 * Signature Generation
2147 * ****************************************************************
2148 */
2150 private String typeSig(Type type) {
2151 L2MSignatureGenerator sg = new L2MSignatureGenerator();
2152 sg.assembleSig(type);
2153 return sg.toString();
2154 }
2156 private String classSig(Type type) {
2157 L2MSignatureGenerator sg = new L2MSignatureGenerator();
2158 sg.assembleClassSig(type);
2159 return sg.toString();
2160 }
2162 /**
2163 * Signature Generation
2164 */
2165 private class L2MSignatureGenerator extends Types.SignatureGenerator {
2167 /**
2168 * An output buffer for type signatures.
2169 */
2170 StringBuilder sb = new StringBuilder();
2172 L2MSignatureGenerator() {
2173 super(types);
2174 }
2176 @Override
2177 protected void append(char ch) {
2178 sb.append(ch);
2179 }
2181 @Override
2182 protected void append(byte[] ba) {
2183 sb.append(new String(ba));
2184 }
2186 @Override
2187 protected void append(Name name) {
2188 sb.append(name.toString());
2189 }
2191 @Override
2192 public String toString() {
2193 return sb.toString();
2194 }
2195 }
2196 }