mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
fix some lambda bugs
For lambdas that implement java.io.Serializable, the compiler emits calls to LambdaMetaFactory.altMetafactory, not LambdaMetaFactory.metafactory, so I've provided a stub implementation that ignores that currently ignores the extra parameters it receives. This also fixes a bug in compiling lambda glue code for lambdas that take longs and/or doubles.
This commit is contained in:
parent
a4d9037ae4
commit
69426b9945
@ -25,17 +25,17 @@ import avian.SystemClassLoader;
|
||||
|
||||
public class LambdaMetafactory {
|
||||
private static int nextNumber = 0;
|
||||
|
||||
|
||||
private static Class resolveReturnInterface(MethodType type) {
|
||||
int index = 1;
|
||||
byte[] s = type.spec;
|
||||
|
||||
|
||||
while (s[index] != ')') ++ index;
|
||||
|
||||
|
||||
if (s[++ index] != 'L') throw new AssertionError();
|
||||
|
||||
|
||||
++ index;
|
||||
|
||||
|
||||
int end = index + 1;
|
||||
while (s[end] != ';') ++ end;
|
||||
|
||||
@ -52,11 +52,11 @@ public class LambdaMetafactory {
|
||||
while (array[i] != c) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
private static String constructorSpec(MethodType type) {
|
||||
return Classes.makeString(type.spec, 0, indexOf(')', type.spec) + 1) + "V";
|
||||
}
|
||||
|
||||
|
||||
private static byte[] makeFactoryCode(List<PoolEntry> pool,
|
||||
String className,
|
||||
String constructorSpec,
|
||||
@ -89,7 +89,7 @@ public class LambdaMetafactory {
|
||||
byte[] result = out.toByteArray();
|
||||
set4(result, 4, result.length - 12);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static byte[] makeConstructorCode(List<PoolEntry> pool,
|
||||
@ -124,7 +124,7 @@ public class LambdaMetafactory {
|
||||
byte[] result = out.toByteArray();
|
||||
set4(result, 4, result.length - 12);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static byte[] makeInvocationCode(List<PoolEntry> pool,
|
||||
@ -167,7 +167,7 @@ public class LambdaMetafactory {
|
||||
default: throw new AssertionError
|
||||
("todo: implement per http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.5");
|
||||
}
|
||||
|
||||
|
||||
write2(out, ConstantPool.addMethodRef
|
||||
(pool,
|
||||
Classes.makeString(implementation.method.class_.name, 0,
|
||||
@ -233,7 +233,7 @@ public class LambdaMetafactory {
|
||||
}
|
||||
|
||||
String constructorSpec = constructorSpec(invokedType);
|
||||
|
||||
|
||||
List<MethodData> methodTable = new ArrayList();
|
||||
|
||||
try {
|
||||
@ -261,9 +261,9 @@ public class LambdaMetafactory {
|
||||
} catch (IOException e) {
|
||||
AssertionError error = new AssertionError();
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
||||
int nameIndex = ConstantPool.addClass(pool, className);
|
||||
int superIndex = ConstantPool.addClass(pool, "java/lang/Object");
|
||||
|
||||
@ -276,12 +276,12 @@ public class LambdaMetafactory {
|
||||
} catch (IOException e) {
|
||||
AssertionError error = new AssertionError();
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
public static CallSite metafactory(MethodHandles.Lookup caller,
|
||||
String invokedName,
|
||||
MethodType invokedType,
|
||||
@ -291,7 +291,7 @@ public class LambdaMetafactory {
|
||||
throws LambdaConversionException
|
||||
{
|
||||
byte[] classData = makeLambda(invokedName, invokedType, methodType, methodImplementation);
|
||||
|
||||
|
||||
try {
|
||||
return new CallSite
|
||||
(new MethodHandle
|
||||
@ -306,4 +306,14 @@ public class LambdaMetafactory {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public static CallSite altMetafactory(MethodHandles.Lookup caller,
|
||||
String invokedName,
|
||||
MethodType invokedType,
|
||||
Object... args)
|
||||
throws LambdaConversionException
|
||||
{
|
||||
// todo: handle flags
|
||||
return metafactory(caller, invokedName, invokedType, (MethodType) args[0], (MethodHandle) args[1], (MethodType) args[2]);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ public final class MethodType implements java.io.Serializable {
|
||||
private static final char[] Primitives = new char[] {
|
||||
'V', 'Z', 'B', 'C', 'S', 'I', 'F', 'J', 'D'
|
||||
};
|
||||
|
||||
|
||||
final ClassLoader loader;
|
||||
final byte[] spec;
|
||||
private volatile List<Parameter> parameters;
|
||||
@ -31,11 +31,11 @@ public final class MethodType implements java.io.Serializable {
|
||||
this.spec = new byte[spec.length() + 1];
|
||||
spec.getBytes(0, spec.length(), this.spec, 0);
|
||||
}
|
||||
|
||||
|
||||
public String toMethodDescriptorString() {
|
||||
return Classes.makeString(spec, 0, spec.length - 1);
|
||||
}
|
||||
|
||||
|
||||
private static String spec(Class c) {
|
||||
if (c.isPrimitive()) {
|
||||
VMClass vmc = Classes.toVMClass(c);
|
||||
@ -56,7 +56,7 @@ public final class MethodType implements java.io.Serializable {
|
||||
Class ... ptypes)
|
||||
{
|
||||
loader = rtype.getClassLoader();
|
||||
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('(');
|
||||
parameters = new ArrayList(ptypes.length);
|
||||
@ -66,7 +66,7 @@ public final class MethodType implements java.io.Serializable {
|
||||
sb.append(spec);
|
||||
|
||||
Type type = type(spec);
|
||||
|
||||
|
||||
parameters.add(new Parameter(i,
|
||||
position,
|
||||
spec,
|
||||
@ -86,7 +86,7 @@ public final class MethodType implements java.io.Serializable {
|
||||
|
||||
this.spec = sb.toString().getBytes();
|
||||
}
|
||||
|
||||
|
||||
public static MethodType methodType(Class rtype,
|
||||
Class ptype0,
|
||||
Class ... ptypes)
|
||||
@ -129,7 +129,7 @@ public final class MethodType implements java.io.Serializable {
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
public Iterable<Parameter> parameters() {
|
||||
if (parameters == null) {
|
||||
List<Parameter> list = new ArrayList();
|
||||
@ -147,7 +147,7 @@ public final class MethodType implements java.io.Serializable {
|
||||
case '[': {
|
||||
++ i;
|
||||
while (spec[i] == '[') ++ i;
|
||||
|
||||
|
||||
switch (spec[i]) {
|
||||
case 'L':
|
||||
++ i;
|
||||
@ -174,7 +174,7 @@ public final class MethodType implements java.io.Serializable {
|
||||
|
||||
String paramSpec = Classes.makeString(spec, start, (i - start) + 1);
|
||||
Type type = type(paramSpec);
|
||||
|
||||
|
||||
list.add(new Parameter
|
||||
(index,
|
||||
position,
|
||||
@ -192,14 +192,14 @@ public final class MethodType implements java.io.Serializable {
|
||||
|
||||
String paramSpec = Classes.makeString(spec, i, spec.length - i - 1);
|
||||
Type type = type(paramSpec);
|
||||
|
||||
|
||||
result = new Result(paramSpec,
|
||||
Classes.forCanonicalName(loader, paramSpec),
|
||||
type.return_);
|
||||
|
||||
|
||||
parameters = list;
|
||||
}
|
||||
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@ -234,18 +234,18 @@ public final class MethodType implements java.io.Serializable {
|
||||
case 'V':
|
||||
return Type.VoidType;
|
||||
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private static enum Type {
|
||||
ObjectType(aload, areturn, 1),
|
||||
IntegerType(iload, ireturn, 1),
|
||||
FloatType(fload, freturn, 1),
|
||||
LongType(lload, lreturn, 1),
|
||||
DoubleType(dload, dreturn, 1),
|
||||
LongType(lload, lreturn, 2),
|
||||
DoubleType(dload, dreturn, 2),
|
||||
VoidType(-1, Assembler.return_, -1);
|
||||
|
||||
|
||||
public final int load;
|
||||
public final int return_;
|
||||
public final int size;
|
||||
@ -256,7 +256,7 @@ public final class MethodType implements java.io.Serializable {
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Parameter {
|
||||
private final int index;
|
||||
private final int position;
|
||||
|
@ -6055,8 +6055,6 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
|
||||
GcNoSuchMethodError::Type));
|
||||
PROTECT(t, bootstrap);
|
||||
|
||||
assertT(t, bootstrap->parameterCount() == 2 + bootstrapArray->length());
|
||||
|
||||
GcLookup* lookup
|
||||
= makeLookup(t, c, ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC);
|
||||
PROTECT(t, lookup);
|
||||
@ -6078,14 +6076,47 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
|
||||
array->setBodyElement(t, argument++, name);
|
||||
array->setBodyElement(t, argument++, type);
|
||||
|
||||
MethodSpecIterator it(
|
||||
t, reinterpret_cast<const char*>(bootstrap->spec()->body().begin()));
|
||||
const char* spec;
|
||||
GcArray* argArray = array;
|
||||
PROTECT(t, argArray);
|
||||
|
||||
if (::strcmp(reinterpret_cast<char*>(bootstrap->spec()->body().begin()),
|
||||
"(Ljava/lang/invoke/MethodHandles$Lookup;"
|
||||
"Ljava/lang/String;"
|
||||
"Ljava/lang/invoke/MethodType;"
|
||||
"[Ljava/lang/Object;)"
|
||||
"Ljava/lang/invoke/CallSite;") == 0) {
|
||||
// LambdaMetaFactory.altMetafactory
|
||||
array = makeArray(t, bootstrapArray->length() - 1);
|
||||
spec = "(Ljava/lang/invoke/MethodHandles$Lookup;"
|
||||
"Ljava/lang/String;"
|
||||
"Ljava/lang/invoke/MethodType;"
|
||||
"Ljava/lang/invoke/MethodType;"
|
||||
"Ljava/lang/invoke/MethodHandle;"
|
||||
"Ljava/lang/invoke/MethodType;"
|
||||
"I"
|
||||
"I"
|
||||
"[Ljava/lang/Class;"
|
||||
"I"
|
||||
"[Ljava/lang/invoke/MethodType;"
|
||||
")Ljava/lang/invoke/CallSite;";
|
||||
} else if (bootstrap->parameterCount() == 2 + bootstrapArray->length()) {
|
||||
spec = reinterpret_cast<char*>(bootstrap->spec()->body().begin());
|
||||
} else {
|
||||
abort(t);
|
||||
}
|
||||
|
||||
MethodSpecIterator it(t, spec);
|
||||
|
||||
for (unsigned i = 0; i < argument; ++i)
|
||||
it.next();
|
||||
|
||||
if (argArray != array) {
|
||||
argument = 0;
|
||||
}
|
||||
|
||||
unsigned i = 0;
|
||||
while (it.hasNext()) {
|
||||
while (i + 1 < bootstrapArray->length() && it.hasNext()) {
|
||||
const char* p = it.next();
|
||||
switch (*p) {
|
||||
case 'L': {
|
||||
@ -6162,8 +6193,12 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
|
||||
? 0
|
||||
: makeMethodHandle(t, REF_invokeSpecial, c->loader(), bootstrap, 0);
|
||||
|
||||
if (argArray != array) {
|
||||
argArray->setBodyElement(t, 3, array);
|
||||
}
|
||||
|
||||
return cast<GcCallSite>(
|
||||
t, t->m->processor->invokeArray(t, bootstrap, handle, array));
|
||||
t, t->m->processor->invokeArray(t, bootstrap, handle, argArray));
|
||||
}
|
||||
|
||||
void noop()
|
||||
|
@ -4,15 +4,33 @@ public class InvokeDynamic {
|
||||
private InvokeDynamic(int foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
|
||||
private interface Operation {
|
||||
int operate(int a, int b);
|
||||
}
|
||||
|
||||
private interface Operation2 {
|
||||
long operate(long a, int b);
|
||||
}
|
||||
|
||||
private static class Pair<A, B> {
|
||||
public final A first;
|
||||
public final B second;
|
||||
|
||||
public Pair(A first, B second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
}
|
||||
|
||||
private interface Supplier<T> extends java.io.Serializable {
|
||||
T get();
|
||||
}
|
||||
|
||||
private static void expect(boolean v) {
|
||||
if (! v) throw new RuntimeException();
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
int c = 4;
|
||||
Operation op = (a, b) -> a + b - c;
|
||||
@ -24,8 +42,19 @@ public class InvokeDynamic {
|
||||
}
|
||||
|
||||
private void test() {
|
||||
int c = 2;
|
||||
Operation op = (a, b) -> ((a + b) * c) - foo;
|
||||
expect(op.operate(2, 3) == ((2 + 3) * 2) - foo);
|
||||
{ int c = 2;
|
||||
Operation op = (a, b) -> ((a + b) * c) - foo;
|
||||
expect(op.operate(2, 3) == ((2 + 3) * 2) - foo);
|
||||
}
|
||||
|
||||
{ int c = 2;
|
||||
Operation2 op = (a, b) -> ((a + b) * c) - foo;
|
||||
expect(op.operate(2, 3) == ((2 + 3) * 2) - foo);
|
||||
}
|
||||
|
||||
{ Supplier<Pair<Long, Double>> s = () -> new Pair<Long, Double>(42L, 77.1D);
|
||||
expect(s.get().first == 42L);
|
||||
expect(s.get().second == 77.1D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user