提交 468e329f 编写于 作者: R rfield

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
上级 73619702
......@@ -126,6 +126,7 @@ public class Symtab {
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 @@ public class Symtab {
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 @@ public class Symtab {
synthesizeEmptyInterfaceIfMissing(cloneableType);
synthesizeEmptyInterfaceIfMissing(serializableType);
synthesizeEmptyInterfaceIfMissing(lambdaMetafactory);
synthesizeEmptyInterfaceIfMissing(serializedLambdaType);
synthesizeBoxTypeIfMissing(doubleType);
synthesizeBoxTypeIfMissing(floatType);
synthesizeBoxTypeIfMissing(voidType);
......
......@@ -48,6 +48,7 @@ import static com.sun.tools.javac.code.Scope.*;
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 @@ public class Types {
return vis;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Signature Generation">
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<Type> 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<Type> 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<Type> typarams) {
append('<');
for (List<Type> ts = typarams; ts.nonEmpty(); ts = ts.tail) {
Type.TypeVar tvar = (Type.TypeVar) ts.head;
append(tvar.tsym.name);
List<Type> bounds = types.getBounds(tvar);
if ((bounds.head.tsym.flags() & INTERFACE) != 0) {
append(':');
}
for (List<Type> l = bounds; l.nonEmpty(); l = l.tail) {
append(':');
assembleSig(l.head);
}
}
append('>');
}
private void assembleSig(List<Type> types) {
for (List<Type> ts = types; ts.nonEmpty(); ts = ts.tail) {
assembleSig(ts.head);
}
}
}
// </editor-fold>
}
......@@ -309,7 +309,9 @@ public class ClassReader implements Completer {
/** Add member to class unless it is synthetic.
*/
private void enterMember(ClassSymbol c, Symbol sym) {
if ((sym.flags_field & (SYNTHETIC|BRIDGE)) != SYNTHETIC)
// Synthetic members are not entered -- reason lost to history (optimization?).
// Lambda methods must be entered because they may have inner classes (which reference them)
if ((sym.flags_field & (SYNTHETIC|BRIDGE)) != SYNTHETIC || sym.name.startsWith(names.lambda))
c.members_field.enter(sym);
}
......
......@@ -39,6 +39,9 @@ import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
import com.sun.tools.javac.code.Attribute.TypeCompound;
import static com.sun.tools.javac.code.BoundKind.EXTENDS;
import static com.sun.tools.javac.code.BoundKind.SUPER;
import static com.sun.tools.javac.code.BoundKind.UNBOUND;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Types.UniqueType;
......@@ -126,10 +129,6 @@ public class ClassWriter extends ClassFile {
*/
ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
/** An output buffer for type signatures.
*/
ByteBuffer sigbuf = new ByteBuffer();
/** The constant pool.
*/
Pool pool;
......@@ -158,6 +157,9 @@ public class ClassWriter extends ClassFile {
/** Access to files. */
private final JavaFileManager fileManager;
/** Sole signature generator */
private final CWSignatureGenerator signatureGen;
/** The tags and constants used in compressed stackmap. */
static final int SAME_FRAME_SIZE = 64;
static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
......@@ -185,6 +187,7 @@ public class ClassWriter extends ClassFile {
source = Source.instance(context);
types = Types.instance(context);
fileManager = context.get(JavaFileManager.class);
signatureGen = new CWSignatureGenerator(types);
verbose = options.isSet(VERBOSE);
scramble = options.isSet("-scramble");
......@@ -270,172 +273,81 @@ public class ClassWriter extends ClassFile {
buf.elems[adr+3] = (byte)((x ) & 0xFF);
}
/******************************************************************
* Signature Generation
******************************************************************/
/** Assemble signature of given type in string buffer.
/**
* Signature Generation
*/
void assembleSig(Type type) {
type = type.unannotatedType();
switch (type.getTag()) {
case BYTE:
sigbuf.appendByte('B');
break;
case SHORT:
sigbuf.appendByte('S');
break;
case CHAR:
sigbuf.appendByte('C');
break;
case INT:
sigbuf.appendByte('I');
break;
case LONG:
sigbuf.appendByte('J');
break;
case FLOAT:
sigbuf.appendByte('F');
break;
case DOUBLE:
sigbuf.appendByte('D');
break;
case BOOLEAN:
sigbuf.appendByte('Z');
break;
case VOID:
sigbuf.appendByte('V');
break;
case CLASS:
sigbuf.appendByte('L');
assembleClassSig(type);
sigbuf.appendByte(';');
break;
case ARRAY:
ArrayType at = (ArrayType)type;
sigbuf.appendByte('[');
assembleSig(at.elemtype);
break;
case METHOD:
MethodType mt = (MethodType)type;
sigbuf.appendByte('(');
assembleSig(mt.argtypes);
sigbuf.appendByte(')');
assembleSig(mt.restype);
if (hasTypeVar(mt.thrown)) {
for (List<Type> l = mt.thrown; l.nonEmpty(); l = l.tail) {
sigbuf.appendByte('^');
assembleSig(l.head);
}
}
break;
case WILDCARD: {
WildcardType ta = (WildcardType) type;
switch (ta.kind) {
case SUPER:
sigbuf.appendByte('-');
assembleSig(ta.type);
break;
case EXTENDS:
sigbuf.appendByte('+');
assembleSig(ta.type);
break;
case UNBOUND:
sigbuf.appendByte('*');
break;
default:
throw new AssertionError(ta.kind);
private class CWSignatureGenerator extends Types.SignatureGenerator {
/**
* An output buffer for type signatures.
*/
ByteBuffer sigbuf = new ByteBuffer();
CWSignatureGenerator(Types types) {
super(types);
}
/**
* Assemble signature of given type in string buffer.
* Check for uninitialized types before calling the general case.
*/
@Override
public void assembleSig(Type type) {
type = type.unannotatedType();
switch (type.getTag()) {
case UNINITIALIZED_THIS:
case UNINITIALIZED_OBJECT:
// we don't yet have a spec for uninitialized types in the
// local variable table
assembleSig(types.erasure(((UninitializedType)type).qtype));
break;
default:
super.assembleSig(type);
}
break;
}
case TYPEVAR:
sigbuf.appendByte('T');
sigbuf.appendName(type.tsym.name);
sigbuf.appendByte(';');
break;
case FORALL:
ForAll ft = (ForAll)type;
assembleParamsSig(ft.tvars);
assembleSig(ft.qtype);
break;
case UNINITIALIZED_THIS:
case UNINITIALIZED_OBJECT:
// we don't yet have a spec for uninitialized types in the
// local variable table
assembleSig(types.erasure(((UninitializedType)type).qtype));
break;
default:
throw new AssertionError("typeSig " + type.getTag());
@Override
protected void append(char ch) {
sigbuf.appendByte(ch);
}
}
boolean hasTypeVar(List<Type> l) {
while (l.nonEmpty()) {
if (l.head.hasTag(TYPEVAR)) return true;
l = l.tail;
@Override
protected void append(byte[] ba) {
sigbuf.appendBytes(ba);
}
return false;
}
void assembleClassSig(Type type) {
type = type.unannotatedType();
ClassType ct = (ClassType)type;
ClassSymbol c = (ClassSymbol)ct.tsym;
enterInner(c);
Type outer = ct.getEnclosingType();
if (outer.allparams().nonEmpty()) {
boolean rawOuter =
c.owner.kind == MTH || // either a local class
c.name == names.empty; // or anonymous
assembleClassSig(rawOuter
? types.erasure(outer)
: outer);
sigbuf.appendByte('.');
Assert.check(c.flatname.startsWith(c.owner.enclClass().flatname));
sigbuf.appendName(rawOuter
? c.flatname.subName(c.owner.enclClass().flatname.getByteLength()+1,c.flatname.getByteLength())
: c.name);
} else {
sigbuf.appendBytes(externalize(c.flatname));
@Override
protected void append(Name name) {
sigbuf.appendName(name);
}
if (ct.getTypeArguments().nonEmpty()) {
sigbuf.appendByte('<');
assembleSig(ct.getTypeArguments());
sigbuf.appendByte('>');
@Override
protected void classReference(ClassSymbol c) {
enterInner(c);
}
}
private void reset() {
sigbuf.reset();
}
void assembleSig(List<Type> types) {
for (List<Type> ts = types; ts.nonEmpty(); ts = ts.tail)
assembleSig(ts.head);
}
private Name toName() {
return sigbuf.toName(names);
}
void assembleParamsSig(List<Type> typarams) {
sigbuf.appendByte('<');
for (List<Type> ts = typarams; ts.nonEmpty(); ts = ts.tail) {
TypeVar tvar = (TypeVar)ts.head;
sigbuf.appendName(tvar.tsym.name);
List<Type> bounds = types.getBounds(tvar);
if ((bounds.head.tsym.flags() & INTERFACE) != 0) {
sigbuf.appendByte(':');
}
for (List<Type> l = bounds; l.nonEmpty(); l = l.tail) {
sigbuf.appendByte(':');
assembleSig(l.head);
}
private boolean isEmpty() {
return sigbuf.length == 0;
}
sigbuf.appendByte('>');
}
/** Return signature of given type
/**
* Return signature of given type
*/
Name typeSig(Type type) {
Assert.check(sigbuf.length == 0);
Assert.check(signatureGen.isEmpty());
//- System.out.println(" ? " + type);
assembleSig(type);
Name n = sigbuf.toName(names);
sigbuf.reset();
signatureGen.assembleSig(type);
Name n = signatureGen.toName();
signatureGen.reset();
//- System.out.println(" " + n);
return n;
}
......@@ -711,7 +623,7 @@ public class ClassWriter extends ClassFile {
(flags & (SYNTHETIC|BRIDGE)) != SYNTHETIC &&
(flags & ANONCONSTR) == 0 &&
(!types.isSameType(sym.type, sym.erasure(types)) ||
hasTypeVar(sym.type.getThrownTypes()))) {
signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
// note that a local class with captured variables
// will get a signature attribute
int alenIdx = writeAttr(names.Signature);
......@@ -1730,7 +1642,7 @@ public class ClassWriter extends ClassFile {
Assert.check((c.flags() & COMPOUND) == 0);
databuf.reset();
poolbuf.reset();
sigbuf.reset();
signatureGen.reset();
pool = c.pool;
innerClasses = null;
innerClassesQueue = null;
......@@ -1791,12 +1703,12 @@ public class ClassWriter extends ClassFile {
if (sigReq) {
Assert.check(source.allowGenerics());
int alenIdx = writeAttr(names.Signature);
if (typarams.length() != 0) assembleParamsSig(typarams);
assembleSig(supertype);
if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams);
signatureGen.assembleSig(supertype);
for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
assembleSig(l.head);
databuf.appendChar(pool.put(sigbuf.toName(names)));
sigbuf.reset();
signatureGen.assembleSig(l.head);
databuf.appendChar(pool.put(signatureGen.toName()));
signatureGen.reset();
endAttr(alenIdx);
acount++;
}
......
......@@ -73,6 +73,7 @@ public class Names {
public final Name clone;
public final Name close;
public final Name compareTo;
public final Name deserializeLambda;
public final Name desiredAssertionStatus;
public final Name equals;
public final Name error;
......@@ -174,6 +175,7 @@ public class Names {
//lambda-related
public final Name lambda;
public final Name metaFactory;
public final Name altMetaFactory;
public final Name.Table table;
......@@ -207,6 +209,7 @@ public class Names {
clone = fromString("clone");
close = fromString("close");
compareTo = fromString("compareTo");
deserializeLambda = fromString("$deserializeLambda$");
desiredAssertionStatus = fromString("desiredAssertionStatus");
equals = fromString("equals");
error = fromString("<error>");
......@@ -306,8 +309,9 @@ public class Names {
package_info = fromString("package-info");
//lambda-related
lambda = fromString("lambda");
lambda = fromString("lambda$");
metaFactory = fromString("metaFactory");
altMetaFactory = fromString("altMetaFactory");
}
protected Name.Table createTable(Options options) {
......
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8005653
* @summary A lambda containing an inner class referencing an external type var in class parameter type
* @author Robert Field
* @run main LambdaInnerTypeVarArgs
*/
import java.io.Serializable;
import java.util.List;
import java.util.ArrayList;
public class LambdaInnerTypeVarArgs {
static int assertionCount = 0;
static void assertTrue(boolean cond) {
assertionCount++;
if (!cond)
throw new AssertionError();
}
interface I {
C doit();
}
abstract class C {
abstract Object it();
}
class TV {
C go() {
List<String> ls = new ArrayList<>();
ls.add("Oh");
ls.add("my");
return foo(ls).doit();
}
<RRRRR> I foo(List<RRRRR> r) {
return () -> new C() {
List<RRRRR> xxxxx = r;
@Override
Object it() { return xxxxx; };
};
}
}
void test1() {
assertTrue(((List<String>)(new TV().go().it())).get(0).equals("Oh"));
}
public static void main(String[] args) {
LambdaInnerTypeVarArgs t = new LambdaInnerTypeVarArgs();
t.test1();
assertTrue(assertionCount == 1);
}
}
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8005653
* @summary A lambda containing an inner class referencing an external type var
* @author Robert Field
* @run main LambdaInnerTypeVarReflect
*/
import java.io.StringWriter;
import java.io.PrintWriter;
import java.io.IOException;
public class LambdaInnerTypeVarReflect {
static int assertionCount = 0;
static void assertTrue(boolean cond) {
assertionCount++;
if (!cond)
throw new AssertionError();
}
interface I {
C doit();
}
abstract class C {
abstract Object it();
}
class TV {
C go() {
return foo("Frump").doit();
}
<RRRRR> I foo(RRRRR r) {
return () -> new C() {
public RRRRR xxxxx = r;
@Override
Object it() { return xxxxx; };
};
}
}
void test1() throws IOException {
char[] buffer = new char[1024];
String innerName = new TV().go().getClass().getName();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
int exitCode = com.sun.tools.javap.Main.run(new String[] {innerName}, pw);
assertTrue(exitCode == 0);
String javapOut = sw.toString();
assertTrue(javapOut.contains(innerName));
assertTrue(!javapOut.contains("RRRRR"));
}
public static void main(String[] args) throws IOException {
LambdaInnerTypeVarReflect t = new LambdaInnerTypeVarReflect();
t.test1();
assertTrue(assertionCount == 3);
}
}
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8006763
* @summary super in method reference used in anonymous class
*/
public class MethodReference61 {
interface SAM {
void m();
}
static class MyTester {
public void ifoo() { }
}
public static void main(String args[]) {
MyTester t = new MyTester() {
SAM s = super::ifoo;
};
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册