Wed, 02 Dec 2015 23:07:58 -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 }
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.sym.enclClass().type;
864 if (rcvrType == syms.arrayClass.type) {
865 // Map the receiver type to the actually type, not just "array"
866 rcvrType = tree.getQualifierExpression().type;
867 }
868 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
869 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
870 }
871 return rcvrExpr;
872 }
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 tree.sym.isStatic() ?
881 make.Type(tree.sym.owner.type) :
882 (rcvr != null) ?
883 makeReceiver(rcvr) :
884 tree.getQualifierExpression();
886 //create the qualifier expression
887 JCFieldAccess select = make.Select(qualifier, tree.sym.name);
888 select.sym = tree.sym;
889 select.type = tree.sym.erasure(types);
891 //create the method call expression
892 JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
893 convertArgs(tree.sym, args.toList(), tree.varargsElement)).
894 setType(tree.sym.erasure(types).getReturnType());
896 apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
897 setVarargsIfNeeded(apply, tree.varargsElement);
898 return apply;
899 }
901 /**
902 * Lambda body to use for a 'new'.
903 */
904 private JCExpression expressionNew() {
905 if (tree.kind == ReferenceKind.ARRAY_CTOR) {
906 //create the array creation expression
907 JCNewArray newArr = make.NewArray(
908 make.Type(types.elemtype(tree.getQualifierExpression().type)),
909 List.of(make.Ident(params.first())),
910 null);
911 newArr.type = tree.getQualifierExpression().type;
912 return newArr;
913 } else {
914 //create the instance creation expression
915 //note that method reference syntax does not allow an explicit
916 //enclosing class (so the enclosing class is null)
917 JCNewClass newClass = make.NewClass(null,
918 List.<JCExpression>nil(),
919 make.Type(tree.getQualifierExpression().type),
920 convertArgs(tree.sym, args.toList(), tree.varargsElement),
921 null);
922 newClass.constructor = tree.sym;
923 newClass.constructorType = tree.sym.erasure(types);
924 newClass.type = tree.getQualifierExpression().type;
925 setVarargsIfNeeded(newClass, tree.varargsElement);
926 return newClass;
927 }
928 }
930 private VarSymbol addParameter(String name, Type p, boolean genArg) {
931 VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
932 vsym.pos = tree.pos;
933 params.append(make.VarDef(vsym, null));
934 if (genArg) {
935 args.append(make.Ident(vsym));
936 }
937 return vsym;
938 }
939 }
941 private MethodType typeToMethodType(Type mt) {
942 Type type = types.erasure(mt);
943 return new MethodType(type.getParameterTypes(),
944 type.getReturnType(),
945 type.getThrownTypes(),
946 syms.methodClass);
947 }
949 /**
950 * Generate an indy method call to the meta factory
951 */
952 private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
953 int refKind, Symbol refSym, List<JCExpression> indy_args) {
954 JCFunctionalExpression tree = context.tree;
955 //determine the static bsm args
956 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
957 List<Object> staticArgs = List.<Object>of(
958 typeToMethodType(samSym.type),
959 new Pool.MethodHandle(refKind, refSym, types),
960 typeToMethodType(tree.getDescriptorType(types)));
962 //computed indy arg types
963 ListBuffer<Type> indy_args_types = new ListBuffer<>();
964 for (JCExpression arg : indy_args) {
965 indy_args_types.append(arg.type);
966 }
968 //finally, compute the type of the indy call
969 MethodType indyType = new MethodType(indy_args_types.toList(),
970 tree.type,
971 List.<Type>nil(),
972 syms.methodClass);
974 Name metafactoryName = context.needsAltMetafactory() ?
975 names.altMetafactory : names.metafactory;
977 if (context.needsAltMetafactory()) {
978 ListBuffer<Object> markers = new ListBuffer<>();
979 for (Type t : tree.targets.tail) {
980 if (t.tsym != syms.serializableType.tsym) {
981 markers.append(t.tsym);
982 }
983 }
984 int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
985 boolean hasMarkers = markers.nonEmpty();
986 boolean hasBridges = context.bridges.nonEmpty();
987 if (hasMarkers) {
988 flags |= FLAG_MARKERS;
989 }
990 if (hasBridges) {
991 flags |= FLAG_BRIDGES;
992 }
993 staticArgs = staticArgs.append(flags);
994 if (hasMarkers) {
995 staticArgs = staticArgs.append(markers.length());
996 staticArgs = staticArgs.appendList(markers.toList());
997 }
998 if (hasBridges) {
999 staticArgs = staticArgs.append(context.bridges.length() - 1);
1000 for (Symbol s : context.bridges) {
1001 Type s_erasure = s.erasure(types);
1002 if (!types.isSameType(s_erasure, samSym.erasure(types))) {
1003 staticArgs = staticArgs.append(s.erasure(types));
1004 }
1005 }
1006 }
1007 if (context.isSerializable()) {
1008 int prevPos = make.pos;
1009 try {
1010 make.at(kInfo.clazz);
1011 addDeserializationCase(refKind, refSym, tree.type, samSym,
1012 tree, staticArgs, indyType);
1013 } finally {
1014 make.at(prevPos);
1015 }
1016 }
1017 }
1019 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
1020 }
1022 /**
1023 * Generate an indy method call with given name, type and static bootstrap
1024 * arguments types
1025 */
1026 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
1027 List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
1028 Name methName) {
1029 int prevPos = make.pos;
1030 try {
1031 make.at(pos);
1032 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
1033 syms.stringType,
1034 syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
1036 Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
1037 bsmName, bsm_staticArgs, List.<Type>nil());
1039 DynamicMethodSymbol dynSym =
1040 new DynamicMethodSymbol(methName,
1041 syms.noSymbol,
1042 bsm.isStatic() ?
1043 ClassFile.REF_invokeStatic :
1044 ClassFile.REF_invokeVirtual,
1045 (MethodSymbol)bsm,
1046 indyType,
1047 staticArgs.toArray());
1049 JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
1050 qualifier.sym = dynSym;
1051 qualifier.type = indyType.getReturnType();
1053 JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
1054 proxyCall.type = indyType.getReturnType();
1055 return proxyCall;
1056 } finally {
1057 make.at(prevPos);
1058 }
1059 }
1060 //where
1061 private List<Type> bsmStaticArgToTypes(List<Object> args) {
1062 ListBuffer<Type> argtypes = new ListBuffer<>();
1063 for (Object arg : args) {
1064 argtypes.append(bsmStaticArgToType(arg));
1065 }
1066 return argtypes.toList();
1067 }
1069 private Type bsmStaticArgToType(Object arg) {
1070 Assert.checkNonNull(arg);
1071 if (arg instanceof ClassSymbol) {
1072 return syms.classType;
1073 } else if (arg instanceof Integer) {
1074 return syms.intType;
1075 } else if (arg instanceof Long) {
1076 return syms.longType;
1077 } else if (arg instanceof Float) {
1078 return syms.floatType;
1079 } else if (arg instanceof Double) {
1080 return syms.doubleType;
1081 } else if (arg instanceof String) {
1082 return syms.stringType;
1083 } else if (arg instanceof Pool.MethodHandle) {
1084 return syms.methodHandleType;
1085 } else if (arg instanceof MethodType) {
1086 return syms.methodTypeType;
1087 } else {
1088 Assert.error("bad static arg " + arg.getClass());
1089 return null;
1090 }
1091 }
1093 /**
1094 * Get the opcode associated with this method reference
1095 */
1096 private int referenceKind(Symbol refSym) {
1097 if (refSym.isConstructor()) {
1098 return ClassFile.REF_newInvokeSpecial;
1099 } else {
1100 if (refSym.isStatic()) {
1101 return ClassFile.REF_invokeStatic;
1102 } else if ((refSym.flags() & PRIVATE) != 0) {
1103 return ClassFile.REF_invokeSpecial;
1104 } else if (refSym.enclClass().isInterface()) {
1105 return ClassFile.REF_invokeInterface;
1106 } else {
1107 return ClassFile.REF_invokeVirtual;
1108 }
1109 }
1110 }
1112 // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1113 /**
1114 * This visitor collects information about translation of a lambda expression.
1115 * More specifically, it keeps track of the enclosing contexts and captured locals
1116 * accessed by the lambda being translated (as well as other useful info).
1117 * It also translates away problems for LambdaToMethod.
1118 */
1119 class LambdaAnalyzerPreprocessor extends TreeTranslator {
1121 /** the frame stack - used to reconstruct translation info about enclosing scopes */
1122 private List<Frame> frameStack;
1124 /**
1125 * keep the count of lambda expression (used to generate unambiguous
1126 * names)
1127 */
1128 private int lambdaCount = 0;
1130 /**
1131 * keep the count of lambda expression defined in given context (used to
1132 * generate unambiguous names for serializable lambdas)
1133 */
1134 private class SyntheticMethodNameCounter {
1135 private Map<String, Integer> map = new HashMap<>();
1136 int getIndex(StringBuilder buf) {
1137 String temp = buf.toString();
1138 Integer count = map.get(temp);
1139 if (count == null) {
1140 count = 0;
1141 }
1142 ++count;
1143 map.put(temp, count);
1144 return count;
1145 }
1146 }
1147 private SyntheticMethodNameCounter syntheticMethodNameCounts =
1148 new SyntheticMethodNameCounter();
1150 private Map<Symbol, JCClassDecl> localClassDefs;
1152 /**
1153 * maps for fake clinit symbols to be used as owners of lambda occurring in
1154 * a static var init context
1155 */
1156 private Map<ClassSymbol, Symbol> clinits =
1157 new HashMap<ClassSymbol, Symbol>();
1159 private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
1160 frameStack = List.nil();
1161 localClassDefs = new HashMap<Symbol, JCClassDecl>();
1162 return translate(tree);
1163 }
1165 @Override
1166 public void visitBlock(JCBlock tree) {
1167 List<Frame> prevStack = frameStack;
1168 try {
1169 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
1170 frameStack = frameStack.prepend(new Frame(tree));
1171 }
1172 super.visitBlock(tree);
1173 }
1174 finally {
1175 frameStack = prevStack;
1176 }
1177 }
1179 @Override
1180 public void visitClassDef(JCClassDecl tree) {
1181 List<Frame> prevStack = frameStack;
1182 int prevLambdaCount = lambdaCount;
1183 SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
1184 syntheticMethodNameCounts;
1185 Map<ClassSymbol, Symbol> prevClinits = clinits;
1186 DiagnosticSource prevSource = log.currentSource();
1187 try {
1188 log.useSource(tree.sym.sourcefile);
1189 lambdaCount = 0;
1190 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
1191 prevClinits = new HashMap<ClassSymbol, Symbol>();
1192 if (tree.sym.owner.kind == MTH) {
1193 localClassDefs.put(tree.sym, tree);
1194 }
1195 if (directlyEnclosingLambda() != null) {
1196 tree.sym.owner = owner();
1197 if (tree.sym.hasOuterInstance()) {
1198 //if a class is defined within a lambda, the lambda must capture
1199 //its enclosing instance (if any)
1200 TranslationContext<?> localContext = context();
1201 while (localContext != null) {
1202 if (localContext.tree.getTag() == LAMBDA) {
1203 ((LambdaTranslationContext)localContext)
1204 .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
1205 }
1206 localContext = localContext.prev;
1207 }
1208 }
1209 }
1210 frameStack = frameStack.prepend(new Frame(tree));
1211 super.visitClassDef(tree);
1212 }
1213 finally {
1214 log.useSource(prevSource.getFile());
1215 frameStack = prevStack;
1216 lambdaCount = prevLambdaCount;
1217 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
1218 clinits = prevClinits;
1219 }
1220 }
1222 @Override
1223 public void visitIdent(JCIdent tree) {
1224 if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
1225 if (tree.sym.kind == VAR &&
1226 tree.sym.owner.kind == MTH &&
1227 tree.type.constValue() == null) {
1228 TranslationContext<?> localContext = context();
1229 while (localContext != null) {
1230 if (localContext.tree.getTag() == LAMBDA) {
1231 JCTree block = capturedDecl(localContext.depth, tree.sym);
1232 if (block == null) break;
1233 ((LambdaTranslationContext)localContext)
1234 .addSymbol(tree.sym, CAPTURED_VAR);
1235 }
1236 localContext = localContext.prev;
1237 }
1238 } else if (tree.sym.owner.kind == TYP) {
1239 TranslationContext<?> localContext = context();
1240 while (localContext != null) {
1241 if (localContext.tree.hasTag(LAMBDA)) {
1242 JCTree block = capturedDecl(localContext.depth, tree.sym);
1243 if (block == null) break;
1244 switch (block.getTag()) {
1245 case CLASSDEF:
1246 JCClassDecl cdecl = (JCClassDecl)block;
1247 ((LambdaTranslationContext)localContext)
1248 .addSymbol(cdecl.sym, CAPTURED_THIS);
1249 break;
1250 default:
1251 Assert.error("bad block kind");
1252 }
1253 }
1254 localContext = localContext.prev;
1255 }
1256 }
1257 }
1258 super.visitIdent(tree);
1259 }
1261 @Override
1262 public void visitLambda(JCLambda tree) {
1263 analyzeLambda(tree, "lambda.stat");
1264 }
1266 private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) {
1267 // Translation of the receiver expression must occur first
1268 JCExpression rcvr = translate(methodReferenceReceiver);
1269 LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1");
1270 if (rcvr != null) {
1271 context.methodReferenceReceiver = rcvr;
1272 }
1273 }
1275 private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) {
1276 List<Frame> prevStack = frameStack;
1277 try {
1278 LambdaTranslationContext context = new LambdaTranslationContext(tree);
1279 if (dumpLambdaToMethodStats) {
1280 log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym);
1281 }
1282 frameStack = frameStack.prepend(new Frame(tree));
1283 for (JCVariableDecl param : tree.params) {
1284 context.addSymbol(param.sym, PARAM);
1285 frameStack.head.addLocal(param.sym);
1286 }
1287 contextMap.put(tree, context);
1288 super.visitLambda(tree);
1289 context.complete();
1290 return context;
1291 }
1292 finally {
1293 frameStack = prevStack;
1294 }
1295 }
1297 @Override
1298 public void visitMethodDef(JCMethodDecl tree) {
1299 List<Frame> prevStack = frameStack;
1300 try {
1301 frameStack = frameStack.prepend(new Frame(tree));
1302 super.visitMethodDef(tree);
1303 }
1304 finally {
1305 frameStack = prevStack;
1306 }
1307 }
1309 @Override
1310 public void visitNewClass(JCNewClass tree) {
1311 TypeSymbol def = tree.type.tsym;
1312 boolean inReferencedClass = currentlyInClass(def);
1313 boolean isLocal = def.isLocal();
1314 if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
1315 TranslationContext<?> localContext = context();
1316 while (localContext != null) {
1317 if (localContext.tree.getTag() == LAMBDA) {
1318 ((LambdaTranslationContext)localContext)
1319 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
1320 }
1321 localContext = localContext.prev;
1322 }
1323 }
1324 if (context() != null && !inReferencedClass && isLocal) {
1325 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
1326 captureLocalClassDefs(def, lambdaContext);
1327 }
1328 super.visitNewClass(tree);
1329 }
1330 //where
1331 void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
1332 JCClassDecl localCDef = localClassDefs.get(csym);
1333 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
1334 BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
1335 @Override
1336 void addFreeVars(ClassSymbol c) {
1337 captureLocalClassDefs(c, lambdaContext);
1338 }
1339 @Override
1340 void visitSymbol(Symbol sym) {
1341 if (sym.kind == VAR &&
1342 sym.owner.kind == MTH &&
1343 ((VarSymbol)sym).getConstValue() == null) {
1344 TranslationContext<?> localContext = context();
1345 while (localContext != null) {
1346 if (localContext.tree.getTag() == LAMBDA) {
1347 JCTree block = capturedDecl(localContext.depth, sym);
1348 if (block == null) break;
1349 ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
1350 }
1351 localContext = localContext.prev;
1352 }
1353 }
1354 }
1355 };
1356 fvc.scan(localCDef);
1357 }
1358 }
1359 //where
1360 boolean currentlyInClass(Symbol csym) {
1361 for (Frame frame : frameStack) {
1362 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
1363 JCClassDecl cdef = (JCClassDecl) frame.tree;
1364 if (cdef.sym == csym) {
1365 return true;
1366 }
1367 }
1368 }
1369 return false;
1370 }
1372 /**
1373 * Method references to local class constructors, may, if the local
1374 * class references local variables, have implicit constructor
1375 * parameters added in Lower; As a result, the invokedynamic bootstrap
1376 * information added in the LambdaToMethod pass will have the wrong
1377 * signature. Hooks between Lower and LambdaToMethod have been added to
1378 * handle normal "new" in this case. This visitor converts potentially
1379 * affected method references into a lambda containing a normal
1380 * expression.
1381 *
1382 * @param tree
1383 */
1384 @Override
1385 public void visitReference(JCMemberReference tree) {
1386 ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree);
1387 contextMap.put(tree, rcontext);
1388 if (rcontext.needsConversionToLambda()) {
1389 // Convert to a lambda, and process as such
1390 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner());
1391 analyzeLambda(conv.lambda(), conv.getReceiverExpression());
1392 } else {
1393 super.visitReference(tree);
1394 if (dumpLambdaToMethodStats) {
1395 log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null);
1396 }
1397 }
1398 }
1400 @Override
1401 public void visitSelect(JCFieldAccess tree) {
1402 if (context() != null && tree.sym.kind == VAR &&
1403 (tree.sym.name == names._this ||
1404 tree.sym.name == names._super)) {
1405 // A select of this or super means, if we are in a lambda,
1406 // we much have an instance context
1407 TranslationContext<?> localContext = context();
1408 while (localContext != null) {
1409 if (localContext.tree.hasTag(LAMBDA)) {
1410 JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
1411 if (clazz == null) break;
1412 ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
1413 }
1414 localContext = localContext.prev;
1415 }
1416 }
1417 super.visitSelect(tree);
1418 }
1420 @Override
1421 public void visitVarDef(JCVariableDecl tree) {
1422 TranslationContext<?> context = context();
1423 LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
1424 (LambdaTranslationContext)context :
1425 null;
1426 if (ltc != null) {
1427 if (frameStack.head.tree.hasTag(LAMBDA)) {
1428 ltc.addSymbol(tree.sym, LOCAL_VAR);
1429 }
1430 // Check for type variables (including as type arguments).
1431 // If they occur within class nested in a lambda, mark for erasure
1432 Type type = tree.sym.asType();
1433 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
1434 ltc.addSymbol(tree.sym, TYPE_VAR);
1435 }
1436 }
1438 List<Frame> prevStack = frameStack;
1439 try {
1440 if (tree.sym.owner.kind == MTH) {
1441 frameStack.head.addLocal(tree.sym);
1442 }
1443 frameStack = frameStack.prepend(new Frame(tree));
1444 super.visitVarDef(tree);
1445 }
1446 finally {
1447 frameStack = prevStack;
1448 }
1449 }
1451 /**
1452 * Return a valid owner given the current declaration stack
1453 * (required to skip synthetic lambda symbols)
1454 */
1455 private Symbol owner() {
1456 return owner(false);
1457 }
1459 @SuppressWarnings("fallthrough")
1460 private Symbol owner(boolean skipLambda) {
1461 List<Frame> frameStack2 = frameStack;
1462 while (frameStack2.nonEmpty()) {
1463 switch (frameStack2.head.tree.getTag()) {
1464 case VARDEF:
1465 if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
1466 frameStack2 = frameStack2.tail;
1467 break;
1468 }
1469 JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
1470 return initSym(cdecl.sym,
1471 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
1472 case BLOCK:
1473 JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
1474 return initSym(cdecl2.sym,
1475 ((JCBlock)frameStack2.head.tree).flags & STATIC);
1476 case CLASSDEF:
1477 return ((JCClassDecl)frameStack2.head.tree).sym;
1478 case METHODDEF:
1479 return ((JCMethodDecl)frameStack2.head.tree).sym;
1480 case LAMBDA:
1481 if (!skipLambda)
1482 return ((LambdaTranslationContext)contextMap
1483 .get(frameStack2.head.tree)).translatedSym;
1484 default:
1485 frameStack2 = frameStack2.tail;
1486 }
1487 }
1488 Assert.error();
1489 return null;
1490 }
1492 private Symbol initSym(ClassSymbol csym, long flags) {
1493 boolean isStatic = (flags & STATIC) != 0;
1494 if (isStatic) {
1495 /* static clinits are generated in Gen, so we need to use a fake
1496 * one. Attr creates a fake clinit method while attributing
1497 * lambda expressions used as initializers of static fields, so
1498 * let's use that one.
1499 */
1500 MethodSymbol clinit = attr.removeClinit(csym);
1501 if (clinit != null) {
1502 clinits.put(csym, clinit);
1503 return clinit;
1504 }
1506 /* if no clinit is found at Attr, then let's try at clinits.
1507 */
1508 clinit = (MethodSymbol)clinits.get(csym);
1509 if (clinit == null) {
1510 /* no luck, let's create a new one
1511 */
1512 clinit = makePrivateSyntheticMethod(STATIC,
1513 names.clinit,
1514 new MethodType(List.<Type>nil(), syms.voidType,
1515 List.<Type>nil(), syms.methodClass),
1516 csym);
1517 clinits.put(csym, clinit);
1518 }
1519 return clinit;
1520 } else {
1521 //get the first constructor and treat it as the instance init sym
1522 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
1523 return s;
1524 }
1525 }
1526 Assert.error("init not found");
1527 return null;
1528 }
1530 private JCTree directlyEnclosingLambda() {
1531 if (frameStack.isEmpty()) {
1532 return null;
1533 }
1534 List<Frame> frameStack2 = frameStack;
1535 while (frameStack2.nonEmpty()) {
1536 switch (frameStack2.head.tree.getTag()) {
1537 case CLASSDEF:
1538 case METHODDEF:
1539 return null;
1540 case LAMBDA:
1541 return frameStack2.head.tree;
1542 default:
1543 frameStack2 = frameStack2.tail;
1544 }
1545 }
1546 Assert.error();
1547 return null;
1548 }
1550 private boolean inClassWithinLambda() {
1551 if (frameStack.isEmpty()) {
1552 return false;
1553 }
1554 List<Frame> frameStack2 = frameStack;
1555 boolean classFound = false;
1556 while (frameStack2.nonEmpty()) {
1557 switch (frameStack2.head.tree.getTag()) {
1558 case LAMBDA:
1559 return classFound;
1560 case CLASSDEF:
1561 classFound = true;
1562 frameStack2 = frameStack2.tail;
1563 break;
1564 default:
1565 frameStack2 = frameStack2.tail;
1566 }
1567 }
1568 // No lambda
1569 return false;
1570 }
1572 /**
1573 * Return the declaration corresponding to a symbol in the enclosing
1574 * scope; the depth parameter is used to filter out symbols defined
1575 * in nested scopes (which do not need to undergo capture).
1576 */
1577 private JCTree capturedDecl(int depth, Symbol sym) {
1578 int currentDepth = frameStack.size() - 1;
1579 for (Frame block : frameStack) {
1580 switch (block.tree.getTag()) {
1581 case CLASSDEF:
1582 ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
1583 if (sym.isMemberOf(clazz, types)) {
1584 return currentDepth > depth ? null : block.tree;
1585 }
1586 break;
1587 case VARDEF:
1588 if (((JCVariableDecl)block.tree).sym == sym &&
1589 sym.owner.kind == MTH) { //only locals are captured
1590 return currentDepth > depth ? null : block.tree;
1591 }
1592 break;
1593 case BLOCK:
1594 case METHODDEF:
1595 case LAMBDA:
1596 if (block.locals != null && block.locals.contains(sym)) {
1597 return currentDepth > depth ? null : block.tree;
1598 }
1599 break;
1600 default:
1601 Assert.error("bad decl kind " + block.tree.getTag());
1602 }
1603 currentDepth--;
1604 }
1605 return null;
1606 }
1608 private TranslationContext<?> context() {
1609 for (Frame frame : frameStack) {
1610 TranslationContext<?> context = contextMap.get(frame.tree);
1611 if (context != null) {
1612 return context;
1613 }
1614 }
1615 return null;
1616 }
1618 /**
1619 * This is used to filter out those identifiers that needs to be adjusted
1620 * when translating away lambda expressions
1621 */
1622 private boolean lambdaIdentSymbolFilter(Symbol sym) {
1623 return (sym.kind == VAR || sym.kind == MTH)
1624 && !sym.isStatic()
1625 && sym.name != names.init;
1626 }
1628 /**
1629 * This is used to filter out those new class expressions that need to
1630 * be qualified with an enclosing tree
1631 */
1632 private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
1633 if (context != null
1634 && tree.encl == null
1635 && tree.def == null
1636 && !tree.type.getEnclosingType().hasTag(NONE)) {
1637 Type encl = tree.type.getEnclosingType();
1638 Type current = context.owner.enclClass().type;
1639 while (!current.hasTag(NONE)) {
1640 if (current.tsym.isSubClass(encl.tsym, types)) {
1641 return true;
1642 }
1643 current = current.getEnclosingType();
1644 }
1645 return false;
1646 } else {
1647 return false;
1648 }
1649 }
1651 private class Frame {
1652 final JCTree tree;
1653 List<Symbol> locals;
1655 public Frame(JCTree tree) {
1656 this.tree = tree;
1657 }
1659 void addLocal(Symbol sym) {
1660 if (locals == null) {
1661 locals = List.nil();
1662 }
1663 locals = locals.prepend(sym);
1664 }
1665 }
1667 /**
1668 * This class is used to store important information regarding translation of
1669 * lambda expression/method references (see subclasses).
1670 */
1671 private abstract class TranslationContext<T extends JCFunctionalExpression> {
1673 /** the underlying (untranslated) tree */
1674 final T tree;
1676 /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
1677 final Symbol owner;
1679 /** the depth of this lambda expression in the frame stack */
1680 final int depth;
1682 /** the enclosing translation context (set for nested lambdas/mref) */
1683 final TranslationContext<?> prev;
1685 /** list of methods to be bridged by the meta-factory */
1686 final List<Symbol> bridges;
1688 TranslationContext(T tree) {
1689 this.tree = tree;
1690 this.owner = owner();
1691 this.depth = frameStack.size() - 1;
1692 this.prev = context();
1693 ClassSymbol csym =
1694 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
1695 this.bridges = types.functionalInterfaceBridges(csym);
1696 }
1698 /** does this functional expression need to be created using alternate metafactory? */
1699 boolean needsAltMetafactory() {
1700 return tree.targets.length() > 1 ||
1701 isSerializable() ||
1702 bridges.length() > 1;
1703 }
1705 /** does this functional expression require serialization support? */
1706 boolean isSerializable() {
1707 if (forceSerializable) {
1708 return true;
1709 }
1710 for (Type target : tree.targets) {
1711 if (types.asSuper(target, syms.serializableType.tsym) != null) {
1712 return true;
1713 }
1714 }
1715 return false;
1716 }
1718 /**
1719 * @return Name of the enclosing method to be folded into synthetic
1720 * method name
1721 */
1722 String enclosingMethodName() {
1723 return syntheticMethodNameComponent(owner.name);
1724 }
1726 /**
1727 * @return Method name in a form that can be folded into a
1728 * component of a synthetic method name
1729 */
1730 String syntheticMethodNameComponent(Name name) {
1731 if (name == null) {
1732 return "null";
1733 }
1734 String methodName = name.toString();
1735 if (methodName.equals("<clinit>")) {
1736 methodName = "static";
1737 } else if (methodName.equals("<init>")) {
1738 methodName = "new";
1739 }
1740 return methodName;
1741 }
1742 }
1744 /**
1745 * This class retains all the useful information about a lambda expression;
1746 * the contents of this class are filled by the LambdaAnalyzer visitor,
1747 * and the used by the main translation routines in order to adjust references
1748 * to captured locals/members, etc.
1749 */
1750 private class LambdaTranslationContext extends TranslationContext<JCLambda> {
1752 /** variable in the enclosing context to which this lambda is assigned */
1753 final Symbol self;
1755 /** variable in the enclosing context to which this lambda is assigned */
1756 final Symbol assignedTo;
1758 Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
1760 /** the synthetic symbol for the method hoisting the translated lambda */
1761 MethodSymbol translatedSym;
1763 List<JCVariableDecl> syntheticParams;
1765 /**
1766 * to prevent recursion, track local classes processed
1767 */
1768 final Set<Symbol> freeVarProcessedLocalClasses;
1770 /**
1771 * For method references converted to lambdas. The method
1772 * reference receiver expression. Must be treated like a captured
1773 * variable.
1774 */
1775 JCExpression methodReferenceReceiver;
1777 LambdaTranslationContext(JCLambda tree) {
1778 super(tree);
1779 Frame frame = frameStack.head;
1780 switch (frame.tree.getTag()) {
1781 case VARDEF:
1782 assignedTo = self = ((JCVariableDecl) frame.tree).sym;
1783 break;
1784 case ASSIGN:
1785 self = null;
1786 assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
1787 break;
1788 default:
1789 assignedTo = self = null;
1790 break;
1791 }
1793 // This symbol will be filled-in in complete
1794 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
1796 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
1798 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
1799 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
1800 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
1801 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
1802 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
1804 freeVarProcessedLocalClasses = new HashSet<>();
1805 }
1807 /**
1808 * For a serializable lambda, generate a disambiguating string
1809 * which maximizes stability across deserialization.
1810 *
1811 * @return String to differentiate synthetic lambda method names
1812 */
1813 private String serializedLambdaDisambiguation() {
1814 StringBuilder buf = new StringBuilder();
1815 // Append the enclosing method signature to differentiate
1816 // overloaded enclosing methods. For lambdas enclosed in
1817 // lambdas, the generated lambda method will not have type yet,
1818 // but the enclosing method's name will have been generated
1819 // with this same method, so it will be unique and never be
1820 // overloaded.
1821 Assert.check(
1822 owner.type != null ||
1823 directlyEnclosingLambda() != null);
1824 if (owner.type != null) {
1825 buf.append(typeSig(owner.type));
1826 buf.append(":");
1827 }
1829 // Add target type info
1830 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
1831 buf.append(" ");
1833 // Add variable assigned to
1834 if (assignedTo != null) {
1835 buf.append(assignedTo.flatName());
1836 buf.append("=");
1837 }
1838 //add captured locals info: type, name, order
1839 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
1840 if (fv != self) {
1841 buf.append(typeSig(fv.type));
1842 buf.append(" ");
1843 buf.append(fv.flatName());
1844 buf.append(",");
1845 }
1846 }
1848 return buf.toString();
1849 }
1851 /**
1852 * For a non-serializable lambda, generate a simple method.
1853 *
1854 * @return Name to use for the synthetic lambda method name
1855 */
1856 private Name lambdaName() {
1857 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
1858 }
1860 /**
1861 * For a serializable lambda, generate a method name which maximizes
1862 * name stability across deserialization.
1863 *
1864 * @return Name to use for the synthetic lambda method name
1865 */
1866 private Name serializedLambdaName() {
1867 StringBuilder buf = new StringBuilder();
1868 buf.append(names.lambda);
1869 // Append the name of the method enclosing the lambda.
1870 buf.append(enclosingMethodName());
1871 buf.append('$');
1872 // Append a hash of the disambiguating string : enclosing method
1873 // signature, etc.
1874 String disam = serializedLambdaDisambiguation();
1875 buf.append(Integer.toHexString(disam.hashCode()));
1876 buf.append('$');
1877 // The above appended name components may not be unique, append
1878 // a count based on the above name components.
1879 buf.append(syntheticMethodNameCounts.getIndex(buf));
1880 String result = buf.toString();
1881 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
1882 return names.fromString(result);
1883 }
1885 /**
1886 * Translate a symbol of a given kind into something suitable for the
1887 * synthetic lambda body
1888 */
1889 Symbol translate(final Symbol sym, LambdaSymbolKind skind) {
1890 Symbol ret;
1891 switch (skind) {
1892 case CAPTURED_THIS:
1893 ret = sym; // self represented
1894 break;
1895 case TYPE_VAR:
1896 // Just erase the type var
1897 ret = new VarSymbol(sym.flags(), sym.name,
1898 types.erasure(sym.type), sym.owner);
1900 /* this information should also be kept for LVT generation at Gen
1901 * a Symbol with pos < startPos won't be tracked.
1902 */
1903 ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
1904 break;
1905 case CAPTURED_VAR:
1906 ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
1907 @Override
1908 public Symbol baseSymbol() {
1909 //keep mapping with original captured symbol
1910 return sym;
1911 }
1912 };
1913 break;
1914 case LOCAL_VAR:
1915 ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
1916 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1917 break;
1918 case PARAM:
1919 ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym);
1920 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1921 break;
1922 default:
1923 Assert.error(skind.name());
1924 throw new AssertionError();
1925 }
1926 if (ret != sym) {
1927 ret.setDeclarationAttributes(sym.getRawAttributes());
1928 ret.setTypeAttributes(sym.getRawTypeAttributes());
1929 }
1930 return ret;
1931 }
1933 void addSymbol(Symbol sym, LambdaSymbolKind skind) {
1934 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
1935 if (!transMap.containsKey(sym)) {
1936 transMap.put(sym, translate(sym, skind));
1937 }
1938 }
1940 Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
1941 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
1942 Assert.checkNonNull(m);
1943 return m;
1944 }
1946 JCTree translate(JCIdent lambdaIdent) {
1947 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
1948 if (m.containsKey(lambdaIdent.sym)) {
1949 Symbol tSym = m.get(lambdaIdent.sym);
1950 JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
1951 tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
1952 return t;
1953 }
1954 }
1955 return null;
1956 }
1958 /**
1959 * The translatedSym is not complete/accurate until the analysis is
1960 * finished. Once the analysis is finished, the translatedSym is
1961 * "completed" -- updated with type information, access modifiers,
1962 * and full parameter list.
1963 */
1964 void complete() {
1965 if (syntheticParams != null) {
1966 return;
1967 }
1968 boolean inInterface = translatedSym.owner.isInterface();
1969 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
1971 // If instance access isn't needed, make it static.
1972 // Interface instance methods must be default methods.
1973 // Lambda methods are private synthetic.
1974 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
1975 // from the class.
1976 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
1977 owner.flags_field & STRICTFP |
1978 owner.owner.flags_field & STRICTFP |
1979 PRIVATE |
1980 (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
1982 //compute synthetic params
1983 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
1984 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>();
1986 // The signature of the method is augmented with the following
1987 // synthetic parameters:
1988 //
1989 // 1) reference to enclosing contexts captured by the lambda expression
1990 // 2) enclosing locals captured by the lambda expression
1991 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
1992 params.append(make.VarDef((VarSymbol) thisSym, null));
1993 parameterSymbols.append((VarSymbol) thisSym);
1994 }
1995 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
1996 params.append(make.VarDef((VarSymbol) thisSym, null));
1997 parameterSymbols.append((VarSymbol) thisSym);
1998 }
1999 syntheticParams = params.toList();
2001 translatedSym.params = parameterSymbols.toList();
2003 // Compute and set the lambda name
2004 translatedSym.name = isSerializable()
2005 ? serializedLambdaName()
2006 : lambdaName();
2008 //prepend synthetic args to translated lambda method signature
2009 translatedSym.type = types.createMethodTypeWithParameters(
2010 generatedLambdaSig(),
2011 TreeInfo.types(syntheticParams));
2012 }
2014 Type generatedLambdaSig() {
2015 return types.erasure(tree.getDescriptorType(types));
2016 }
2017 }
2019 /**
2020 * This class retains all the useful information about a method reference;
2021 * the contents of this class are filled by the LambdaAnalyzer visitor,
2022 * and the used by the main translation routines in order to adjust method
2023 * references (i.e. in case a bridge is needed)
2024 */
2025 private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
2027 final boolean isSuper;
2028 final Symbol sigPolySym;
2030 ReferenceTranslationContext(JCMemberReference tree) {
2031 super(tree);
2032 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
2033 this.sigPolySym = isSignaturePolymorphic()
2034 ? makePrivateSyntheticMethod(tree.sym.flags(),
2035 tree.sym.name,
2036 bridgedRefSig(),
2037 tree.sym.enclClass())
2038 : null;
2039 }
2041 /**
2042 * Get the opcode associated with this method reference
2043 */
2044 int referenceKind() {
2045 return LambdaToMethod.this.referenceKind(tree.sym);
2046 }
2048 boolean needsVarArgsConversion() {
2049 return tree.varargsElement != null;
2050 }
2052 /**
2053 * @return Is this an array operation like clone()
2054 */
2055 boolean isArrayOp() {
2056 return tree.sym.owner == syms.arrayClass;
2057 }
2059 boolean receiverAccessible() {
2060 //hack needed to workaround 292 bug (7087658)
2061 //when 292 issue is fixed we should remove this and change the backend
2062 //code to always generate a method handle to an accessible method
2063 return tree.ownerAccessible;
2064 }
2066 /**
2067 * The VM does not support access across nested classes (8010319).
2068 * Were that ever to change, this should be removed.
2069 */
2070 boolean isPrivateInOtherClass() {
2071 return (tree.sym.flags() & PRIVATE) != 0 &&
2072 !types.isSameType(
2073 types.erasure(tree.sym.enclClass().asType()),
2074 types.erasure(owner.enclClass().asType()));
2075 }
2077 /**
2078 * Signature polymorphic methods need special handling.
2079 * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
2080 */
2081 final boolean isSignaturePolymorphic() {
2082 return tree.sym.kind == MTH &&
2083 types.isSignaturePolymorphic((MethodSymbol)tree.sym);
2084 }
2086 /**
2087 * Erasure destroys the implementation parameter subtype
2088 * relationship for intersection types
2089 */
2090 boolean interfaceParameterIsIntersectionType() {
2091 List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
2092 if (tree.kind == ReferenceKind.UNBOUND) {
2093 tl = tl.tail;
2094 }
2095 for (; tl.nonEmpty(); tl = tl.tail) {
2096 Type pt = tl.head;
2097 if (pt.getKind() == TypeKind.TYPEVAR) {
2098 TypeVar tv = (TypeVar) pt;
2099 if (tv.bound.getKind() == TypeKind.INTERSECTION) {
2100 return true;
2101 }
2102 }
2103 }
2104 return false;
2105 }
2107 /**
2108 * Does this reference need to be converted to a lambda
2109 * (i.e. var args need to be expanded or "super" is used)
2110 */
2111 final boolean needsConversionToLambda() {
2112 return interfaceParameterIsIntersectionType() ||
2113 isSuper ||
2114 needsVarArgsConversion() ||
2115 isArrayOp() ||
2116 isPrivateInOtherClass() ||
2117 !receiverAccessible() ||
2118 (tree.getMode() == ReferenceMode.NEW &&
2119 tree.kind != ReferenceKind.ARRAY_CTOR &&
2120 (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
2121 }
2123 Type generatedRefSig() {
2124 return types.erasure(tree.sym.type);
2125 }
2127 Type bridgedRefSig() {
2128 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
2129 }
2130 }
2131 }
2132 // </editor-fold>
2134 /*
2135 * These keys provide mappings for various translated lambda symbols
2136 * and the prevailing order must be maintained.
2137 */
2138 enum LambdaSymbolKind {
2139 PARAM, // original to translated lambda parameters
2140 LOCAL_VAR, // original to translated lambda locals
2141 CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters
2142 CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access)
2143 TYPE_VAR; // original to translated lambda type variables
2144 }
2146 /**
2147 * ****************************************************************
2148 * Signature Generation
2149 * ****************************************************************
2150 */
2152 private String typeSig(Type type) {
2153 L2MSignatureGenerator sg = new L2MSignatureGenerator();
2154 sg.assembleSig(type);
2155 return sg.toString();
2156 }
2158 private String classSig(Type type) {
2159 L2MSignatureGenerator sg = new L2MSignatureGenerator();
2160 sg.assembleClassSig(type);
2161 return sg.toString();
2162 }
2164 /**
2165 * Signature Generation
2166 */
2167 private class L2MSignatureGenerator extends Types.SignatureGenerator {
2169 /**
2170 * An output buffer for type signatures.
2171 */
2172 StringBuilder sb = new StringBuilder();
2174 L2MSignatureGenerator() {
2175 super(types);
2176 }
2178 @Override
2179 protected void append(char ch) {
2180 sb.append(ch);
2181 }
2183 @Override
2184 protected void append(byte[] ba) {
2185 sb.append(new String(ba));
2186 }
2188 @Override
2189 protected void append(Name name) {
2190 sb.append(name.toString());
2191 }
2193 @Override
2194 public String toString() {
2195 return sb.toString();
2196 }
2197 }
2198 }