src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java

changeset 1587
f1f605f85850
parent 1515
b61e5f801f7c
child 1595
d686d8a7eb78
equal deleted inserted replaced
1586:9fb4f223a90d 1587:f1f605f85850
29 import com.sun.tools.javac.tree.JCTree.*; 29 import com.sun.tools.javac.tree.JCTree.*;
30 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; 30 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
31 import com.sun.tools.javac.tree.TreeMaker; 31 import com.sun.tools.javac.tree.TreeMaker;
32 import com.sun.tools.javac.tree.TreeScanner; 32 import com.sun.tools.javac.tree.TreeScanner;
33 import com.sun.tools.javac.tree.TreeTranslator; 33 import com.sun.tools.javac.tree.TreeTranslator;
34 import com.sun.tools.javac.code.Flags;
35 import com.sun.tools.javac.code.Kinds; 34 import com.sun.tools.javac.code.Kinds;
35 import com.sun.tools.javac.code.Scope;
36 import com.sun.tools.javac.code.Symbol; 36 import com.sun.tools.javac.code.Symbol;
37 import com.sun.tools.javac.code.Symbol.ClassSymbol; 37 import com.sun.tools.javac.code.Symbol.ClassSymbol;
38 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; 38 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
39 import com.sun.tools.javac.code.Symbol.MethodSymbol; 39 import com.sun.tools.javac.code.Symbol.MethodSymbol;
40 import com.sun.tools.javac.code.Symbol.VarSymbol; 40 import com.sun.tools.javac.code.Symbol.VarSymbol;
55 import java.util.Map; 55 import java.util.Map;
56 56
57 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*; 57 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
58 import static com.sun.tools.javac.code.Flags.*; 58 import static com.sun.tools.javac.code.Flags.*;
59 import static com.sun.tools.javac.code.Kinds.*; 59 import static com.sun.tools.javac.code.Kinds.*;
60 import static com.sun.tools.javac.code.TypeTag.BOT; 60 import static com.sun.tools.javac.code.TypeTag.*;
61 import static com.sun.tools.javac.code.TypeTag.NONE;
62 import static com.sun.tools.javac.code.TypeTag.VOID;
63 import static com.sun.tools.javac.tree.JCTree.Tag.*; 61 import static com.sun.tools.javac.tree.JCTree.Tag.*;
64 62
65 /** 63 /**
66 * This pass desugars lambda expressions into static methods 64 * This pass desugars lambda expressions into static methods
67 * 65 *
87 private Map<JCTree, TranslationContext<?>> contextMap; 85 private Map<JCTree, TranslationContext<?>> contextMap;
88 86
89 /** current translation context (visitor argument) */ 87 /** current translation context (visitor argument) */
90 private TranslationContext<?> context; 88 private TranslationContext<?> context;
91 89
92 /** list of translated methods 90 /** info about the current class being processed */
93 **/ 91 private KlassInfo kInfo;
94 private ListBuffer<JCTree> translatedMethodList; 92
93 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
94 public static final int FLAG_SERIALIZABLE = 1 << 0;
95
96 /** Flag for alternate metafactories indicating the lambda object has multiple targets */
97 public static final int FLAG_MARKERS = 1 << 1;
98
99 private class KlassInfo {
100
101 /**
102 * list of methods to append
103 */
104 private ListBuffer<JCTree> appendedMethodList;
105
106 /**
107 * list of deserialization cases
108 */
109 private final Map<String, ListBuffer<JCStatement>> deserializeCases;
110
111 /**
112 * deserialize method symbol
113 */
114 private final MethodSymbol deserMethodSym;
115
116 /**
117 * deserialize method parameter symbol
118 */
119 private final VarSymbol deserParamSym;
120
121 private KlassInfo(Symbol kSym) {
122 appendedMethodList = ListBuffer.lb();
123 deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
124 long flags = PRIVATE | STATIC | SYNTHETIC;
125 MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
126 List.<Type>nil(), syms.methodClass);
127 deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym);
128 deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), syms.serializedLambdaType, deserMethodSym);
129 }
130
131 private void addMethod(JCTree decl) {
132 appendedMethodList = appendedMethodList.prepend(decl);
133 }
134 }
95 135
96 // <editor-fold defaultstate="collapsed" desc="Instantiating"> 136 // <editor-fold defaultstate="collapsed" desc="Instantiating">
97 private static final Context.Key<LambdaToMethod> unlambdaKey = 137 private static final Context.Key<LambdaToMethod> unlambdaKey =
98 new Context.Key<LambdaToMethod>(); 138 new Context.Key<LambdaToMethod>();
99 139
110 syms = Symtab.instance(context); 150 syms = Symtab.instance(context);
111 rs = Resolve.instance(context); 151 rs = Resolve.instance(context);
112 make = TreeMaker.instance(context); 152 make = TreeMaker.instance(context);
113 types = Types.instance(context); 153 types = Types.instance(context);
114 transTypes = TransTypes.instance(context); 154 transTypes = TransTypes.instance(context);
115 this.analyzer = makeAnalyzer(); 155 analyzer = new LambdaAnalyzer();
116 }
117
118 private LambdaAnalyzer makeAnalyzer() {
119 return new LambdaAnalyzer();
120 } 156 }
121 // </editor-fold> 157 // </editor-fold>
122 158
123 // <editor-fold defaultstate="collapsed" desc="translate methods"> 159 // <editor-fold defaultstate="collapsed" desc="translate methods">
124 @Override 160 @Override
166 public void visitClassDef(JCClassDecl tree) { 202 public void visitClassDef(JCClassDecl tree) {
167 if (tree.sym.owner.kind == PCK) { 203 if (tree.sym.owner.kind == PCK) {
168 //analyze class 204 //analyze class
169 analyzer.analyzeClass(tree); 205 analyzer.analyzeClass(tree);
170 } 206 }
171 ListBuffer<JCTree> prevTranslated = translatedMethodList; 207 KlassInfo prevKlassInfo = kInfo;
172 try { 208 try {
173 translatedMethodList = ListBuffer.lb(); 209 kInfo = new KlassInfo(tree.sym);
174 super.visitClassDef(tree); 210 super.visitClassDef(tree);
211 if (!kInfo.deserializeCases.isEmpty()) {
212 kInfo.addMethod(makeDeserializeMethod(tree.sym));
213 }
175 //add all translated instance methods here 214 //add all translated instance methods here
176 tree.defs = tree.defs.appendList(translatedMethodList.toList()); 215 List<JCTree> newMethods = kInfo.appendedMethodList.toList();
177 for (JCTree lambda : translatedMethodList) { 216 tree.defs = tree.defs.appendList(newMethods);
217 for (JCTree lambda : newMethods) {
178 tree.sym.members().enter(((JCMethodDecl)lambda).sym); 218 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
179 } 219 }
180 result = tree; 220 result = tree;
181 } finally { 221 } finally {
182 translatedMethodList = prevTranslated; 222 kInfo = prevKlassInfo;
183 } 223 }
184 } 224 }
185 225
186 /** 226 /**
187 * Translate a lambda into a method to be inserted into the class. 227 * Translate a lambda into a method to be inserted into the class.
215 //to refer to the static method parameters (rather than i.e. acessing to 255 //to refer to the static method parameters (rather than i.e. acessing to
216 //captured members directly). 256 //captured members directly).
217 lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl)); 257 lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
218 258
219 //Add the method to the list of methods to be added to this class. 259 //Add the method to the list of methods to be added to this class.
220 translatedMethodList = translatedMethodList.prepend(lambdaDecl); 260 kInfo.addMethod(lambdaDecl);
221 261
222 //now that we have generated a method for the lambda expression, 262 //now that we have generated a method for the lambda expression,
223 //we can translate the lambda into a method reference pointing to the newly 263 //we can translate the lambda into a method reference pointing to the newly
224 //created method. 264 //created method.
225 // 265 //
232 272
233 ListBuffer<JCExpression> syntheticInits = ListBuffer.lb(); 273 ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
234 274
235 if (!sym.isStatic()) { 275 if (!sym.isStatic()) {
236 syntheticInits.append(makeThis( 276 syntheticInits.append(makeThis(
237 sym.owner.asType(), 277 sym.owner.enclClass().asType(),
238 localContext.owner.enclClass())); 278 localContext.owner.enclClass()));
239 } 279 }
240 280
241 //add captured locals 281 //add captured locals
242 for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) { 282 for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
251 291
252 //build a sam instance using an indy call to the meta-factory 292 //build a sam instance using an indy call to the meta-factory
253 int refKind = referenceKind(sym); 293 int refKind = referenceKind(sym);
254 294
255 //convert to an invokedynamic call 295 //convert to an invokedynamic call
256 result = makeMetaFactoryIndyCall(tree, refKind, sym, indy_args); 296 result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args);
257 } 297 }
258 298
259 private JCIdent makeThis(Type type, Symbol owner) { 299 private JCIdent makeThis(Type type, Symbol owner) {
260 VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC, 300 VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
261 names._this, 301 names._this,
289 switch(tree.kind) { 329 switch(tree.kind) {
290 330
291 case IMPLICIT_INNER: /** Inner :: new */ 331 case IMPLICIT_INNER: /** Inner :: new */
292 case SUPER: /** super :: instMethod */ 332 case SUPER: /** super :: instMethod */
293 init = makeThis( 333 init = makeThis(
294 localContext.owner.owner.asType(), 334 localContext.owner.enclClass().asType(),
295 localContext.owner); 335 localContext.owner.enclClass());
296 break; 336 break;
297 337
298 case BOUND: /** Expr :: instMethod */ 338 case BOUND: /** Expr :: instMethod */
299 init = tree.getQualifierExpression(); 339 init = tree.getQualifierExpression();
300 break; 340 break;
312 352
313 List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev); 353 List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
314 354
315 355
316 //build a sam instance using an indy call to the meta-factory 356 //build a sam instance using an indy call to the meta-factory
317 result = makeMetaFactoryIndyCall(tree, localContext.referenceKind(), refSym, indy_args); 357 result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args);
318 } 358 }
319 359
320 /** 360 /**
321 * Translate identifiers within a lambda to the mapped identifier 361 * Translate identifiers within a lambda to the mapped identifier
322 * @param tree 362 * @param tree
331 Symbol translatedSym = lambdaContext.getSymbolMap(PARAM).get(tree.sym); 371 Symbol translatedSym = lambdaContext.getSymbolMap(PARAM).get(tree.sym);
332 result = make.Ident(translatedSym).setType(tree.type); 372 result = make.Ident(translatedSym).setType(tree.type);
333 } else if (lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { 373 } else if (lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
334 Symbol translatedSym = lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym); 374 Symbol translatedSym = lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
335 result = make.Ident(translatedSym).setType(tree.type); 375 result = make.Ident(translatedSym).setType(tree.type);
376 } else if (lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
377 Symbol translatedSym = lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
378 result = make.Ident(translatedSym).setType(translatedSym.type);
336 } else if (lambdaContext.getSymbolMap(CAPTURED_VAR).containsKey(tree.sym)) { 379 } else if (lambdaContext.getSymbolMap(CAPTURED_VAR).containsKey(tree.sym)) {
337 Symbol translatedSym = lambdaContext.getSymbolMap(CAPTURED_VAR).get(tree.sym); 380 Symbol translatedSym = lambdaContext.getSymbolMap(CAPTURED_VAR).get(tree.sym);
338 result = make.Ident(translatedSym).setType(tree.type); 381 result = make.Ident(translatedSym).setType(tree.type);
339 } else { 382 } else {
340 if (tree.sym.owner.kind == Kinds.TYP) { 383 if (tree.sym.owner.kind == Kinds.TYP) {
360 public void visitVarDef(JCVariableDecl tree) { 403 public void visitVarDef(JCVariableDecl tree) {
361 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context; 404 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
362 if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { 405 if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
363 JCExpression init = translate(tree.init); 406 JCExpression init = translate(tree.init);
364 result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init); 407 result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
408 } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
409 JCExpression init = translate(tree.init);
410 VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
411 result = make.VarDef(xsym, init);
412 // Replace the entered symbol for this variable
413 Scope sc = tree.sym.owner.members();
414 if (sc != null) {
415 sc.remove(tree.sym);
416 sc.enter(xsym);
417 }
365 } else { 418 } else {
366 super.visitVarDef(tree); 419 super.visitVarDef(tree);
367 } 420 }
368 } 421 }
369 422
449 trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); 502 trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
450 } 503 }
451 return trans_block; 504 return trans_block;
452 } 505 }
453 506
507 private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
508 ListBuffer<JCCase> cases = ListBuffer.lb();
509 ListBuffer<JCBreak> breaks = ListBuffer.lb();
510 for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
511 JCBreak br = make.Break(null);
512 breaks.add(br);
513 List<JCStatement> stmts = entry.getValue().append(br).toList();
514 cases.add(make.Case(make.Literal(entry.getKey()), stmts));
515 }
516 JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
517 for (JCBreak br : breaks) {
518 br.target = sw;
519 }
520 JCBlock body = make.Block(0L, List.<JCStatement>of(
521 sw,
522 make.Throw(makeNewClass(
523 syms.illegalArgumentExceptionType,
524 List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
525 JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
526 names.deserializeLambda,
527 make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
528 List.<JCTypeParameter>nil(),
529 List.of(make.VarDef(kInfo.deserParamSym, null)),
530 List.<JCExpression>nil(),
531 body,
532 null);
533 deser.sym = kInfo.deserMethodSym;
534 deser.type = kInfo.deserMethodSym.type;
535 //System.err.printf("DESER: '%s'\n", deser);
536 return deser;
537 }
538
539 /** Make an attributed class instance creation expression.
540 * @param ctype The class type.
541 * @param args The constructor arguments.
542 */
543 JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
544 JCNewClass tree = make.NewClass(null,
545 null, make.QualIdent(ctype.tsym), args, null);
546 tree.constructor = rs.resolveConstructor(
547 null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil());
548 tree.type = ctype;
549 return tree;
550 }
551
552 private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
553 DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
554 String functionalInterfaceClass = classSig(targetType);
555 String functionalInterfaceMethodName = samSym.getSimpleName().toString();
556 String functionalInterfaceMethodSignature = methodSig(types.erasure(samSym.type));
557 String implClass = classSig(refSym.owner.type);
558 String implMethodName = refSym.getQualifiedName().toString();
559 String implMethodSignature = methodSig(types.erasure(refSym.type));
560
561 JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
562 ListBuffer<JCExpression> serArgs = ListBuffer.lb();
563 int i = 0;
564 for (Type t : indyType.getParameterTypes()) {
565 List<JCExpression> indexAsArg = ListBuffer.<JCExpression>lb().append(make.Literal(i)).toList();
566 List<Type> argTypes = ListBuffer.<Type>lb().append(syms.intType).toList();
567 serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
568 ++i;
569 }
570 JCStatement stmt = make.If(
571 deserTest(deserTest(deserTest(deserTest(deserTest(
572 kindTest,
573 "getFunctionalInterfaceClass", functionalInterfaceClass),
574 "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
575 "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
576 "getImplClass", implClass),
577 "getImplMethodSignature", implMethodSignature),
578 make.Return(makeIndyCall(
579 pos,
580 syms.lambdaMetafactory,
581 names.altMetaFactory,
582 staticArgs, indyType, serArgs.toList())),
583 null);
584 ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
585 if (stmts == null) {
586 stmts = ListBuffer.lb();
587 kInfo.deserializeCases.put(implMethodName, stmts);
588 }
589 /****
590 System.err.printf("+++++++++++++++++\n");
591 System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
592 System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
593 System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
594 System.err.printf("*implMethodKind: %d\n", implMethodKind);
595 System.err.printf("*implClass: '%s'\n", implClass);
596 System.err.printf("*implMethodName: '%s'\n", implMethodName);
597 System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
598 ****/
599 stmts.append(stmt);
600 }
601
602 private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
603 JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
604 testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
605 testExpr.setType(syms.booleanType);
606 return testExpr;
607 }
608
609 private JCExpression deserTest(JCExpression prev, String func, String lit) {
610 MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
611 Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
612 JCMethodInvocation eqtest = make.Apply(
613 List.<JCExpression>nil(),
614 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
615 List.<JCExpression>of(make.Literal(lit)));
616 eqtest.setType(syms.booleanType);
617 JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
618 compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
619 compound.setType(syms.booleanType);
620 return compound;
621 }
622
623 private JCExpression deserGetter(String func, Type type) {
624 return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
625 }
626
627 private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
628 MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
629 Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
630 return make.Apply(
631 List.<JCExpression>nil(),
632 make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
633 args).setType(type);
634 }
635
454 /** 636 /**
455 * Create new synthetic method with given flags, name, type, owner 637 * Create new synthetic method with given flags, name, type, owner
456 */ 638 */
457 private MethodSymbol makeSyntheticMethod(long flags, Name name, Type type, Symbol owner) { 639 private MethodSymbol makeSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
458 return new MethodSymbol(flags | SYNTHETIC, name, type, owner); 640 return new MethodSymbol(flags | SYNTHETIC, name, type, owner);
676 * Bridges a member reference - this is needed when: 858 * Bridges a member reference - this is needed when:
677 * * Var args in the referenced method need to be flattened away 859 * * Var args in the referenced method need to be flattened away
678 * * super is used 860 * * super is used
679 */ 861 */
680 private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) { 862 private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
681 JCMethodDecl bridgeDecl = (new MemberReferenceBridger(tree, localContext).bridge()); 863 kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
682 translatedMethodList = translatedMethodList.prepend(bridgeDecl);
683 } 864 }
684 865
685 /** 866 /**
686 * Generate an indy method call to the meta factory 867 * Generate an indy method call to the meta factory
687 */ 868 */
688 private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, int refKind, Symbol refSym, List<JCExpression> indy_args) { 869 private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory,
870 boolean isSerializable, int refKind, Symbol refSym, List<JCExpression> indy_args) {
689 //determine the static bsm args 871 //determine the static bsm args
690 Type mtype = types.erasure(tree.descriptorType); 872 Type mtype = types.erasure(tree.descriptorType);
691 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym); 873 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
692 List<Object> staticArgs = List.<Object>of( 874 List<Object> staticArgs = List.<Object>of(
693 new Pool.MethodHandle(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(tree.type.tsym), types), 875 new Pool.MethodHandle(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(tree.type.tsym), types),
707 MethodType indyType = new MethodType(indy_args_types.toList(), 889 MethodType indyType = new MethodType(indy_args_types.toList(),
708 tree.type, 890 tree.type,
709 List.<Type>nil(), 891 List.<Type>nil(),
710 syms.methodClass); 892 syms.methodClass);
711 893
712 return makeIndyCall(tree, syms.lambdaMetafactory, names.metaFactory, staticArgs, indyType, indy_args); 894 Name metafactoryName = needsAltMetafactory ?
895 names.altMetaFactory : names.metaFactory;
896
897 if (needsAltMetafactory) {
898 ListBuffer<Object> markers = ListBuffer.lb();
899 for (Symbol t : tree.targets.tail) {
900 if (t != syms.serializableType.tsym) {
901 markers.append(t);
902 }
903 }
904 int flags = isSerializable? FLAG_SERIALIZABLE : 0;
905 boolean hasMarkers = markers.nonEmpty();
906 flags |= hasMarkers ? FLAG_MARKERS : 0;
907 staticArgs = staticArgs.append(flags);
908 if (hasMarkers) {
909 staticArgs = staticArgs.append(markers.length());
910 staticArgs = staticArgs.appendList(markers.toList());
911 }
912 if (isSerializable) {
913 addDeserializationCase(refKind, refSym, tree.type, samSym,
914 tree, staticArgs, indyType);
915 }
916 }
917
918 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
713 } 919 }
714 920
715 /** 921 /**
716 * Generate an indy method call with given name, type and static bootstrap 922 * Generate an indy method call with given name, type and static bootstrap
717 * arguments types 923 * arguments types
793 } else { 999 } else {
794 return ClassFile.REF_invokeVirtual; 1000 return ClassFile.REF_invokeVirtual;
795 } 1001 }
796 } 1002 }
797 } 1003 }
1004
798 // </editor-fold> 1005 // </editor-fold>
799 1006
800 // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">\ 1007 // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">\
801 /** 1008 /**
802 * This visitor collects information about translation of a lambda expression. 1009 * This visitor collects information about translation of a lambda expression.
812 * keep the count of lambda expression (used to generate unambiguous 1019 * keep the count of lambda expression (used to generate unambiguous
813 * names) 1020 * names)
814 */ 1021 */
815 private int lambdaCount = 0; 1022 private int lambdaCount = 0;
816 1023
1024 /**
1025 * keep the count of lambda expression defined in given context (used to
1026 * generate unambiguous names for serializable lambdas)
1027 */
1028 private Map<String, Integer> serializableLambdaCounts =
1029 new HashMap<String, Integer>();
1030
1031 /**
1032 * maps for fake clinit symbols to be used as owners of lambda occurring in
1033 * a static var init context
1034 */
1035 private Map<ClassSymbol, Symbol> clinits =
1036 new HashMap<ClassSymbol, Symbol>();
1037
817 private void analyzeClass(JCClassDecl tree) { 1038 private void analyzeClass(JCClassDecl tree) {
818 frameStack = List.nil(); 1039 frameStack = List.nil();
819 scan(tree); 1040 scan(tree);
820 } 1041 }
821 1042
834 } 1055 }
835 1056
836 @Override 1057 @Override
837 public void visitClassDef(JCClassDecl tree) { 1058 public void visitClassDef(JCClassDecl tree) {
838 List<Frame> prevStack = frameStack; 1059 List<Frame> prevStack = frameStack;
1060 Map<String, Integer> prevSerializableLambdaCount = serializableLambdaCounts;
1061 Map<ClassSymbol, Symbol> prevClinits = clinits;
839 try { 1062 try {
840 if (frameStack.nonEmpty() && enclosingLambda() != null) { 1063 serializableLambdaCounts = new HashMap<String, Integer>();
1064 prevClinits = new HashMap<ClassSymbol, Symbol>();
1065 if (directlyEnclosingLambda() != null) {
841 tree.sym.owner = owner(); 1066 tree.sym.owner = owner();
842 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)contextMap.get(enclosingLambda()); 1067 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) contextMap.get(directlyEnclosingLambda());
843 Type encl = lambdaContext.enclosingType(); 1068 Type encl = lambdaContext.enclosingType();
844 if (encl.hasTag(NONE)) { 1069 if (encl.hasTag(NONE)) {
845 //if the translated lambda body occurs in a static context, 1070 //if the translated lambda body occurs in a static context,
846 //any class declaration within it must be made static 1071 //any class declaration within it must be made static
1072 //@@@TODO: What about nested classes within lambda?
847 tree.sym.flags_field |= STATIC; 1073 tree.sym.flags_field |= STATIC;
848 ((ClassType)tree.sym.type).setEnclosingType(Type.noType); 1074 ((ClassType) tree.sym.type).setEnclosingType(Type.noType);
849 } else { 1075 } else {
850 //if the translated lambda body is in an instance context 1076 //if the translated lambda body is in an instance context
851 //the enclosing type of any class declaration within it 1077 //the enclosing type of any class declaration within it
852 //must be updated to point to the new enclosing type (if any) 1078 //must be updated to point to the new enclosing type (if any)
853 ((ClassType)tree.sym.type).setEnclosingType(encl); 1079 ((ClassType) tree.sym.type).setEnclosingType(encl);
854 } 1080 }
855 } 1081 }
856 frameStack = frameStack.prepend(new Frame(tree)); 1082 frameStack = frameStack.prepend(new Frame(tree));
857 super.visitClassDef(tree); 1083 super.visitClassDef(tree);
858 } 1084 }
859 finally { 1085 finally {
860 frameStack = prevStack; 1086 frameStack = prevStack;
861 } 1087 serializableLambdaCounts = prevSerializableLambdaCount;
862 if (!tree.sym.isStatic() && frameStack.nonEmpty() && enclosingLambda() != null) { 1088 clinits = prevClinits;
1089 }
1090 if (!tree.sym.isStatic() && directlyEnclosingLambda() != null) {
863 // Any (non-static) class defined within a lambda is an implicit 'this' reference 1091 // Any (non-static) class defined within a lambda is an implicit 'this' reference
864 // because its constructor will reference the enclosing class 1092 // because its constructor will reference the enclosing class
865 ((LambdaTranslationContext) context()).addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS); 1093 ((LambdaTranslationContext) context()).addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
866 } 1094 }
867 } 1095 }
868 1096
869 @Override 1097 @Override
870 public void visitIdent(JCIdent tree) { 1098 public void visitIdent(JCIdent tree) {
871 if (context() == null || !lambdaIdentSymbolFilter(tree.sym)) { 1099 if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
872 super.visitIdent(tree);
873 } else {
874 if (tree.sym.kind == VAR && 1100 if (tree.sym.kind == VAR &&
875 tree.sym.owner.kind == MTH && 1101 tree.sym.owner.kind == MTH &&
876 tree.type.constValue() == null) { 1102 tree.type.constValue() == null) {
877 TranslationContext<?> localContext = context(); 1103 TranslationContext<?> localContext = context();
878 while (localContext != null) { 1104 while (localContext != null) {
900 } 1126 }
901 localContext = localContext.prev; 1127 localContext = localContext.prev;
902 } 1128 }
903 } 1129 }
904 } 1130 }
1131 super.visitIdent(tree);
905 } 1132 }
906 1133
907 @Override 1134 @Override
908 public void visitLambda(JCLambda tree) { 1135 public void visitLambda(JCLambda tree) {
909 List<Frame> prevStack = frameStack; 1136 List<Frame> prevStack = frameStack;
967 } 1194 }
968 } 1195 }
969 1196
970 @Override 1197 @Override
971 public void visitVarDef(JCVariableDecl tree) { 1198 public void visitVarDef(JCVariableDecl tree) {
972 if (frameStack.head.tree.hasTag(LAMBDA)) { 1199 TranslationContext<?> context = context();
973 ((LambdaTranslationContext)context()).addSymbol(tree.sym, LOCAL_VAR); 1200 LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
974 } 1201 (LambdaTranslationContext)context :
1202 null;
1203 if (ltc != null) {
1204 if (frameStack.head.tree.hasTag(LAMBDA)) {
1205 ltc.addSymbol(tree.sym, LOCAL_VAR);
1206 }
1207 // Check for type variables (including as type arguments).
1208 // If they occur within class nested in a lambda, mark for erasure
1209 Type type = tree.sym.asType();
1210 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
1211 ltc.addSymbol(tree.sym, TYPE_VAR);
1212 }
1213 }
1214
975 List<Frame> prevStack = frameStack; 1215 List<Frame> prevStack = frameStack;
976 try { 1216 try {
977 if (tree.sym.owner.kind == MTH) { 1217 if (tree.sym.owner.kind == MTH) {
978 frameStack.head.addLocal(tree.sym); 1218 frameStack.head.addLocal(tree.sym);
979 } 1219 }
984 frameStack = prevStack; 1224 frameStack = prevStack;
985 } 1225 }
986 } 1226 }
987 1227
988 private Name lambdaName() { 1228 private Name lambdaName() {
989 return names.lambda.append(names.fromString("$" + lambdaCount++)); 1229 return names.lambda.append(names.fromString("" + lambdaCount++));
1230 }
1231
1232 private Name serializedLambdaName(Symbol owner) {
1233 StringBuilder buf = new StringBuilder();
1234 buf.append(names.lambda);
1235 buf.append(owner.name);
1236 buf.append('$');
1237 int methTypeHash = methodSig(owner.type).hashCode();
1238 buf.append(methTypeHash);
1239 buf.append('$');
1240 String temp = buf.toString();
1241 Integer count = serializableLambdaCounts.get(temp);
1242 if (count == null) {
1243 count = 0;
1244 }
1245 buf.append(count++);
1246 serializableLambdaCounts.put(temp, count);
1247 return names.fromString(buf.toString());
990 } 1248 }
991 1249
992 /** 1250 /**
993 * Return a valid owner given the current declaration stack 1251 * Return a valid owner given the current declaration stack
994 * (required to skip synthetic lambda symbols) 1252 * (required to skip synthetic lambda symbols)
1006 if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) { 1264 if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
1007 frameStack2 = frameStack2.tail; 1265 frameStack2 = frameStack2.tail;
1008 break; 1266 break;
1009 } 1267 }
1010 JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree; 1268 JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
1011 return makeSyntheticMethod(((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC, names.empty, null, cdecl.sym); 1269 return initSym(cdecl.sym,
1270 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
1012 case BLOCK: 1271 case BLOCK:
1013 JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree; 1272 JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
1014 return makeSyntheticMethod(((JCBlock)frameStack2.head.tree).flags & STATIC | Flags.BLOCK, names.empty, null, cdecl2.sym); 1273 return initSym(cdecl2.sym,
1274 ((JCBlock)frameStack2.head.tree).flags & STATIC);
1015 case CLASSDEF: 1275 case CLASSDEF:
1016 return ((JCClassDecl)frameStack2.head.tree).sym; 1276 return ((JCClassDecl)frameStack2.head.tree).sym;
1017 case METHODDEF: 1277 case METHODDEF:
1018 return ((JCMethodDecl)frameStack2.head.tree).sym; 1278 return ((JCMethodDecl)frameStack2.head.tree).sym;
1019 case LAMBDA: 1279 case LAMBDA:
1025 } 1285 }
1026 Assert.error(); 1286 Assert.error();
1027 return null; 1287 return null;
1028 } 1288 }
1029 1289
1030 private JCTree enclosingLambda() { 1290 private Symbol initSym(ClassSymbol csym, long flags) {
1291 boolean isStatic = (flags & STATIC) != 0;
1292 if (isStatic) {
1293 //static clinits are generated in Gen - so we need to fake them
1294 Symbol clinit = clinits.get(csym);
1295 if (clinit == null) {
1296 clinit = makeSyntheticMethod(STATIC,
1297 names.clinit,
1298 new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
1299 csym);
1300 clinits.put(csym, clinit);
1301 }
1302 return clinit;
1303 } else {
1304 //get the first constructor and treat it as the instance init sym
1305 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
1306 return s;
1307 }
1308 }
1309 Assert.error("init not found");
1310 return null;
1311 }
1312
1313 private JCTree directlyEnclosingLambda() {
1314 if (frameStack.isEmpty()) {
1315 return null;
1316 }
1031 List<Frame> frameStack2 = frameStack; 1317 List<Frame> frameStack2 = frameStack;
1032 while (frameStack2.nonEmpty()) { 1318 while (frameStack2.nonEmpty()) {
1033 switch (frameStack2.head.tree.getTag()) { 1319 switch (frameStack2.head.tree.getTag()) {
1034 case CLASSDEF: 1320 case CLASSDEF:
1035 case METHODDEF: 1321 case METHODDEF:
1040 frameStack2 = frameStack2.tail; 1326 frameStack2 = frameStack2.tail;
1041 } 1327 }
1042 } 1328 }
1043 Assert.error(); 1329 Assert.error();
1044 return null; 1330 return null;
1331 }
1332
1333 private boolean inClassWithinLambda() {
1334 if (frameStack.isEmpty()) {
1335 return false;
1336 }
1337 List<Frame> frameStack2 = frameStack;
1338 boolean classFound = false;
1339 while (frameStack2.nonEmpty()) {
1340 switch (frameStack2.head.tree.getTag()) {
1341 case LAMBDA:
1342 return classFound;
1343 case CLASSDEF:
1344 classFound = true;
1345 frameStack2 = frameStack2.tail;
1346 break;
1347 default:
1348 frameStack2 = frameStack2.tail;
1349 }
1350 }
1351 // No lambda
1352 return false;
1045 } 1353 }
1046 1354
1047 /** 1355 /**
1048 * Return the declaration corresponding to a symbol in the enclosing 1356 * Return the declaration corresponding to a symbol in the enclosing
1049 * scope; the depth parameter is used to filter out symbols defined 1357 * scope; the depth parameter is used to filter out symbols defined
1176 this.tree = tree; 1484 this.tree = tree;
1177 this.owner = owner(); 1485 this.owner = owner();
1178 this.depth = frameStack.size() - 1; 1486 this.depth = frameStack.size() - 1;
1179 this.prev = context(); 1487 this.prev = context();
1180 } 1488 }
1489
1490 /** does this functional expression need to be created using alternate metafactory? */
1491 boolean needsAltMetafactory() {
1492 return (tree.targets.length() > 1 ||
1493 isSerializable());
1494 }
1495
1496 /** does this functional expression require serialization support? */
1497 boolean isSerializable() {
1498 for (Symbol target : tree.targets) {
1499 if (types.asSuper(target.type, syms.serializableType.tsym) != null) {
1500 return true;
1501 }
1502 }
1503 return false;
1504 }
1181 } 1505 }
1182 1506
1183 /** 1507 /**
1184 * This class retains all the useful information about a lambda expression; 1508 * This class retains all the useful information about a lambda expression;
1185 * the contents of this class are filled by the LambdaAnalyzer visitor, 1509 * the contents of this class are filled by the LambdaAnalyzer visitor,
1201 Map<Symbol, Symbol> capturedLocals = new LinkedHashMap<Symbol, Symbol>(); 1525 Map<Symbol, Symbol> capturedLocals = new LinkedHashMap<Symbol, Symbol>();
1202 1526
1203 /** map from class symbols to translated synthetic parameters (for captured member access) */ 1527 /** map from class symbols to translated synthetic parameters (for captured member access) */
1204 Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>(); 1528 Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>();
1205 1529
1530 /** map from original to translated lambda locals */
1531 Map<Symbol, Symbol> typeVars = new LinkedHashMap<Symbol, Symbol>();
1532
1206 /** the synthetic symbol for the method hoisting the translated lambda */ 1533 /** the synthetic symbol for the method hoisting the translated lambda */
1207 Symbol translatedSym; 1534 Symbol translatedSym;
1208 1535
1209 List<JCVariableDecl> syntheticParams; 1536 List<JCVariableDecl> syntheticParams;
1210 1537
1212 super(tree); 1539 super(tree);
1213 Frame frame = frameStack.head; 1540 Frame frame = frameStack.head;
1214 if (frame.tree.hasTag(VARDEF)) { 1541 if (frame.tree.hasTag(VARDEF)) {
1215 self = ((JCVariableDecl)frame.tree).sym; 1542 self = ((JCVariableDecl)frame.tree).sym;
1216 } 1543 }
1217 this.translatedSym = makeSyntheticMethod(0, lambdaName(), null, owner.enclClass()); 1544 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName();
1545 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass());
1218 } 1546 }
1219 1547
1220 /** 1548 /**
1221 * Translate a symbol of a given kind into something suitable for the 1549 * Translate a symbol of a given kind into something suitable for the
1222 * synthetic lambda body 1550 * synthetic lambda body
1223 */ 1551 */
1224 Symbol translate(String name, Symbol sym, LambdaSymbolKind skind) { 1552 Symbol translate(String name, Symbol sym, LambdaSymbolKind skind) {
1225 if (skind == CAPTURED_THIS) { 1553 switch (skind) {
1226 return sym; // self represented 1554 case CAPTURED_THIS:
1227 } else { 1555 return sym; // self represented
1228 return makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym); 1556 case TYPE_VAR:
1557 // Just erase the type var
1558 return new VarSymbol(sym.flags(), names.fromString(name), types.erasure(sym.type), sym.owner);
1559 default:
1560 return makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
1229 } 1561 }
1230 } 1562 }
1231 1563
1232 void addSymbol(Symbol sym, LambdaSymbolKind skind) { 1564 void addSymbol(Symbol sym, LambdaSymbolKind skind) {
1233 Map<Symbol, Symbol> transMap = null; 1565 Map<Symbol, Symbol> transMap = null;
1247 break; 1579 break;
1248 case PARAM: 1580 case PARAM:
1249 transMap = lambdaParams; 1581 transMap = lambdaParams;
1250 preferredName = sym.name.toString(); 1582 preferredName = sym.name.toString();
1251 break; 1583 break;
1584 case TYPE_VAR:
1585 transMap = typeVars;
1586 preferredName = sym.name.toString();
1587 break;
1252 default: throw new AssertionError(); 1588 default: throw new AssertionError();
1253 } 1589 }
1254 if (!transMap.containsKey(sym)) { 1590 if (!transMap.containsKey(sym)) {
1255 transMap.put(sym, translate(preferredName, sym, skind)); 1591 transMap.put(sym, translate(preferredName, sym, skind));
1256 } 1592 }
1270 translationMap.putAll(lambdaLocals); 1606 translationMap.putAll(lambdaLocals);
1271 break; 1607 break;
1272 case PARAM: 1608 case PARAM:
1273 translationMap.putAll(lambdaParams); 1609 translationMap.putAll(lambdaParams);
1274 break; 1610 break;
1611 case TYPE_VAR:
1612 translationMap.putAll(typeVars);
1613 break;
1275 default: throw new AssertionError(); 1614 default: throw new AssertionError();
1276 } 1615 }
1277 } 1616 }
1278 return translationMap; 1617 return translationMap;
1279 } 1618 }
1309 } 1648 }
1310 1649
1311 syntheticParams = params.toList(); 1650 syntheticParams = params.toList();
1312 1651
1313 //prepend synthetic args to translated lambda method signature 1652 //prepend synthetic args to translated lambda method signature
1314 translatedSym.type = (MethodType) types.createMethodTypeWithParameters( 1653 translatedSym.type = types.createMethodTypeWithParameters(
1315 (MethodType) generatedLambdaSig(), 1654 generatedLambdaSig(),
1316 TreeInfo.types(syntheticParams)); 1655 TreeInfo.types(syntheticParams));
1317 } 1656 }
1318 1657
1319 Type enclosingType() { 1658 Type enclosingType() {
1320 return owner.isStatic() ? 1659 return owner.isStatic() ?
1387 1726
1388 enum LambdaSymbolKind { 1727 enum LambdaSymbolKind {
1389 CAPTURED_VAR, 1728 CAPTURED_VAR,
1390 CAPTURED_THIS, 1729 CAPTURED_THIS,
1391 LOCAL_VAR, 1730 LOCAL_VAR,
1392 PARAM; 1731 PARAM,
1732 TYPE_VAR;
1733 }
1734
1735 /**
1736 * ****************************************************************
1737 * Signature Generation
1738 * ****************************************************************
1739 */
1740
1741 private String methodSig(Type type) {
1742 L2MSignatureGenerator sg = new L2MSignatureGenerator();
1743 sg.assembleSig(type);
1744 return sg.toString();
1745 }
1746
1747 private String classSig(Type type) {
1748 L2MSignatureGenerator sg = new L2MSignatureGenerator();
1749 sg.assembleClassSig(type);
1750 return sg.toString();
1751 }
1752
1753 /**
1754 * Signature Generation
1755 */
1756 private class L2MSignatureGenerator extends Types.SignatureGenerator {
1757
1758 /**
1759 * An output buffer for type signatures.
1760 */
1761 StringBuilder sb = new StringBuilder();
1762
1763 L2MSignatureGenerator() {
1764 super(types);
1765 }
1766
1767 @Override
1768 protected void append(char ch) {
1769 sb.append(ch);
1770 }
1771
1772 @Override
1773 protected void append(byte[] ba) {
1774 sb.append(new String(ba));
1775 }
1776
1777 @Override
1778 protected void append(Name name) {
1779 sb.append(name.toString());
1780 }
1781
1782 @Override
1783 public String toString() {
1784 return sb.toString();
1785 }
1393 } 1786 }
1394 } 1787 }

mercurial