mirror of
https://github.com/corda/corda.git
synced 2025-04-25 05:19:44 +00:00
Handle multiple interface lambdas, stubs to handle bridging, marker interfaces
This commit is contained in:
parent
8ff5f2a26a
commit
52d1ca9799
@ -33,9 +33,17 @@ import avian.Assembler;
|
|||||||
import avian.ConstantPool.PoolEntry;
|
import avian.ConstantPool.PoolEntry;
|
||||||
import avian.SystemClassLoader;
|
import avian.SystemClassLoader;
|
||||||
|
|
||||||
|
// To understand what this is all about, please read:
|
||||||
|
//
|
||||||
|
// http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html
|
||||||
|
|
||||||
public class LambdaMetafactory {
|
public class LambdaMetafactory {
|
||||||
private static int nextNumber = 0;
|
private static int nextNumber = 0;
|
||||||
|
|
||||||
|
public static final int FLAG_SERIALIZABLE = 1;
|
||||||
|
public static final int FLAG_MARKERS = 2;
|
||||||
|
public static final int FLAG_BRIDGES = 4;
|
||||||
|
|
||||||
private static Class resolveReturnInterface(MethodType type) {
|
private static Class resolveReturnInterface(MethodType type) {
|
||||||
int index = 1;
|
int index = 1;
|
||||||
byte[] s = type.spec;
|
byte[] s = type.spec;
|
||||||
@ -212,13 +220,15 @@ public class LambdaMetafactory {
|
|||||||
new MethodHandle(implementationClass,
|
new MethodHandle(implementationClass,
|
||||||
implementationName,
|
implementationName,
|
||||||
implementationSpec,
|
implementationSpec,
|
||||||
implementationKind));
|
implementationKind),
|
||||||
|
emptyInterfaceList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] makeLambda(String invokedName,
|
private static byte[] makeLambda(String invokedName,
|
||||||
MethodType invokedType,
|
MethodType invokedType,
|
||||||
MethodType methodType,
|
MethodType methodType,
|
||||||
MethodHandle methodImplementation)
|
MethodHandle methodImplementation,
|
||||||
|
Class[] interfaces)
|
||||||
{
|
{
|
||||||
String className;
|
String className;
|
||||||
{ int number;
|
{ int number;
|
||||||
@ -230,8 +240,12 @@ public class LambdaMetafactory {
|
|||||||
|
|
||||||
List<PoolEntry> pool = new ArrayList();
|
List<PoolEntry> pool = new ArrayList();
|
||||||
|
|
||||||
int interfaceIndex = ConstantPool.addClass
|
int[] interfaceIndexes = new int[interfaces.length + 1];
|
||||||
(pool, invokedType.returnType().getName().replace('.', '/'));
|
interfaceIndexes[0] = ConstantPool.addClass(pool, invokedType.returnType().getName().replace('.', '/'));
|
||||||
|
for (int i = 0; i < interfaces.length; i++) {
|
||||||
|
String name = interfaces[i].getName().replace('.', '/');
|
||||||
|
interfaceIndexes[i + 1] = ConstantPool.addClass(pool, name);
|
||||||
|
}
|
||||||
|
|
||||||
List<FieldData> fieldTable = new ArrayList();
|
List<FieldData> fieldTable = new ArrayList();
|
||||||
|
|
||||||
@ -280,7 +294,7 @@ public class LambdaMetafactory {
|
|||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
try {
|
try {
|
||||||
Assembler.writeClass
|
Assembler.writeClass
|
||||||
(out, pool, nameIndex, superIndex, new int[] { interfaceIndex },
|
(out, pool, nameIndex, superIndex, interfaceIndexes,
|
||||||
fieldTable.toArray(new FieldData[fieldTable.size()]),
|
fieldTable.toArray(new FieldData[fieldTable.size()]),
|
||||||
methodTable.toArray(new MethodData[methodTable.size()]));
|
methodTable.toArray(new MethodData[methodTable.size()]));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -292,16 +306,7 @@ public class LambdaMetafactory {
|
|||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CallSite metafactory(MethodHandles.Lookup caller,
|
private static CallSite makeCallSite(MethodType invokedType, byte[] classData) throws AssertionError {
|
||||||
String invokedName,
|
|
||||||
MethodType invokedType,
|
|
||||||
MethodType methodType,
|
|
||||||
MethodHandle methodImplementation,
|
|
||||||
MethodType instantiatedMethodType)
|
|
||||||
throws LambdaConversionException
|
|
||||||
{
|
|
||||||
byte[] classData = makeLambda(invokedName, invokedType, methodType, methodImplementation);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new CallSite
|
return new CallSite
|
||||||
(new MethodHandle
|
(new MethodHandle
|
||||||
@ -317,13 +322,89 @@ public class LambdaMetafactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Class[] emptyInterfaceList = new Class[] {};
|
||||||
|
|
||||||
|
public static CallSite metafactory(MethodHandles.Lookup caller,
|
||||||
|
String invokedName,
|
||||||
|
MethodType invokedType,
|
||||||
|
MethodType methodType,
|
||||||
|
MethodHandle methodImplementation,
|
||||||
|
MethodType instantiatedMethodType)
|
||||||
|
throws LambdaConversionException
|
||||||
|
{
|
||||||
|
byte[] classData = makeLambda(invokedName, invokedType, methodType, methodImplementation, emptyInterfaceList);
|
||||||
|
return makeCallSite(invokedType, classData);
|
||||||
|
}
|
||||||
|
|
||||||
public static CallSite altMetafactory(MethodHandles.Lookup caller,
|
public static CallSite altMetafactory(MethodHandles.Lookup caller,
|
||||||
String invokedName,
|
String invokedName,
|
||||||
MethodType invokedType,
|
MethodType invokedType,
|
||||||
Object... args)
|
Object... args) throws LambdaConversionException {
|
||||||
throws LambdaConversionException
|
// Behaves as if the prototype is like this:
|
||||||
{
|
//
|
||||||
// todo: handle flags
|
// CallSite altMetafactory(
|
||||||
return metafactory(caller, invokedName, invokedType, (MethodType) args[0], (MethodHandle) args[1], (MethodType) args[2]);
|
// MethodHandles.Lookup caller,
|
||||||
|
// String invokedName,
|
||||||
|
// MethodType invokedType,
|
||||||
|
// MethodType methodType,
|
||||||
|
// MethodHandle methodImplementation,
|
||||||
|
// MethodType instantiatedMethodType,
|
||||||
|
// int flags,
|
||||||
|
// int markerInterfaceCount, // IF flags has MARKERS set
|
||||||
|
// Class... markerInterfaces, // IF flags has MARKERS set
|
||||||
|
// int bridgeCount, // IF flags has BRIDGES set
|
||||||
|
// MethodType... bridges // IF flags has BRIDGES set
|
||||||
|
// )
|
||||||
|
|
||||||
|
MethodType methodType = (MethodType) args[0];
|
||||||
|
MethodHandle methodImplementation = (MethodHandle) args[1];
|
||||||
|
|
||||||
|
int flags = (Integer) args[3];
|
||||||
|
boolean serializable = (flags & FLAG_SERIALIZABLE) != 0;
|
||||||
|
|
||||||
|
// Marker interfaces are added to a lambda when they're written like this:
|
||||||
|
//
|
||||||
|
// Runnable r = (Runnable & Serializable) () -> foo()
|
||||||
|
//
|
||||||
|
// The intersection type in the cast here indicates to the compiler what interfaces
|
||||||
|
// the generated lambda class should implement. Because a lambda has (by definition)
|
||||||
|
// one method only, it is meaningless for these interfaces to contain anything, thus
|
||||||
|
// they are only allowed to be empty marker interfaces. In practice the Serializable
|
||||||
|
// interface is handled specially and the use of markers is extremely rare. Adding
|
||||||
|
// support would be easy though.
|
||||||
|
if ((flags & FLAG_MARKERS) != 0)
|
||||||
|
throw new UnsupportedOperationException("Marker interfaces on lambdas are not supported on Avian yet. Sorry.");
|
||||||
|
|
||||||
|
// In some cases there is a mismatch between what the JVM type system supports and
|
||||||
|
// what the Java language supports. In other cases the type of a lambda expression
|
||||||
|
// may not perfectly match the functional interface which represents it. Consider the
|
||||||
|
// following case:
|
||||||
|
//
|
||||||
|
// interface I { void foo(Integer i, String s1, Strings s2) }
|
||||||
|
// class Foo { static void m(Number i, Object... rest) {} }
|
||||||
|
//
|
||||||
|
// I lambda = Foo::m
|
||||||
|
//
|
||||||
|
// This is allowed by the Java language, even though the interface representing the
|
||||||
|
// lambda specifies three specific arguments and the method implementing the lambda
|
||||||
|
// uses varargs and a different type signature. Behind the scenes the compiler generates
|
||||||
|
// a "bridge" method that does the adaptation.
|
||||||
|
//
|
||||||
|
// You can learn more here: http://www.oracle.com/technetwork/java/jvmls2013heid-2013922.pdf
|
||||||
|
// and here: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html
|
||||||
|
if ((flags & FLAG_BRIDGES) != 0) {
|
||||||
|
int bridgeCount = (Integer) args[4];
|
||||||
|
if (bridgeCount > 0)
|
||||||
|
throw new UnsupportedOperationException("A lambda that requires bridge methods was used, this is not yet supported by Avian. Sorry.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This is not necessary if the function type interface is already inheriting
|
||||||
|
// from Serializable.
|
||||||
|
Class[] interfaces = new Class[serializable ? 1 : 0];
|
||||||
|
if (serializable)
|
||||||
|
interfaces[0] = java.io.Serializable.class;
|
||||||
|
|
||||||
|
byte[] classData = makeLambda(invokedName, invokedType, methodType, methodImplementation, interfaces);
|
||||||
|
return makeCallSite(invokedType, classData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user