Mon, 03 Jun 2013 17:09:26 -0700
8006615: [doclint] move remaining messages into resource bundle
Reviewed-by: mcimadamore, vromero
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.HashMap;
52 import java.util.LinkedHashMap;
53 import java.util.Map;
55 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
56 import static com.sun.tools.javac.code.Flags.*;
57 import static com.sun.tools.javac.code.Kinds.*;
58 import static com.sun.tools.javac.code.TypeTag.*;
59 import static com.sun.tools.javac.tree.JCTree.Tag.*;
61 /**
62 * This pass desugars lambda expressions into static methods
63 *
64 * <p><b>This is NOT part of any supported API.
65 * If you write code that depends on this, you do so at your own risk.
66 * This code and its internal interfaces are subject to change or
67 * deletion without notice.</b>
68 */
69 public class LambdaToMethod extends TreeTranslator {
71 private Lower lower;
72 private Names names;
73 private Symtab syms;
74 private Resolve rs;
75 private TreeMaker make;
76 private Types types;
77 private TransTypes transTypes;
78 private Env<AttrContext> attrEnv;
80 /** the analyzer scanner */
81 private LambdaAnalyzerPreprocessor analyzer;
83 /** map from lambda trees to translation contexts */
84 private Map<JCTree, TranslationContext<?>> contextMap;
86 /** current translation context (visitor argument) */
87 private TranslationContext<?> context;
89 /** info about the current class being processed */
90 private KlassInfo kInfo;
92 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
93 public static final int FLAG_SERIALIZABLE = 1 << 0;
95 /** Flag for alternate metafactories indicating the lambda object has multiple targets */
96 public static final int FLAG_MARKERS = 1 << 1;
98 private class KlassInfo {
100 /**
101 * list of methods to append
102 */
103 private ListBuffer<JCTree> appendedMethodList;
105 /**
106 * list of deserialization cases
107 */
108 private final Map<String, ListBuffer<JCStatement>> deserializeCases;
110 /**
111 * deserialize method symbol
112 */
113 private final MethodSymbol deserMethodSym;
115 /**
116 * deserialize method parameter symbol
117 */
118 private final VarSymbol deserParamSym;
120 private KlassInfo(Symbol kSym) {
121 appendedMethodList = ListBuffer.lb();
122 deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
123 long flags = PRIVATE | STATIC | SYNTHETIC;
124 MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
125 List.<Type>nil(), syms.methodClass);
126 deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym);
127 deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
128 syms.serializedLambdaType, deserMethodSym);
129 }
131 private void addMethod(JCTree decl) {
132 appendedMethodList = appendedMethodList.prepend(decl);
133 }
134 }
136 // <editor-fold defaultstate="collapsed" desc="Instantiating">
137 private static final Context.Key<LambdaToMethod> unlambdaKey =
138 new Context.Key<LambdaToMethod>();
140 public static LambdaToMethod instance(Context context) {
141 LambdaToMethod instance = context.get(unlambdaKey);
142 if (instance == null) {
143 instance = new LambdaToMethod(context);
144 }
145 return instance;
146 }
148 private LambdaToMethod(Context context) {
149 lower = Lower.instance(context);
150 names = Names.instance(context);
151 syms = Symtab.instance(context);
152 rs = Resolve.instance(context);
153 make = TreeMaker.instance(context);
154 types = Types.instance(context);
155 transTypes = TransTypes.instance(context);
156 analyzer = new LambdaAnalyzerPreprocessor();
157 }
158 // </editor-fold>
160 // <editor-fold defaultstate="collapsed" desc="translate methods">
161 @Override
162 public <T extends JCTree> T translate(T tree) {
163 TranslationContext<?> newContext = contextMap.get(tree);
164 return translate(tree, newContext != null ? newContext : context);
165 }
167 <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
168 TranslationContext<?> prevContext = context;
169 try {
170 context = newContext;
171 return super.translate(tree);
172 }
173 finally {
174 context = prevContext;
175 }
176 }
178 <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
179 ListBuffer<T> buf = ListBuffer.lb();
180 for (T tree : trees) {
181 buf.append(translate(tree, newContext));
182 }
183 return buf.toList();
184 }
186 public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
187 this.make = make;
188 this.attrEnv = env;
189 this.context = null;
190 this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
191 return translate(cdef);
192 }
193 // </editor-fold>
195 // <editor-fold defaultstate="collapsed" desc="visitor methods">
196 /**
197 * Visit a class.
198 * Maintain the translatedMethodList across nested classes.
199 * Append the translatedMethodList to the class after it is translated.
200 * @param tree
201 */
202 @Override
203 public void visitClassDef(JCClassDecl tree) {
204 if (tree.sym.owner.kind == PCK) {
205 //analyze class
206 tree = analyzer.analyzeAndPreprocessClass(tree);
207 }
208 KlassInfo prevKlassInfo = kInfo;
209 try {
210 kInfo = new KlassInfo(tree.sym);
211 super.visitClassDef(tree);
212 if (!kInfo.deserializeCases.isEmpty()) {
213 kInfo.addMethod(makeDeserializeMethod(tree.sym));
214 }
215 //add all translated instance methods here
216 List<JCTree> newMethods = kInfo.appendedMethodList.toList();
217 tree.defs = tree.defs.appendList(newMethods);
218 for (JCTree lambda : newMethods) {
219 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
220 }
221 result = tree;
222 } finally {
223 kInfo = prevKlassInfo;
224 }
225 }
227 /**
228 * Translate a lambda into a method to be inserted into the class.
229 * Then replace the lambda site with an invokedynamic call of to lambda
230 * meta-factory, which will use the lambda method.
231 * @param tree
232 */
233 @Override
234 public void visitLambda(JCLambda tree) {
235 LambdaTranslationContext localContext = (LambdaTranslationContext)context;
236 MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
237 MethodType lambdaType = (MethodType) sym.type;
239 {
240 MethodSymbol owner = (MethodSymbol) localContext.owner;
241 ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
242 ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
244 for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
245 if (tc.position.onLambda == tree) {
246 lambdaTypeAnnos.append(tc);
247 } else {
248 ownerTypeAnnos.append(tc);
249 }
250 }
251 if (lambdaTypeAnnos.nonEmpty()) {
252 owner.annotations.setTypeAttributes(ownerTypeAnnos.toList());
253 sym.annotations.setTypeAttributes(lambdaTypeAnnos.toList());
254 }
255 }
257 //create the method declaration hoisting the lambda body
258 JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
259 sym.name,
260 make.QualIdent(lambdaType.getReturnType().tsym),
261 List.<JCTypeParameter>nil(),
262 localContext.syntheticParams,
263 lambdaType.getThrownTypes() == null ?
264 List.<JCExpression>nil() :
265 make.Types(lambdaType.getThrownTypes()),
266 null,
267 null);
268 lambdaDecl.sym = sym;
269 lambdaDecl.type = lambdaType;
271 //translate lambda body
272 //As the lambda body is translated, all references to lambda locals,
273 //captured variables, enclosing members are adjusted accordingly
274 //to refer to the static method parameters (rather than i.e. acessing to
275 //captured members directly).
276 lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
278 //Add the method to the list of methods to be added to this class.
279 kInfo.addMethod(lambdaDecl);
281 //now that we have generated a method for the lambda expression,
282 //we can translate the lambda into a method reference pointing to the newly
283 //created method.
284 //
285 //Note that we need to adjust the method handle so that it will match the
286 //signature of the SAM descriptor - this means that the method reference
287 //should be added the following synthetic arguments:
288 //
289 // * the "this" argument if it is an instance method
290 // * enclosing locals captured by the lambda expression
292 ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
294 if (!sym.isStatic()) {
295 syntheticInits.append(makeThis(
296 sym.owner.enclClass().asType(),
297 localContext.owner.enclClass()));
298 }
300 //add captured locals
301 for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
302 if (fv != localContext.self) {
303 JCTree captured_local = make.Ident(fv).setType(fv.type);
304 syntheticInits.append((JCExpression) captured_local);
305 }
306 }
308 //then, determine the arguments to the indy call
309 List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
311 //build a sam instance using an indy call to the meta-factory
312 int refKind = referenceKind(sym);
314 //convert to an invokedynamic call
315 result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args);
316 }
318 private JCIdent makeThis(Type type, Symbol owner) {
319 VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
320 names._this,
321 type,
322 owner);
323 return make.Ident(_this);
324 }
326 /**
327 * Translate a method reference into an invokedynamic call to the
328 * meta-factory.
329 * @param tree
330 */
331 @Override
332 public void visitReference(JCMemberReference tree) {
333 ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
335 //first determine the method symbol to be used to generate the sam instance
336 //this is either the method reference symbol, or the bridged reference symbol
337 Symbol refSym = localContext.needsBridge() ?
338 localContext.bridgeSym :
339 tree.sym;
341 //build the bridge method, if needed
342 if (localContext.needsBridge()) {
343 bridgeMemberReference(tree, localContext);
344 }
346 //the qualifying expression is treated as a special captured arg
347 JCExpression init;
348 switch(tree.kind) {
350 case IMPLICIT_INNER: /** Inner :: new */
351 case SUPER: /** super :: instMethod */
352 init = makeThis(
353 localContext.owner.enclClass().asType(),
354 localContext.owner.enclClass());
355 break;
357 case BOUND: /** Expr :: instMethod */
358 init = tree.getQualifierExpression();
359 break;
361 case UNBOUND: /** Type :: instMethod */
362 case STATIC: /** Type :: staticMethod */
363 case TOPLEVEL: /** Top level :: new */
364 case ARRAY_CTOR: /** ArrayType :: new */
365 init = null;
366 break;
368 default:
369 throw new InternalError("Should not have an invalid kind");
370 }
372 List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
375 //build a sam instance using an indy call to the meta-factory
376 result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args);
377 }
379 /**
380 * Translate identifiers within a lambda to the mapped identifier
381 * @param tree
382 */
383 @Override
384 public void visitIdent(JCIdent tree) {
385 if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
386 super.visitIdent(tree);
387 } else {
388 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
389 if (lambdaContext.getSymbolMap(PARAM).containsKey(tree.sym)) {
390 Symbol translatedSym = lambdaContext.getSymbolMap(PARAM).get(tree.sym);
391 result = make.Ident(translatedSym).setType(tree.type);
392 translatedSym.annotations.setTypeAttributes(tree.sym.getRawTypeAttributes());
393 } else if (lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
394 Symbol translatedSym = lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
395 result = make.Ident(translatedSym).setType(tree.type);
396 translatedSym.annotations.setTypeAttributes(tree.sym.getRawTypeAttributes());
397 } else if (lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
398 Symbol translatedSym = lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
399 result = make.Ident(translatedSym).setType(translatedSym.type);
400 translatedSym.annotations.setTypeAttributes(tree.sym.getRawTypeAttributes());
401 } else if (lambdaContext.getSymbolMap(CAPTURED_VAR).containsKey(tree.sym)) {
402 Symbol translatedSym = lambdaContext.getSymbolMap(CAPTURED_VAR).get(tree.sym);
403 result = make.Ident(translatedSym).setType(tree.type);
404 } else {
405 //access to untranslated symbols (i.e. compile-time constants,
406 //members defined inside the lambda body, etc.) )
407 super.visitIdent(tree);
408 }
409 }
410 }
412 @Override
413 public void visitVarDef(JCVariableDecl tree) {
414 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
415 if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
416 JCExpression init = translate(tree.init);
417 result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
418 } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
419 JCExpression init = translate(tree.init);
420 VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
421 result = make.VarDef(xsym, init);
422 // Replace the entered symbol for this variable
423 Scope sc = tree.sym.owner.members();
424 if (sc != null) {
425 sc.remove(tree.sym);
426 sc.enter(xsym);
427 }
428 } else {
429 super.visitVarDef(tree);
430 }
431 }
433 // </editor-fold>
435 // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
437 private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
438 return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
439 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
440 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
441 }
443 private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
444 Type restype = lambdaMethodDecl.type.getReturnType();
445 boolean isLambda_void = expr.type.hasTag(VOID);
446 boolean isTarget_void = restype.hasTag(VOID);
447 boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
448 if (isTarget_void) {
449 //target is void:
450 // BODY;
451 JCStatement stat = make.Exec(expr);
452 return make.Block(0, List.<JCStatement>of(stat));
453 } else if (isLambda_void && isTarget_Void) {
454 //void to Void conversion:
455 // BODY; return null;
456 ListBuffer<JCStatement> stats = ListBuffer.lb();
457 stats.append(make.Exec(expr));
458 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
459 return make.Block(0, stats.toList());
460 } else {
461 //non-void to non-void conversion:
462 // return (TYPE)BODY;
463 JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
464 return make.Block(0, List.<JCStatement>of(make.Return(retExpr)));
465 }
466 }
468 private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
469 final Type restype = lambdaMethodDecl.type.getReturnType();
470 final boolean isTarget_void = restype.hasTag(VOID);
471 boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
473 class LambdaBodyTranslator extends TreeTranslator {
475 @Override
476 public void visitClassDef(JCClassDecl tree) {
477 //do NOT recurse on any inner classes
478 result = tree;
479 }
481 @Override
482 public void visitLambda(JCLambda tree) {
483 //do NOT recurse on any nested lambdas
484 result = tree;
485 }
487 @Override
488 public void visitReturn(JCReturn tree) {
489 boolean isLambda_void = tree.expr == null;
490 if (isTarget_void && !isLambda_void) {
491 //Void to void conversion:
492 // { TYPE $loc = RET-EXPR; return; }
493 VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
494 JCVariableDecl varDef = make.VarDef(loc, tree.expr);
495 result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
496 } else if (!isTarget_void || !isLambda_void) {
497 //non-void to non-void conversion:
498 // return (TYPE)RET-EXPR;
499 tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
500 result = tree;
501 } else {
502 result = tree;
503 }
505 }
506 }
508 JCBlock trans_block = new LambdaBodyTranslator().translate(block);
509 if (completeNormally && isTarget_Void) {
510 //there's no return statement and the lambda (possibly inferred)
511 //return type is java.lang.Void; emit a synthetic return statement
512 trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
513 }
514 return trans_block;
515 }
517 private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
518 ListBuffer<JCCase> cases = ListBuffer.lb();
519 ListBuffer<JCBreak> breaks = ListBuffer.lb();
520 for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
521 JCBreak br = make.Break(null);
522 breaks.add(br);
523 List<JCStatement> stmts = entry.getValue().append(br).toList();
524 cases.add(make.Case(make.Literal(entry.getKey()), stmts));
525 }
526 JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
527 for (JCBreak br : breaks) {
528 br.target = sw;
529 }
530 JCBlock body = make.Block(0L, List.<JCStatement>of(
531 sw,
532 make.Throw(makeNewClass(
533 syms.illegalArgumentExceptionType,
534 List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
535 JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
536 names.deserializeLambda,
537 make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
538 List.<JCTypeParameter>nil(),
539 List.of(make.VarDef(kInfo.deserParamSym, null)),
540 List.<JCExpression>nil(),
541 body,
542 null);
543 deser.sym = kInfo.deserMethodSym;
544 deser.type = kInfo.deserMethodSym.type;
545 //System.err.printf("DESER: '%s'\n", deser);
546 return deser;
547 }
549 /** Make an attributed class instance creation expression.
550 * @param ctype The class type.
551 * @param args The constructor arguments.
552 * @param cons The constructor symbol
553 */
554 JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
555 JCNewClass tree = make.NewClass(null,
556 null, make.QualIdent(ctype.tsym), args, null);
557 tree.constructor = cons;
558 tree.type = ctype;
559 return tree;
560 }
562 /** Make an attributed class instance creation expression.
563 * @param ctype The class type.
564 * @param args The constructor arguments.
565 */
566 JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
567 return makeNewClass(ctype, args,
568 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
569 }
571 private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
572 DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
573 String functionalInterfaceClass = classSig(targetType);
574 String functionalInterfaceMethodName = samSym.getSimpleName().toString();
575 String functionalInterfaceMethodSignature = methodSig(types.erasure(samSym.type));
576 String implClass = classSig(types.erasure(refSym.owner.type));
577 String implMethodName = refSym.getQualifiedName().toString();
578 String implMethodSignature = methodSig(types.erasure(refSym.type));
580 JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
581 ListBuffer<JCExpression> serArgs = ListBuffer.lb();
582 int i = 0;
583 for (Type t : indyType.getParameterTypes()) {
584 List<JCExpression> indexAsArg = ListBuffer.<JCExpression>lb().append(make.Literal(i)).toList();
585 List<Type> argTypes = ListBuffer.<Type>lb().append(syms.intType).toList();
586 serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
587 ++i;
588 }
589 JCStatement stmt = make.If(
590 deserTest(deserTest(deserTest(deserTest(deserTest(
591 kindTest,
592 "getFunctionalInterfaceClass", functionalInterfaceClass),
593 "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
594 "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
595 "getImplClass", implClass),
596 "getImplMethodSignature", implMethodSignature),
597 make.Return(makeIndyCall(
598 pos,
599 syms.lambdaMetafactory,
600 names.altMetaFactory,
601 staticArgs, indyType, serArgs.toList())),
602 null);
603 ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
604 if (stmts == null) {
605 stmts = ListBuffer.lb();
606 kInfo.deserializeCases.put(implMethodName, stmts);
607 }
608 /****
609 System.err.printf("+++++++++++++++++\n");
610 System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
611 System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
612 System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
613 System.err.printf("*implMethodKind: %d\n", implMethodKind);
614 System.err.printf("*implClass: '%s'\n", implClass);
615 System.err.printf("*implMethodName: '%s'\n", implMethodName);
616 System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
617 ****/
618 stmts.append(stmt);
619 }
621 private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
622 JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
623 testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
624 testExpr.setType(syms.booleanType);
625 return testExpr;
626 }
628 private JCExpression deserTest(JCExpression prev, String func, String lit) {
629 MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
630 Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
631 JCMethodInvocation eqtest = make.Apply(
632 List.<JCExpression>nil(),
633 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
634 List.<JCExpression>of(make.Literal(lit)));
635 eqtest.setType(syms.booleanType);
636 JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
637 compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
638 compound.setType(syms.booleanType);
639 return compound;
640 }
642 private JCExpression deserGetter(String func, Type type) {
643 return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
644 }
646 private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
647 MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
648 Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
649 return make.Apply(
650 List.<JCExpression>nil(),
651 make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
652 args).setType(type);
653 }
655 /**
656 * Create new synthetic method with given flags, name, type, owner
657 */
658 private MethodSymbol makeSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
659 return new MethodSymbol(flags | SYNTHETIC, name, type, owner);
660 }
662 /**
663 * Create new synthetic variable with given flags, name, type, owner
664 */
665 private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
666 return makeSyntheticVar(flags, names.fromString(name), type, owner);
667 }
669 /**
670 * Create new synthetic variable with given flags, name, type, owner
671 */
672 private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
673 return new VarSymbol(flags | SYNTHETIC, name, type, owner);
674 }
676 /**
677 * Set varargsElement field on a given tree (must be either a new class tree
678 * or a method call tree)
679 */
680 private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
681 if (varargsElement != null) {
682 switch (tree.getTag()) {
683 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
684 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
685 default: throw new AssertionError();
686 }
687 }
688 }
690 /**
691 * Convert method/constructor arguments by inserting appropriate cast
692 * as required by type-erasure - this is needed when bridging a lambda/method
693 * reference, as the bridged signature might require downcast to be compatible
694 * with the generated signature.
695 */
696 private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
697 Assert.check(meth.kind == Kinds.MTH);
698 List<Type> formals = types.erasure(meth.type).getParameterTypes();
699 if (varargsElement != null) {
700 Assert.check((meth.flags() & VARARGS) != 0);
701 }
702 return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
703 }
705 // </editor-fold>
707 /**
708 * Generate an adapter method "bridge" for a method reference which cannot
709 * be used directly.
710 */
711 private class MemberReferenceBridger {
713 private final JCMemberReference tree;
714 private final ReferenceTranslationContext localContext;
715 private final ListBuffer<JCExpression> args = ListBuffer.lb();
716 private final ListBuffer<JCVariableDecl> params = ListBuffer.lb();
718 MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
719 this.tree = tree;
720 this.localContext = localContext;
721 }
723 /**
724 * Generate the bridge
725 */
726 JCMethodDecl bridge() {
727 int prevPos = make.pos;
728 try {
729 make.at(tree);
730 Type samDesc = localContext.bridgedRefSig();
731 List<Type> samPTypes = samDesc.getParameterTypes();
733 //an extra argument is prepended to the signature of the bridge in case
734 //the member reference is an instance method reference (in which case
735 //the receiver expression is passed to the bridge itself).
736 Type recType = null;
737 switch (tree.kind) {
738 case IMPLICIT_INNER:
739 recType = tree.sym.owner.type.getEnclosingType();
740 break;
741 case BOUND:
742 recType = tree.getQualifierExpression().type;
743 break;
744 case UNBOUND:
745 recType = samPTypes.head;
746 samPTypes = samPTypes.tail;
747 break;
748 }
750 //generate the parameter list for the bridged member reference - the
751 //bridge signature will match the signature of the target sam descriptor
753 VarSymbol rcvr = (recType == null)
754 ? null
755 : addParameter("rec$", recType, false);
757 List<Type> refPTypes = tree.sym.type.getParameterTypes();
758 int refSize = refPTypes.size();
759 int samSize = samPTypes.size();
760 // Last parameter to copy from referenced method
761 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
763 List<Type> l = refPTypes;
764 // Use parameter types of the referenced method, excluding final var args
765 for (int i = 0; l.nonEmpty() && i < last; ++i) {
766 addParameter("x$" + i, l.head, true);
767 l = l.tail;
768 }
769 // Flatten out the var args
770 for (int i = last; i < samSize; ++i) {
771 addParameter("xva$" + i, tree.varargsElement, true);
772 }
774 //generate the bridge method declaration
775 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
776 localContext.bridgeSym.name,
777 make.QualIdent(samDesc.getReturnType().tsym),
778 List.<JCTypeParameter>nil(),
779 params.toList(),
780 tree.sym.type.getThrownTypes() == null
781 ? List.<JCExpression>nil()
782 : make.Types(tree.sym.type.getThrownTypes()),
783 null,
784 null);
785 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
786 bridgeDecl.type = localContext.bridgeSym.type =
787 types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
789 //bridge method body generation - this can be either a method call or a
790 //new instance creation expression, depending on the member reference kind
791 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
792 ? bridgeExpressionInvoke(makeReceiver(rcvr))
793 : bridgeExpressionNew();
795 //the body is either a return expression containing a method call,
796 //or the method call itself, depending on whether the return type of
797 //the bridge is non-void/void.
798 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
800 return bridgeDecl;
801 } finally {
802 make.at(prevPos);
803 }
804 }
805 //where
806 private JCExpression makeReceiver(VarSymbol rcvr) {
807 if (rcvr == null) return null;
808 JCExpression rcvrExpr = make.Ident(rcvr);
809 Type rcvrType = tree.sym.enclClass().type;
810 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
811 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
812 }
813 return rcvrExpr;
814 }
816 /**
817 * determine the receiver of the bridged method call - the receiver can
818 * be either the synthetic receiver parameter or a type qualifier; the
819 * original qualifier expression is never used here, as it might refer
820 * to symbols not available in the static context of the bridge
821 */
822 private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
823 JCExpression qualifier =
824 tree.sym.isStatic() ?
825 make.Type(tree.sym.owner.type) :
826 (rcvr != null) ?
827 rcvr :
828 tree.getQualifierExpression();
830 //create the qualifier expression
831 JCFieldAccess select = make.Select(qualifier, tree.sym.name);
832 select.sym = tree.sym;
833 select.type = tree.sym.erasure(types);
835 //create the method call expression
836 JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
837 convertArgs(tree.sym, args.toList(), tree.varargsElement)).
838 setType(tree.sym.erasure(types).getReturnType());
840 apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
841 setVarargsIfNeeded(apply, tree.varargsElement);
842 return apply;
843 }
845 /**
846 * the enclosing expression is either 'null' (no enclosing type) or set
847 * to the first bridge synthetic parameter
848 */
849 private JCExpression bridgeExpressionNew() {
850 if (tree.kind == ReferenceKind.ARRAY_CTOR) {
851 //create the array creation expression
852 JCNewArray newArr = make.NewArray(
853 make.Type(types.elemtype(tree.getQualifierExpression().type)),
854 List.of(make.Ident(params.first())),
855 null);
856 newArr.type = tree.getQualifierExpression().type;
857 return newArr;
858 } else {
859 JCExpression encl = null;
860 switch (tree.kind) {
861 case UNBOUND:
862 case IMPLICIT_INNER:
863 encl = make.Ident(params.first());
864 }
866 //create the instance creation expression
867 JCNewClass newClass = make.NewClass(encl,
868 List.<JCExpression>nil(),
869 make.Type(tree.getQualifierExpression().type),
870 convertArgs(tree.sym, args.toList(), tree.varargsElement),
871 null);
872 newClass.constructor = tree.sym;
873 newClass.constructorType = tree.sym.erasure(types);
874 newClass.type = tree.getQualifierExpression().type;
875 setVarargsIfNeeded(newClass, tree.varargsElement);
876 return newClass;
877 }
878 }
880 private VarSymbol addParameter(String name, Type p, boolean genArg) {
881 VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
882 params.append(make.VarDef(vsym, null));
883 if (genArg) {
884 args.append(make.Ident(vsym));
885 }
886 return vsym;
887 }
888 }
890 /**
891 * Bridges a member reference - this is needed when:
892 * * Var args in the referenced method need to be flattened away
893 * * super is used
894 */
895 private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
896 kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
897 }
899 /**
900 * Generate an indy method call to the meta factory
901 */
902 private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory,
903 boolean isSerializable, int refKind, Symbol refSym, List<JCExpression> indy_args) {
904 //determine the static bsm args
905 Type mtype = types.erasure(tree.descriptorType);
906 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
907 List<Object> staticArgs = List.<Object>of(
908 new Pool.MethodHandle(ClassFile.REF_invokeInterface,
909 types.findDescriptorSymbol(tree.type.tsym), types),
910 new Pool.MethodHandle(refKind, refSym, types),
911 new MethodType(mtype.getParameterTypes(),
912 mtype.getReturnType(),
913 mtype.getThrownTypes(),
914 syms.methodClass));
916 //computed indy arg types
917 ListBuffer<Type> indy_args_types = ListBuffer.lb();
918 for (JCExpression arg : indy_args) {
919 indy_args_types.append(arg.type);
920 }
922 //finally, compute the type of the indy call
923 MethodType indyType = new MethodType(indy_args_types.toList(),
924 tree.type,
925 List.<Type>nil(),
926 syms.methodClass);
928 Name metafactoryName = needsAltMetafactory ?
929 names.altMetaFactory : names.metaFactory;
931 if (needsAltMetafactory) {
932 ListBuffer<Object> markers = ListBuffer.lb();
933 for (Symbol t : tree.targets.tail) {
934 if (t != syms.serializableType.tsym) {
935 markers.append(t);
936 }
937 }
938 int flags = isSerializable? FLAG_SERIALIZABLE : 0;
939 boolean hasMarkers = markers.nonEmpty();
940 flags |= hasMarkers ? FLAG_MARKERS : 0;
941 staticArgs = staticArgs.append(flags);
942 if (hasMarkers) {
943 staticArgs = staticArgs.append(markers.length());
944 staticArgs = staticArgs.appendList(markers.toList());
945 }
946 if (isSerializable) {
947 addDeserializationCase(refKind, refSym, tree.type, samSym,
948 tree, staticArgs, indyType);
949 }
950 }
952 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
953 }
955 /**
956 * Generate an indy method call with given name, type and static bootstrap
957 * arguments types
958 */
959 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
960 List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
961 int prevPos = make.pos;
962 try {
963 make.at(pos);
964 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
965 syms.stringType,
966 syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
968 Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
969 bsmName, bsm_staticArgs, List.<Type>nil());
971 DynamicMethodSymbol dynSym =
972 new DynamicMethodSymbol(names.lambda,
973 syms.noSymbol,
974 bsm.isStatic() ?
975 ClassFile.REF_invokeStatic :
976 ClassFile.REF_invokeVirtual,
977 (MethodSymbol)bsm,
978 indyType,
979 staticArgs.toArray());
981 JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
982 qualifier.sym = dynSym;
983 qualifier.type = indyType.getReturnType();
985 JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
986 proxyCall.type = indyType.getReturnType();
987 return proxyCall;
988 } finally {
989 make.at(prevPos);
990 }
991 }
992 //where
993 private List<Type> bsmStaticArgToTypes(List<Object> args) {
994 ListBuffer<Type> argtypes = ListBuffer.lb();
995 for (Object arg : args) {
996 argtypes.append(bsmStaticArgToType(arg));
997 }
998 return argtypes.toList();
999 }
1001 private Type bsmStaticArgToType(Object arg) {
1002 Assert.checkNonNull(arg);
1003 if (arg instanceof ClassSymbol) {
1004 return syms.classType;
1005 } else if (arg instanceof Integer) {
1006 return syms.intType;
1007 } else if (arg instanceof Long) {
1008 return syms.longType;
1009 } else if (arg instanceof Float) {
1010 return syms.floatType;
1011 } else if (arg instanceof Double) {
1012 return syms.doubleType;
1013 } else if (arg instanceof String) {
1014 return syms.stringType;
1015 } else if (arg instanceof Pool.MethodHandle) {
1016 return syms.methodHandleType;
1017 } else if (arg instanceof MethodType) {
1018 return syms.methodTypeType;
1019 } else {
1020 Assert.error("bad static arg " + arg.getClass());
1021 return null;
1022 }
1023 }
1025 /**
1026 * Get the opcode associated with this method reference
1027 */
1028 private int referenceKind(Symbol refSym) {
1029 if (refSym.isConstructor()) {
1030 return ClassFile.REF_newInvokeSpecial;
1031 } else {
1032 if (refSym.isStatic()) {
1033 return ClassFile.REF_invokeStatic;
1034 } else if (refSym.enclClass().isInterface()) {
1035 return ClassFile.REF_invokeInterface;
1036 } else {
1037 return (refSym.flags() & PRIVATE) != 0 ?
1038 ClassFile.REF_invokeSpecial :
1039 ClassFile.REF_invokeVirtual;
1040 }
1041 }
1042 }
1044 // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1045 /**
1046 * This visitor collects information about translation of a lambda expression.
1047 * More specifically, it keeps track of the enclosing contexts and captured locals
1048 * accessed by the lambda being translated (as well as other useful info).
1049 * It also translates away problems for LambdaToMethod.
1050 */
1051 class LambdaAnalyzerPreprocessor extends TreeTranslator {
1053 /** the frame stack - used to reconstruct translation info about enclosing scopes */
1054 private List<Frame> frameStack;
1056 /**
1057 * keep the count of lambda expression (used to generate unambiguous
1058 * names)
1059 */
1060 private int lambdaCount = 0;
1062 /**
1063 * keep the count of lambda expression defined in given context (used to
1064 * generate unambiguous names for serializable lambdas)
1065 */
1066 private Map<String, Integer> serializableLambdaCounts =
1067 new HashMap<String, Integer>();
1069 private Map<Symbol, JCClassDecl> localClassDefs;
1071 /**
1072 * maps for fake clinit symbols to be used as owners of lambda occurring in
1073 * a static var init context
1074 */
1075 private Map<ClassSymbol, Symbol> clinits =
1076 new HashMap<ClassSymbol, Symbol>();
1078 private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
1079 frameStack = List.nil();
1080 localClassDefs = new HashMap<Symbol, JCClassDecl>();
1081 return translate(tree);
1082 }
1084 @Override
1085 public void visitBlock(JCBlock tree) {
1086 List<Frame> prevStack = frameStack;
1087 try {
1088 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
1089 frameStack = frameStack.prepend(new Frame(tree));
1090 }
1091 super.visitBlock(tree);
1092 }
1093 finally {
1094 frameStack = prevStack;
1095 }
1096 }
1098 @Override
1099 public void visitClassDef(JCClassDecl tree) {
1100 List<Frame> prevStack = frameStack;
1101 Map<String, Integer> prevSerializableLambdaCount =
1102 serializableLambdaCounts;
1103 Map<ClassSymbol, Symbol> prevClinits = clinits;
1104 try {
1105 serializableLambdaCounts = new HashMap<String, Integer>();
1106 prevClinits = new HashMap<ClassSymbol, Symbol>();
1107 if (tree.sym.owner.kind == MTH) {
1108 localClassDefs.put(tree.sym, tree);
1109 }
1110 if (directlyEnclosingLambda() != null) {
1111 tree.sym.owner = owner();
1112 if (tree.sym.hasOuterInstance()) {
1113 //if a class is defined within a lambda, the lambda must capture
1114 //its enclosing instance (if any)
1115 TranslationContext<?> localContext = context();
1116 while (localContext != null) {
1117 if (localContext.tree.getTag() == LAMBDA) {
1118 ((LambdaTranslationContext)localContext)
1119 .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
1120 }
1121 localContext = localContext.prev;
1122 }
1123 }
1124 }
1125 frameStack = frameStack.prepend(new Frame(tree));
1126 super.visitClassDef(tree);
1127 }
1128 finally {
1129 frameStack = prevStack;
1130 serializableLambdaCounts = prevSerializableLambdaCount;
1131 clinits = prevClinits;
1132 }
1133 }
1135 @Override
1136 public void visitIdent(JCIdent tree) {
1137 if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
1138 if (tree.sym.kind == VAR &&
1139 tree.sym.owner.kind == MTH &&
1140 tree.type.constValue() == null) {
1141 TranslationContext<?> localContext = context();
1142 while (localContext != null) {
1143 if (localContext.tree.getTag() == LAMBDA) {
1144 JCTree block = capturedDecl(localContext.depth, tree.sym);
1145 if (block == null) break;
1146 ((LambdaTranslationContext)localContext)
1147 .addSymbol(tree.sym, CAPTURED_VAR);
1148 }
1149 localContext = localContext.prev;
1150 }
1151 } else if (tree.sym.owner.kind == TYP) {
1152 TranslationContext<?> localContext = context();
1153 while (localContext != null) {
1154 if (localContext.tree.hasTag(LAMBDA)) {
1155 JCTree block = capturedDecl(localContext.depth, tree.sym);
1156 if (block == null) break;
1157 switch (block.getTag()) {
1158 case CLASSDEF:
1159 JCClassDecl cdecl = (JCClassDecl)block;
1160 ((LambdaTranslationContext)localContext)
1161 .addSymbol(cdecl.sym, CAPTURED_THIS);
1162 break;
1163 default:
1164 Assert.error("bad block kind");
1165 }
1166 }
1167 localContext = localContext.prev;
1168 }
1169 }
1170 }
1171 super.visitIdent(tree);
1172 }
1174 @Override
1175 public void visitLambda(JCLambda tree) {
1176 List<Frame> prevStack = frameStack;
1177 try {
1178 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
1179 frameStack = frameStack.prepend(new Frame(tree));
1180 for (JCVariableDecl param : tree.params) {
1181 context.addSymbol(param.sym, PARAM);
1182 frameStack.head.addLocal(param.sym);
1183 }
1184 contextMap.put(tree, context);
1185 super.visitLambda(tree);
1186 context.complete();
1187 }
1188 finally {
1189 frameStack = prevStack;
1190 }
1191 }
1193 @Override
1194 public void visitMethodDef(JCMethodDecl tree) {
1195 List<Frame> prevStack = frameStack;
1196 try {
1197 frameStack = frameStack.prepend(new Frame(tree));
1198 super.visitMethodDef(tree);
1199 }
1200 finally {
1201 frameStack = prevStack;
1202 }
1203 }
1205 @Override
1206 public void visitNewClass(JCNewClass tree) {
1207 if (lambdaNewClassFilter(context(), tree)) {
1208 TranslationContext<?> localContext = context();
1209 while (localContext != null) {
1210 if (localContext.tree.getTag() == LAMBDA) {
1211 ((LambdaTranslationContext)localContext)
1212 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
1213 }
1214 localContext = localContext.prev;
1215 }
1216 }
1217 if (context() != null && tree.type.tsym.owner.kind == MTH) {
1218 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
1219 captureLocalClassDefs(tree.type.tsym, lambdaContext);
1220 }
1221 super.visitNewClass(tree);
1222 }
1223 //where
1224 void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
1225 JCClassDecl localCDef = localClassDefs.get(csym);
1226 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
1227 BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
1228 @Override
1229 void addFreeVars(ClassSymbol c) {
1230 captureLocalClassDefs(c, lambdaContext);
1231 }
1232 @Override
1233 void visitSymbol(Symbol sym) {
1234 if (sym.kind == VAR &&
1235 sym.owner.kind == MTH &&
1236 ((VarSymbol)sym).getConstValue() == null) {
1237 TranslationContext<?> localContext = context();
1238 while (localContext != null) {
1239 if (localContext.tree.getTag() == LAMBDA) {
1240 JCTree block = capturedDecl(localContext.depth, sym);
1241 if (block == null) break;
1242 ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
1243 }
1244 localContext = localContext.prev;
1245 }
1246 }
1247 }
1248 };
1249 fvc.scan(localCDef);
1250 }
1251 }
1253 /**
1254 * Method references to local class constructors, may, if the local
1255 * class references local variables, have implicit constructor
1256 * parameters added in Lower; As a result, the invokedynamic bootstrap
1257 * information added in the LambdaToMethod pass will have the wrong
1258 * signature. Hooks between Lower and LambdaToMethod have been added to
1259 * handle normal "new" in this case. This visitor converts potentially
1260 * effected method references into a lambda containing a normal "new" of
1261 * the class.
1262 *
1263 * @param tree
1264 */
1265 @Override
1266 public void visitReference(JCMemberReference tree) {
1267 if (tree.getMode() == ReferenceMode.NEW
1268 && tree.kind != ReferenceKind.ARRAY_CTOR
1269 && tree.sym.owner.isLocal()) {
1270 MethodSymbol consSym = (MethodSymbol) tree.sym;
1271 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
1272 Type classType = consSym.owner.type;
1274 // Build lambda parameters
1275 // partially cloned from TreeMaker.Params until 8014021 is fixed
1276 Symbol owner = owner();
1277 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
1278 int i = 0;
1279 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
1280 paramBuff.append(make.Param(make.paramName(i++), l.head, owner));
1281 }
1282 List<JCVariableDecl> params = paramBuff.toList();
1284 // Make new-class call
1285 JCNewClass nc = makeNewClass(classType, make.Idents(params));
1286 nc.pos = tree.pos;
1288 // Make lambda holding the new-class call
1289 JCLambda slam = make.Lambda(params, nc);
1290 slam.descriptorType = tree.descriptorType;
1291 slam.targets = tree.targets;
1292 slam.type = tree.type;
1293 slam.pos = tree.pos;
1295 // Now it is a lambda, process as such
1296 visitLambda(slam);
1297 } else {
1298 super.visitReference(tree);
1299 contextMap.put(tree, makeReferenceContext(tree));
1300 }
1301 }
1303 @Override
1304 public void visitSelect(JCFieldAccess tree) {
1305 if (context() != null && tree.sym.kind == VAR &&
1306 (tree.sym.name == names._this ||
1307 tree.sym.name == names._super)) {
1308 // A select of this or super means, if we are in a lambda,
1309 // we much have an instance context
1310 TranslationContext<?> localContext = context();
1311 while (localContext != null) {
1312 if (localContext.tree.hasTag(LAMBDA)) {
1313 JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
1314 if (clazz == null) break;
1315 ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
1316 }
1317 localContext = localContext.prev;
1318 }
1319 }
1320 super.visitSelect(tree);
1321 }
1323 @Override
1324 public void visitVarDef(JCVariableDecl tree) {
1325 TranslationContext<?> context = context();
1326 LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
1327 (LambdaTranslationContext)context :
1328 null;
1329 if (ltc != null) {
1330 if (frameStack.head.tree.hasTag(LAMBDA)) {
1331 ltc.addSymbol(tree.sym, LOCAL_VAR);
1332 }
1333 // Check for type variables (including as type arguments).
1334 // If they occur within class nested in a lambda, mark for erasure
1335 Type type = tree.sym.asType();
1336 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
1337 ltc.addSymbol(tree.sym, TYPE_VAR);
1338 }
1339 }
1341 List<Frame> prevStack = frameStack;
1342 try {
1343 if (tree.sym.owner.kind == MTH) {
1344 frameStack.head.addLocal(tree.sym);
1345 }
1346 frameStack = frameStack.prepend(new Frame(tree));
1347 super.visitVarDef(tree);
1348 }
1349 finally {
1350 frameStack = prevStack;
1351 }
1352 }
1354 private Name lambdaName() {
1355 return names.lambda.append(names.fromString("" + lambdaCount++));
1356 }
1358 /**
1359 * For a serializable lambda, generate a name which maximizes name
1360 * stability across deserialization.
1361 * @param owner
1362 * @return Name to use for the synthetic lambda method name
1363 */
1364 private Name serializedLambdaName(Symbol owner) {
1365 StringBuilder buf = new StringBuilder();
1366 buf.append(names.lambda);
1367 // Append the name of the method enclosing the lambda.
1368 String methodName = owner.name.toString();
1369 if (methodName.equals("<clinit>"))
1370 methodName = "static";
1371 else if (methodName.equals("<init>"))
1372 methodName = "new";
1373 buf.append(methodName);
1374 buf.append('$');
1375 // Append a hash of the enclosing method signature to differentiate
1376 // overloaded enclosing methods. For lambdas enclosed in lambdas,
1377 // the generated lambda method will not have type yet, but the
1378 // enclosing method's name will have been generated with this same
1379 // method, so it will be unique and never be overloaded.
1380 Assert.check(owner.type != null || directlyEnclosingLambda() != null);
1381 if (owner.type != null) {
1382 int methTypeHash = methodSig(owner.type).hashCode();
1383 buf.append(Integer.toHexString(methTypeHash));
1384 }
1385 buf.append('$');
1386 // The above appended name components may not be unique, append a
1387 // count based on the above name components.
1388 String temp = buf.toString();
1389 Integer count = serializableLambdaCounts.get(temp);
1390 if (count == null) {
1391 count = 0;
1392 }
1393 buf.append(count++);
1394 serializableLambdaCounts.put(temp, count);
1395 return names.fromString(buf.toString());
1396 }
1398 /**
1399 * Return a valid owner given the current declaration stack
1400 * (required to skip synthetic lambda symbols)
1401 */
1402 private Symbol owner() {
1403 return owner(false);
1404 }
1406 @SuppressWarnings("fallthrough")
1407 private Symbol owner(boolean skipLambda) {
1408 List<Frame> frameStack2 = frameStack;
1409 while (frameStack2.nonEmpty()) {
1410 switch (frameStack2.head.tree.getTag()) {
1411 case VARDEF:
1412 if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
1413 frameStack2 = frameStack2.tail;
1414 break;
1415 }
1416 JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
1417 return initSym(cdecl.sym,
1418 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
1419 case BLOCK:
1420 JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
1421 return initSym(cdecl2.sym,
1422 ((JCBlock)frameStack2.head.tree).flags & STATIC);
1423 case CLASSDEF:
1424 return ((JCClassDecl)frameStack2.head.tree).sym;
1425 case METHODDEF:
1426 return ((JCMethodDecl)frameStack2.head.tree).sym;
1427 case LAMBDA:
1428 if (!skipLambda)
1429 return ((LambdaTranslationContext)contextMap
1430 .get(frameStack2.head.tree)).translatedSym;
1431 default:
1432 frameStack2 = frameStack2.tail;
1433 }
1434 }
1435 Assert.error();
1436 return null;
1437 }
1439 private Symbol initSym(ClassSymbol csym, long flags) {
1440 boolean isStatic = (flags & STATIC) != 0;
1441 if (isStatic) {
1442 //static clinits are generated in Gen - so we need to fake them
1443 Symbol clinit = clinits.get(csym);
1444 if (clinit == null) {
1445 clinit = makeSyntheticMethod(STATIC,
1446 names.clinit,
1447 new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
1448 csym);
1449 clinits.put(csym, clinit);
1450 }
1451 return clinit;
1452 } else {
1453 //get the first constructor and treat it as the instance init sym
1454 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
1455 return s;
1456 }
1457 }
1458 Assert.error("init not found");
1459 return null;
1460 }
1462 private JCTree directlyEnclosingLambda() {
1463 if (frameStack.isEmpty()) {
1464 return null;
1465 }
1466 List<Frame> frameStack2 = frameStack;
1467 while (frameStack2.nonEmpty()) {
1468 switch (frameStack2.head.tree.getTag()) {
1469 case CLASSDEF:
1470 case METHODDEF:
1471 return null;
1472 case LAMBDA:
1473 return frameStack2.head.tree;
1474 default:
1475 frameStack2 = frameStack2.tail;
1476 }
1477 }
1478 Assert.error();
1479 return null;
1480 }
1482 private boolean inClassWithinLambda() {
1483 if (frameStack.isEmpty()) {
1484 return false;
1485 }
1486 List<Frame> frameStack2 = frameStack;
1487 boolean classFound = false;
1488 while (frameStack2.nonEmpty()) {
1489 switch (frameStack2.head.tree.getTag()) {
1490 case LAMBDA:
1491 return classFound;
1492 case CLASSDEF:
1493 classFound = true;
1494 frameStack2 = frameStack2.tail;
1495 break;
1496 default:
1497 frameStack2 = frameStack2.tail;
1498 }
1499 }
1500 // No lambda
1501 return false;
1502 }
1504 /**
1505 * Return the declaration corresponding to a symbol in the enclosing
1506 * scope; the depth parameter is used to filter out symbols defined
1507 * in nested scopes (which do not need to undergo capture).
1508 */
1509 private JCTree capturedDecl(int depth, Symbol sym) {
1510 int currentDepth = frameStack.size() - 1;
1511 for (Frame block : frameStack) {
1512 switch (block.tree.getTag()) {
1513 case CLASSDEF:
1514 ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
1515 if (sym.isMemberOf(clazz, types)) {
1516 return currentDepth > depth ? null : block.tree;
1517 }
1518 break;
1519 case VARDEF:
1520 if (((JCVariableDecl)block.tree).sym == sym &&
1521 sym.owner.kind == MTH) { //only locals are captured
1522 return currentDepth > depth ? null : block.tree;
1523 }
1524 break;
1525 case BLOCK:
1526 case METHODDEF:
1527 case LAMBDA:
1528 if (block.locals != null && block.locals.contains(sym)) {
1529 return currentDepth > depth ? null : block.tree;
1530 }
1531 break;
1532 default:
1533 Assert.error("bad decl kind " + block.tree.getTag());
1534 }
1535 currentDepth--;
1536 }
1537 return null;
1538 }
1540 private TranslationContext<?> context() {
1541 for (Frame frame : frameStack) {
1542 TranslationContext<?> context = contextMap.get(frame.tree);
1543 if (context != null) {
1544 return context;
1545 }
1546 }
1547 return null;
1548 }
1550 /**
1551 * This is used to filter out those identifiers that needs to be adjusted
1552 * when translating away lambda expressions
1553 */
1554 private boolean lambdaIdentSymbolFilter(Symbol sym) {
1555 return (sym.kind == VAR || sym.kind == MTH)
1556 && !sym.isStatic()
1557 && sym.name != names.init;
1558 }
1560 /**
1561 * This is used to filter out those new class expressions that need to
1562 * be qualified with an enclosing tree
1563 */
1564 private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
1565 if (context != null
1566 && tree.encl == null
1567 && tree.def == null
1568 && !tree.type.getEnclosingType().hasTag(NONE)) {
1569 Type encl = tree.type.getEnclosingType();
1570 Type current = context.owner.enclClass().type;
1571 while (!current.hasTag(NONE)) {
1572 if (current.tsym.isSubClass(encl.tsym, types)) {
1573 return true;
1574 }
1575 current = current.getEnclosingType();
1576 }
1577 return false;
1578 } else {
1579 return false;
1580 }
1581 }
1583 private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
1584 return new LambdaTranslationContext(tree);
1585 }
1587 private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
1588 return new ReferenceTranslationContext(tree);
1589 }
1591 private class Frame {
1592 final JCTree tree;
1593 List<Symbol> locals;
1595 public Frame(JCTree tree) {
1596 this.tree = tree;
1597 }
1599 void addLocal(Symbol sym) {
1600 if (locals == null) {
1601 locals = List.nil();
1602 }
1603 locals = locals.prepend(sym);
1604 }
1605 }
1607 /**
1608 * This class is used to store important information regarding translation of
1609 * lambda expression/method references (see subclasses).
1610 */
1611 private abstract class TranslationContext<T extends JCFunctionalExpression> {
1613 /** the underlying (untranslated) tree */
1614 T tree;
1616 /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
1617 Symbol owner;
1619 /** the depth of this lambda expression in the frame stack */
1620 int depth;
1622 /** the enclosing translation context (set for nested lambdas/mref) */
1623 TranslationContext<?> prev;
1625 TranslationContext(T tree) {
1626 this.tree = tree;
1627 this.owner = owner();
1628 this.depth = frameStack.size() - 1;
1629 this.prev = context();
1630 }
1632 /** does this functional expression need to be created using alternate metafactory? */
1633 boolean needsAltMetafactory() {
1634 return (tree.targets.length() > 1 ||
1635 isSerializable());
1636 }
1638 /** does this functional expression require serialization support? */
1639 boolean isSerializable() {
1640 for (Symbol target : tree.targets) {
1641 if (types.asSuper(target.type, syms.serializableType.tsym) != null) {
1642 return true;
1643 }
1644 }
1645 return false;
1646 }
1647 }
1649 /**
1650 * This class retains all the useful information about a lambda expression;
1651 * the contents of this class are filled by the LambdaAnalyzer visitor,
1652 * and the used by the main translation routines in order to adjust references
1653 * to captured locals/members, etc.
1654 */
1655 private class LambdaTranslationContext extends TranslationContext<JCLambda> {
1657 /** variable in the enclosing context to which this lambda is assigned */
1658 Symbol self;
1660 /** map from original to translated lambda parameters */
1661 Map<Symbol, Symbol> lambdaParams = new LinkedHashMap<Symbol, Symbol>();
1663 /** map from original to translated lambda locals */
1664 Map<Symbol, Symbol> lambdaLocals = new LinkedHashMap<Symbol, Symbol>();
1666 /** map from variables in enclosing scope to translated synthetic parameters */
1667 Map<Symbol, Symbol> capturedLocals = new LinkedHashMap<Symbol, Symbol>();
1669 /** map from class symbols to translated synthetic parameters (for captured member access) */
1670 Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>();
1672 /** map from original to translated lambda locals */
1673 Map<Symbol, Symbol> typeVars = new LinkedHashMap<Symbol, Symbol>();
1675 /** the synthetic symbol for the method hoisting the translated lambda */
1676 Symbol translatedSym;
1678 List<JCVariableDecl> syntheticParams;
1680 LambdaTranslationContext(JCLambda tree) {
1681 super(tree);
1682 Frame frame = frameStack.head;
1683 if (frame.tree.hasTag(VARDEF)) {
1684 self = ((JCVariableDecl)frame.tree).sym;
1685 }
1686 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName();
1687 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass());
1688 }
1690 /**
1691 * Translate a symbol of a given kind into something suitable for the
1692 * synthetic lambda body
1693 */
1694 Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
1695 Symbol ret;
1696 switch (skind) {
1697 case CAPTURED_THIS:
1698 ret = sym; // self represented
1699 break;
1700 case TYPE_VAR:
1701 // Just erase the type var
1702 ret = new VarSymbol(sym.flags(), name,
1703 types.erasure(sym.type), sym.owner);
1704 break;
1705 case CAPTURED_VAR:
1706 ret = new VarSymbol(SYNTHETIC | FINAL, name, types.erasure(sym.type), translatedSym) {
1707 @Override
1708 public Symbol baseSymbol() {
1709 //keep mapping with original captured symbol
1710 return sym;
1711 }
1712 };
1713 break;
1714 default:
1715 ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
1716 }
1717 if (ret != sym) {
1718 ret.annotations.setDeclarationAttributes(sym.getRawAttributes());
1719 ret.annotations.setTypeAttributes(sym.getRawTypeAttributes());
1720 }
1721 return ret;
1722 }
1724 void addSymbol(Symbol sym, LambdaSymbolKind skind) {
1725 Map<Symbol, Symbol> transMap = null;
1726 Name preferredName;
1727 switch (skind) {
1728 case CAPTURED_THIS:
1729 transMap = capturedThis;
1730 preferredName = names.fromString("encl$" + capturedThis.size());
1731 break;
1732 case CAPTURED_VAR:
1733 transMap = capturedLocals;
1734 preferredName = names.fromString("cap$" + capturedLocals.size());
1735 break;
1736 case LOCAL_VAR:
1737 transMap = lambdaLocals;
1738 preferredName = sym.name;
1739 break;
1740 case PARAM:
1741 transMap = lambdaParams;
1742 preferredName = sym.name;
1743 break;
1744 case TYPE_VAR:
1745 transMap = typeVars;
1746 preferredName = sym.name;
1747 break;
1748 default: throw new AssertionError();
1749 }
1750 if (!transMap.containsKey(sym)) {
1751 transMap.put(sym, translate(preferredName, sym, skind));
1752 }
1753 }
1755 Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind... skinds) {
1756 LinkedHashMap<Symbol, Symbol> translationMap = new LinkedHashMap<Symbol, Symbol>();
1757 for (LambdaSymbolKind skind : skinds) {
1758 switch (skind) {
1759 case CAPTURED_THIS:
1760 translationMap.putAll(capturedThis);
1761 break;
1762 case CAPTURED_VAR:
1763 translationMap.putAll(capturedLocals);
1764 break;
1765 case LOCAL_VAR:
1766 translationMap.putAll(lambdaLocals);
1767 break;
1768 case PARAM:
1769 translationMap.putAll(lambdaParams);
1770 break;
1771 case TYPE_VAR:
1772 translationMap.putAll(typeVars);
1773 break;
1774 default: throw new AssertionError();
1775 }
1776 }
1777 return translationMap;
1778 }
1780 /**
1781 * The translatedSym is not complete/accurate until the analysis is
1782 * finished. Once the analysis is finished, the translatedSym is
1783 * "completed" -- updated with type information, access modifiers,
1784 * and full parameter list.
1785 */
1786 void complete() {
1787 if (syntheticParams != null) {
1788 return;
1789 }
1790 boolean inInterface = translatedSym.owner.isInterface();
1791 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
1793 // If instance access isn't needed, make it static.
1794 // Interface instance methods must be default methods.
1795 // Awaiting VM channges, default methods are public
1796 translatedSym.flags_field = SYNTHETIC |
1797 ((inInterface && thisReferenced)? PUBLIC : PRIVATE) |
1798 (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
1800 //compute synthetic params
1801 ListBuffer<JCVariableDecl> params = ListBuffer.lb();
1803 // The signature of the method is augmented with the following
1804 // synthetic parameters:
1805 //
1806 // 1) reference to enclosing contexts captured by the lambda expression
1807 // 2) enclosing locals captured by the lambda expression
1808 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR, PARAM).values()) {
1809 params.append(make.VarDef((VarSymbol) thisSym, null));
1810 }
1812 syntheticParams = params.toList();
1814 //prepend synthetic args to translated lambda method signature
1815 translatedSym.type = types.createMethodTypeWithParameters(
1816 generatedLambdaSig(),
1817 TreeInfo.types(syntheticParams));
1818 }
1820 Type generatedLambdaSig() {
1821 return types.erasure(tree.descriptorType);
1822 }
1823 }
1825 /**
1826 * This class retains all the useful information about a method reference;
1827 * the contents of this class are filled by the LambdaAnalyzer visitor,
1828 * and the used by the main translation routines in order to adjust method
1829 * references (i.e. in case a bridge is needed)
1830 */
1831 private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
1833 final boolean isSuper;
1834 final Symbol bridgeSym;
1836 ReferenceTranslationContext(JCMemberReference tree) {
1837 super(tree);
1838 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
1839 this.bridgeSym = needsBridge()
1840 ? makeSyntheticMethod(isSuper ? 0 : STATIC,
1841 lambdaName().append(names.fromString("$bridge")), null,
1842 owner.enclClass())
1843 : null;
1844 }
1846 /**
1847 * Get the opcode associated with this method reference
1848 */
1849 int referenceKind() {
1850 return LambdaToMethod.this.referenceKind(needsBridge() ? bridgeSym : tree.sym);
1851 }
1853 boolean needsVarArgsConversion() {
1854 return tree.varargsElement != null;
1855 }
1857 /**
1858 * @return Is this an array operation like clone()
1859 */
1860 boolean isArrayOp() {
1861 return tree.sym.owner == syms.arrayClass;
1862 }
1864 boolean isPrivateConstructor() {
1865 //hack needed to workaround 292 bug (8005122)
1866 //when 292 issue is fixed we should simply remove this
1867 return tree.sym.name == names.init &&
1868 (tree.sym.flags() & PRIVATE) != 0;
1869 }
1871 boolean receiverAccessible() {
1872 //hack needed to workaround 292 bug (7087658)
1873 //when 292 issue is fixed we should remove this and change the backend
1874 //code to always generate a method handle to an accessible method
1875 return tree.ownerAccessible;
1876 }
1878 /**
1879 * Does this reference needs a bridge (i.e. var args need to be
1880 * expanded or "super" is used)
1881 */
1882 final boolean needsBridge() {
1883 return isSuper || needsVarArgsConversion() || isArrayOp() ||
1884 isPrivateConstructor() || !receiverAccessible();
1885 }
1887 Type generatedRefSig() {
1888 return types.erasure(tree.sym.type);
1889 }
1891 Type bridgedRefSig() {
1892 return types.erasure(types.findDescriptorSymbol(tree.targets.head).type);
1893 }
1894 }
1895 }
1896 // </editor-fold>
1898 enum LambdaSymbolKind {
1899 CAPTURED_VAR,
1900 CAPTURED_THIS,
1901 LOCAL_VAR,
1902 PARAM,
1903 TYPE_VAR;
1904 }
1906 /**
1907 * ****************************************************************
1908 * Signature Generation
1909 * ****************************************************************
1910 */
1912 private String methodSig(Type type) {
1913 L2MSignatureGenerator sg = new L2MSignatureGenerator();
1914 sg.assembleSig(type);
1915 return sg.toString();
1916 }
1918 private String classSig(Type type) {
1919 L2MSignatureGenerator sg = new L2MSignatureGenerator();
1920 sg.assembleClassSig(type);
1921 return sg.toString();
1922 }
1924 /**
1925 * Signature Generation
1926 */
1927 private class L2MSignatureGenerator extends Types.SignatureGenerator {
1929 /**
1930 * An output buffer for type signatures.
1931 */
1932 StringBuilder sb = new StringBuilder();
1934 L2MSignatureGenerator() {
1935 super(types);
1936 }
1938 @Override
1939 protected void append(char ch) {
1940 sb.append(ch);
1941 }
1943 @Override
1944 protected void append(byte[] ba) {
1945 sb.append(new String(ba));
1946 }
1948 @Override
1949 protected void append(Name name) {
1950 sb.append(name.toString());
1951 }
1953 @Override
1954 public String toString() {
1955 return sb.toString();
1956 }
1957 }
1958 }