# HG changeset patch
# User rfield
# Date 1360982438 28800
# Node ID 7cf27559c8df0c10593087d158edb685e6478397
# Parent 05b5bf59c9d3e67e448e33bf7b74b80d9653b01c
8004969: Generate $deserializeLambda$ method
8006763: super in method reference used in anonymous class - ClassFormatError is produced
8005632: Inner classes within lambdas cause build failures
8005653: Lambdas containing inner classes referencing external type variables do not correctly parameterize the inner classes
Reviewed-by: mcimadamore
diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Fri Feb 15 11:26:11 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Fri Feb 15 18:40:38 2013 -0800
@@ -126,6 +126,7 @@
public final Type stringBuilderType;
public final Type cloneableType;
public final Type serializableType;
+ public final Type serializedLambdaType;
public final Type methodHandleType;
public final Type methodHandleLookupType;
public final Type methodTypeType;
@@ -458,6 +459,7 @@
cloneableType = enterClass("java.lang.Cloneable");
throwableType = enterClass("java.lang.Throwable");
serializableType = enterClass("java.io.Serializable");
+ serializedLambdaType = enterClass("java.lang.invoke.SerializedLambda");
methodHandleType = enterClass("java.lang.invoke.MethodHandle");
methodHandleLookupType = enterClass("java.lang.invoke.MethodHandles$Lookup");
methodTypeType = enterClass("java.lang.invoke.MethodType");
@@ -514,6 +516,7 @@
synthesizeEmptyInterfaceIfMissing(cloneableType);
synthesizeEmptyInterfaceIfMissing(serializableType);
synthesizeEmptyInterfaceIfMissing(lambdaMetafactory);
+ synthesizeEmptyInterfaceIfMissing(serializedLambdaType);
synthesizeBoxTypeIfMissing(doubleType);
synthesizeBoxTypeIfMissing(floatType);
synthesizeBoxTypeIfMissing(voidType);
diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/src/share/classes/com/sun/tools/javac/code/Types.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Fri Feb 15 11:26:11 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Fri Feb 15 18:40:38 2013 -0800
@@ -48,6 +48,7 @@
import static com.sun.tools.javac.code.Symbol.*;
import static com.sun.tools.javac.code.Type.*;
import static com.sun.tools.javac.code.TypeTag.*;
+import static com.sun.tools.javac.jvm.ClassFile.externalize;
import static com.sun.tools.javac.util.ListBuffer.lb;
/**
@@ -4354,4 +4355,172 @@
return vis;
}
//
+
+ //
+
+ public static abstract class SignatureGenerator {
+
+ private final Types types;
+
+ protected abstract void append(char ch);
+ protected abstract void append(byte[] ba);
+ protected abstract void append(Name name);
+ protected void classReference(ClassSymbol c) { /* by default: no-op */ }
+
+ protected SignatureGenerator(Types types) {
+ this.types = types;
+ }
+
+ /**
+ * Assemble signature of given type in string buffer.
+ */
+ public void assembleSig(Type type) {
+ type = type.unannotatedType();
+ switch (type.getTag()) {
+ case BYTE:
+ append('B');
+ break;
+ case SHORT:
+ append('S');
+ break;
+ case CHAR:
+ append('C');
+ break;
+ case INT:
+ append('I');
+ break;
+ case LONG:
+ append('J');
+ break;
+ case FLOAT:
+ append('F');
+ break;
+ case DOUBLE:
+ append('D');
+ break;
+ case BOOLEAN:
+ append('Z');
+ break;
+ case VOID:
+ append('V');
+ break;
+ case CLASS:
+ append('L');
+ assembleClassSig(type);
+ append(';');
+ break;
+ case ARRAY:
+ ArrayType at = (ArrayType) type;
+ append('[');
+ assembleSig(at.elemtype);
+ break;
+ case METHOD:
+ MethodType mt = (MethodType) type;
+ append('(');
+ assembleSig(mt.argtypes);
+ append(')');
+ assembleSig(mt.restype);
+ if (hasTypeVar(mt.thrown)) {
+ for (List l = mt.thrown; l.nonEmpty(); l = l.tail) {
+ append('^');
+ assembleSig(l.head);
+ }
+ }
+ break;
+ case WILDCARD: {
+ Type.WildcardType ta = (Type.WildcardType) type;
+ switch (ta.kind) {
+ case SUPER:
+ append('-');
+ assembleSig(ta.type);
+ break;
+ case EXTENDS:
+ append('+');
+ assembleSig(ta.type);
+ break;
+ case UNBOUND:
+ append('*');
+ break;
+ default:
+ throw new AssertionError(ta.kind);
+ }
+ break;
+ }
+ case TYPEVAR:
+ append('T');
+ append(type.tsym.name);
+ append(';');
+ break;
+ case FORALL:
+ Type.ForAll ft = (Type.ForAll) type;
+ assembleParamsSig(ft.tvars);
+ assembleSig(ft.qtype);
+ break;
+ default:
+ throw new AssertionError("typeSig " + type.getTag());
+ }
+ }
+
+ public boolean hasTypeVar(List l) {
+ while (l.nonEmpty()) {
+ if (l.head.hasTag(TypeTag.TYPEVAR)) {
+ return true;
+ }
+ l = l.tail;
+ }
+ return false;
+ }
+
+ public void assembleClassSig(Type type) {
+ type = type.unannotatedType();
+ ClassType ct = (ClassType) type;
+ ClassSymbol c = (ClassSymbol) ct.tsym;
+ classReference(c);
+ Type outer = ct.getEnclosingType();
+ if (outer.allparams().nonEmpty()) {
+ boolean rawOuter =
+ c.owner.kind == Kinds.MTH || // either a local class
+ c.name == types.names.empty; // or anonymous
+ assembleClassSig(rawOuter
+ ? types.erasure(outer)
+ : outer);
+ append('.');
+ Assert.check(c.flatname.startsWith(c.owner.enclClass().flatname));
+ append(rawOuter
+ ? c.flatname.subName(c.owner.enclClass().flatname.getByteLength() + 1, c.flatname.getByteLength())
+ : c.name);
+ } else {
+ append(externalize(c.flatname));
+ }
+ if (ct.getTypeArguments().nonEmpty()) {
+ append('<');
+ assembleSig(ct.getTypeArguments());
+ append('>');
+ }
+ }
+
+ public void assembleParamsSig(List typarams) {
+ append('<');
+ for (List ts = typarams; ts.nonEmpty(); ts = ts.tail) {
+ Type.TypeVar tvar = (Type.TypeVar) ts.head;
+ append(tvar.tsym.name);
+ List bounds = types.getBounds(tvar);
+ if ((bounds.head.tsym.flags() & INTERFACE) != 0) {
+ append(':');
+ }
+ for (List l = bounds; l.nonEmpty(); l = l.tail) {
+ append(':');
+ assembleSig(l.head);
+ }
+ }
+ append('>');
+ }
+
+ private void assembleSig(List types) {
+ for (List ts = types; ts.nonEmpty(); ts = ts.tail) {
+ assembleSig(ts.head);
+ }
+ }
+ }
+ //
}
diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Feb 15 11:26:11 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Feb 15 18:40:38 2013 -0800
@@ -31,8 +31,8 @@
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.tree.TreeTranslator;
-import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
@@ -57,9 +57,7 @@
import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Kinds.*;
-import static com.sun.tools.javac.code.TypeTag.BOT;
-import static com.sun.tools.javac.code.TypeTag.NONE;
-import static com.sun.tools.javac.code.TypeTag.VOID;
+import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
/**
@@ -89,9 +87,51 @@
/** current translation context (visitor argument) */
private TranslationContext> context;
- /** list of translated methods
- **/
- private ListBuffer translatedMethodList;
+ /** info about the current class being processed */
+ private KlassInfo kInfo;
+
+ /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
+ public static final int FLAG_SERIALIZABLE = 1 << 0;
+
+ /** Flag for alternate metafactories indicating the lambda object has multiple targets */
+ public static final int FLAG_MARKERS = 1 << 1;
+
+ private class KlassInfo {
+
+ /**
+ * list of methods to append
+ */
+ private ListBuffer appendedMethodList;
+
+ /**
+ * list of deserialization cases
+ */
+ private final Map> deserializeCases;
+
+ /**
+ * deserialize method symbol
+ */
+ private final MethodSymbol deserMethodSym;
+
+ /**
+ * deserialize method parameter symbol
+ */
+ private final VarSymbol deserParamSym;
+
+ private KlassInfo(Symbol kSym) {
+ appendedMethodList = ListBuffer.lb();
+ deserializeCases = new HashMap>();
+ long flags = PRIVATE | STATIC | SYNTHETIC;
+ MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
+ List.nil(), syms.methodClass);
+ deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym);
+ deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), syms.serializedLambdaType, deserMethodSym);
+ }
+
+ private void addMethod(JCTree decl) {
+ appendedMethodList = appendedMethodList.prepend(decl);
+ }
+ }
//
private static final Context.Key unlambdaKey =
@@ -112,11 +152,7 @@
make = TreeMaker.instance(context);
types = Types.instance(context);
transTypes = TransTypes.instance(context);
- this.analyzer = makeAnalyzer();
- }
-
- private LambdaAnalyzer makeAnalyzer() {
- return new LambdaAnalyzer();
+ analyzer = new LambdaAnalyzer();
}
//
@@ -168,18 +204,22 @@
//analyze class
analyzer.analyzeClass(tree);
}
- ListBuffer prevTranslated = translatedMethodList;
+ KlassInfo prevKlassInfo = kInfo;
try {
- translatedMethodList = ListBuffer.lb();
+ kInfo = new KlassInfo(tree.sym);
super.visitClassDef(tree);
+ if (!kInfo.deserializeCases.isEmpty()) {
+ kInfo.addMethod(makeDeserializeMethod(tree.sym));
+ }
//add all translated instance methods here
- tree.defs = tree.defs.appendList(translatedMethodList.toList());
- for (JCTree lambda : translatedMethodList) {
+ List newMethods = kInfo.appendedMethodList.toList();
+ tree.defs = tree.defs.appendList(newMethods);
+ for (JCTree lambda : newMethods) {
tree.sym.members().enter(((JCMethodDecl)lambda).sym);
}
result = tree;
} finally {
- translatedMethodList = prevTranslated;
+ kInfo = prevKlassInfo;
}
}
@@ -217,7 +257,7 @@
lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
//Add the method to the list of methods to be added to this class.
- translatedMethodList = translatedMethodList.prepend(lambdaDecl);
+ kInfo.addMethod(lambdaDecl);
//now that we have generated a method for the lambda expression,
//we can translate the lambda into a method reference pointing to the newly
@@ -234,7 +274,7 @@
if (!sym.isStatic()) {
syntheticInits.append(makeThis(
- sym.owner.asType(),
+ sym.owner.enclClass().asType(),
localContext.owner.enclClass()));
}
@@ -253,7 +293,7 @@
int refKind = referenceKind(sym);
//convert to an invokedynamic call
- result = makeMetaFactoryIndyCall(tree, refKind, sym, indy_args);
+ result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args);
}
private JCIdent makeThis(Type type, Symbol owner) {
@@ -291,8 +331,8 @@
case IMPLICIT_INNER: /** Inner :: new */
case SUPER: /** super :: instMethod */
init = makeThis(
- localContext.owner.owner.asType(),
- localContext.owner);
+ localContext.owner.enclClass().asType(),
+ localContext.owner.enclClass());
break;
case BOUND: /** Expr :: instMethod */
@@ -314,7 +354,7 @@
//build a sam instance using an indy call to the meta-factory
- result = makeMetaFactoryIndyCall(tree, localContext.referenceKind(), refSym, indy_args);
+ result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args);
}
/**
@@ -333,6 +373,9 @@
} else if (lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
Symbol translatedSym = lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
result = make.Ident(translatedSym).setType(tree.type);
+ } else if (lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
+ Symbol translatedSym = lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
+ result = make.Ident(translatedSym).setType(translatedSym.type);
} else if (lambdaContext.getSymbolMap(CAPTURED_VAR).containsKey(tree.sym)) {
Symbol translatedSym = lambdaContext.getSymbolMap(CAPTURED_VAR).get(tree.sym);
result = make.Ident(translatedSym).setType(tree.type);
@@ -362,6 +405,16 @@
if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
JCExpression init = translate(tree.init);
result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
+ } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
+ JCExpression init = translate(tree.init);
+ VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
+ result = make.VarDef(xsym, init);
+ // Replace the entered symbol for this variable
+ Scope sc = tree.sym.owner.members();
+ if (sc != null) {
+ sc.remove(tree.sym);
+ sc.enter(xsym);
+ }
} else {
super.visitVarDef(tree);
}
@@ -451,6 +504,135 @@
return trans_block;
}
+ private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
+ ListBuffer cases = ListBuffer.lb();
+ ListBuffer breaks = ListBuffer.lb();
+ for (Map.Entry> entry : kInfo.deserializeCases.entrySet()) {
+ JCBreak br = make.Break(null);
+ breaks.add(br);
+ List stmts = entry.getValue().append(br).toList();
+ cases.add(make.Case(make.Literal(entry.getKey()), stmts));
+ }
+ JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
+ for (JCBreak br : breaks) {
+ br.target = sw;
+ }
+ JCBlock body = make.Block(0L, List.of(
+ sw,
+ make.Throw(makeNewClass(
+ syms.illegalArgumentExceptionType,
+ List.of(make.Literal("Invalid lambda deserialization"))))));
+ JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
+ names.deserializeLambda,
+ make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
+ List.nil(),
+ List.of(make.VarDef(kInfo.deserParamSym, null)),
+ List.nil(),
+ body,
+ null);
+ deser.sym = kInfo.deserMethodSym;
+ deser.type = kInfo.deserMethodSym.type;
+ //System.err.printf("DESER: '%s'\n", deser);
+ return deser;
+ }
+
+ /** Make an attributed class instance creation expression.
+ * @param ctype The class type.
+ * @param args The constructor arguments.
+ */
+ JCNewClass makeNewClass(Type ctype, List args) {
+ JCNewClass tree = make.NewClass(null,
+ null, make.QualIdent(ctype.tsym), args, null);
+ tree.constructor = rs.resolveConstructor(
+ null, attrEnv, ctype, TreeInfo.types(args), List.nil());
+ tree.type = ctype;
+ return tree;
+ }
+
+ private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
+ DiagnosticPosition pos, List