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