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