Merge pull request #511 from dicej/lambda-fixes

Lambda fixes
This commit is contained in:
Joel Dice 2016-12-06 09:50:16 -07:00 committed by GitHub
commit c5d7e5b8c5
13 changed files with 410 additions and 170 deletions

View File

@ -27,4 +27,6 @@ public class ClassAddendum extends Addendum {
public Pair enclosingMethod; public Pair enclosingMethod;
public VMMethod[] bootstrapMethodTable; public VMMethod[] bootstrapMethodTable;
public VMMethod[] bootstrapLambdaTable;
} }

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke; package java.lang.invoke;
public class CallSite { public class CallSite {

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke; package java.lang.invoke;
public class LambdaConversionException extends java.lang.Exception { public class LambdaConversionException extends java.lang.Exception {

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke; package java.lang.invoke;
import static avian.Stream.write1; import static avian.Stream.write1;
@ -25,17 +35,17 @@ import avian.SystemClassLoader;
public class LambdaMetafactory { public class LambdaMetafactory {
private static int nextNumber = 0; private static int nextNumber = 0;
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;
while (s[index] != ')') ++ index; while (s[index] != ')') ++ index;
if (s[++ index] != 'L') throw new AssertionError(); if (s[++ index] != 'L') throw new AssertionError();
++ index; ++ index;
int end = index + 1; int end = index + 1;
while (s[end] != ';') ++ end; while (s[end] != ';') ++ end;
@ -52,11 +62,11 @@ public class LambdaMetafactory {
while (array[i] != c) ++i; while (array[i] != c) ++i;
return i; return i;
} }
private static String constructorSpec(MethodType type) { private static String constructorSpec(MethodType type) {
return Classes.makeString(type.spec, 0, indexOf(')', type.spec) + 1) + "V"; return Classes.makeString(type.spec, 0, indexOf(')', type.spec) + 1) + "V";
} }
private static byte[] makeFactoryCode(List<PoolEntry> pool, private static byte[] makeFactoryCode(List<PoolEntry> pool,
String className, String className,
String constructorSpec, String constructorSpec,
@ -89,7 +99,7 @@ public class LambdaMetafactory {
byte[] result = out.toByteArray(); byte[] result = out.toByteArray();
set4(result, 4, result.length - 12); set4(result, 4, result.length - 12);
return result; return result;
} }
private static byte[] makeConstructorCode(List<PoolEntry> pool, private static byte[] makeConstructorCode(List<PoolEntry> pool,
@ -124,7 +134,7 @@ public class LambdaMetafactory {
byte[] result = out.toByteArray(); byte[] result = out.toByteArray();
set4(result, 4, result.length - 12); set4(result, 4, result.length - 12);
return result; return result;
} }
private static byte[] makeInvocationCode(List<PoolEntry> pool, private static byte[] makeInvocationCode(List<PoolEntry> pool,
@ -167,7 +177,7 @@ public class LambdaMetafactory {
default: throw new AssertionError default: throw new AssertionError
("todo: implement per http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.5"); ("todo: implement per http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.5");
} }
write2(out, ConstantPool.addMethodRef write2(out, ConstantPool.addMethodRef
(pool, (pool,
Classes.makeString(implementation.method.class_.name, 0, Classes.makeString(implementation.method.class_.name, 0,
@ -233,7 +243,7 @@ public class LambdaMetafactory {
} }
String constructorSpec = constructorSpec(invokedType); String constructorSpec = constructorSpec(invokedType);
List<MethodData> methodTable = new ArrayList(); List<MethodData> methodTable = new ArrayList();
try { try {
@ -261,9 +271,9 @@ public class LambdaMetafactory {
} catch (IOException e) { } catch (IOException e) {
AssertionError error = new AssertionError(); AssertionError error = new AssertionError();
error.initCause(e); error.initCause(e);
throw error; throw error;
} }
int nameIndex = ConstantPool.addClass(pool, className); int nameIndex = ConstantPool.addClass(pool, className);
int superIndex = ConstantPool.addClass(pool, "java/lang/Object"); int superIndex = ConstantPool.addClass(pool, "java/lang/Object");
@ -276,12 +286,12 @@ public class LambdaMetafactory {
} catch (IOException e) { } catch (IOException e) {
AssertionError error = new AssertionError(); AssertionError error = new AssertionError();
error.initCause(e); error.initCause(e);
throw error; throw error;
} }
return out.toByteArray(); return out.toByteArray();
} }
public static CallSite metafactory(MethodHandles.Lookup caller, public static CallSite metafactory(MethodHandles.Lookup caller,
String invokedName, String invokedName,
MethodType invokedType, MethodType invokedType,
@ -291,7 +301,7 @@ public class LambdaMetafactory {
throws LambdaConversionException throws LambdaConversionException
{ {
byte[] classData = makeLambda(invokedName, invokedType, methodType, methodImplementation); byte[] classData = makeLambda(invokedName, invokedType, methodType, methodImplementation);
try { try {
return new CallSite return new CallSite
(new MethodHandle (new MethodHandle
@ -306,4 +316,14 @@ public class LambdaMetafactory {
throw error; 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]);
}
} }

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke; package java.lang.invoke;
import avian.Classes; import avian.Classes;
@ -6,12 +16,12 @@ import avian.SystemClassLoader;
public class MethodHandle { public class MethodHandle {
static final int REF_invokeStatic = 6; static final int REF_invokeStatic = 6;
static final int REF_invokeSpecial = 7; static final int REF_invokeSpecial = 7;
final int kind; final int kind;
private final ClassLoader loader; private final ClassLoader loader;
final avian.VMMethod method; final avian.VMMethod method;
private volatile MethodType type; private volatile MethodType type;
MethodHandle(int kind, ClassLoader loader, avian.VMMethod method) { MethodHandle(int kind, ClassLoader loader, avian.VMMethod method) {
this.kind = kind; this.kind = kind;
this.loader = loader; this.loader = loader;
@ -44,7 +54,7 @@ public class MethodHandle {
sb.append(Classes.makeString(method.spec, 0, sb.append(Classes.makeString(method.spec, 0,
method.spec.length - 1)); method.spec.length - 1));
return sb.toString(); return sb.toString();
} }
public MethodType type() { public MethodType type() {
if (type == null) { if (type == null) {

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke; package java.lang.invoke;
public class MethodHandles { public class MethodHandles {

View File

@ -1,3 +1,13 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke; package java.lang.invoke;
import static avian.Assembler.*; import static avian.Assembler.*;
@ -14,7 +24,7 @@ public final class MethodType implements java.io.Serializable {
private static final char[] Primitives = new char[] { private static final char[] Primitives = new char[] {
'V', 'Z', 'B', 'C', 'S', 'I', 'F', 'J', 'D' 'V', 'Z', 'B', 'C', 'S', 'I', 'F', 'J', 'D'
}; };
final ClassLoader loader; final ClassLoader loader;
final byte[] spec; final byte[] spec;
private volatile List<Parameter> parameters; private volatile List<Parameter> parameters;
@ -31,11 +41,11 @@ public final class MethodType implements java.io.Serializable {
this.spec = new byte[spec.length() + 1]; this.spec = new byte[spec.length() + 1];
spec.getBytes(0, spec.length(), this.spec, 0); spec.getBytes(0, spec.length(), this.spec, 0);
} }
public String toMethodDescriptorString() { public String toMethodDescriptorString() {
return Classes.makeString(spec, 0, spec.length - 1); return Classes.makeString(spec, 0, spec.length - 1);
} }
private static String spec(Class c) { private static String spec(Class c) {
if (c.isPrimitive()) { if (c.isPrimitive()) {
VMClass vmc = Classes.toVMClass(c); VMClass vmc = Classes.toVMClass(c);
@ -56,7 +66,7 @@ public final class MethodType implements java.io.Serializable {
Class ... ptypes) Class ... ptypes)
{ {
loader = rtype.getClassLoader(); loader = rtype.getClassLoader();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append('('); sb.append('(');
parameters = new ArrayList(ptypes.length); parameters = new ArrayList(ptypes.length);
@ -66,7 +76,7 @@ public final class MethodType implements java.io.Serializable {
sb.append(spec); sb.append(spec);
Type type = type(spec); Type type = type(spec);
parameters.add(new Parameter(i, parameters.add(new Parameter(i,
position, position,
spec, spec,
@ -86,7 +96,7 @@ public final class MethodType implements java.io.Serializable {
this.spec = sb.toString().getBytes(); this.spec = sb.toString().getBytes();
} }
public static MethodType methodType(Class rtype, public static MethodType methodType(Class rtype,
Class ptype0, Class ptype0,
Class ... ptypes) Class ... ptypes)
@ -129,7 +139,7 @@ public final class MethodType implements java.io.Serializable {
return array; return array;
} }
public Iterable<Parameter> parameters() { public Iterable<Parameter> parameters() {
if (parameters == null) { if (parameters == null) {
List<Parameter> list = new ArrayList(); List<Parameter> list = new ArrayList();
@ -147,7 +157,7 @@ public final class MethodType implements java.io.Serializable {
case '[': { case '[': {
++ i; ++ i;
while (spec[i] == '[') ++ i; while (spec[i] == '[') ++ i;
switch (spec[i]) { switch (spec[i]) {
case 'L': case 'L':
++ i; ++ i;
@ -174,7 +184,7 @@ public final class MethodType implements java.io.Serializable {
String paramSpec = Classes.makeString(spec, start, (i - start) + 1); String paramSpec = Classes.makeString(spec, start, (i - start) + 1);
Type type = type(paramSpec); Type type = type(paramSpec);
list.add(new Parameter list.add(new Parameter
(index, (index,
position, position,
@ -192,14 +202,14 @@ public final class MethodType implements java.io.Serializable {
String paramSpec = Classes.makeString(spec, i, spec.length - i - 1); String paramSpec = Classes.makeString(spec, i, spec.length - i - 1);
Type type = type(paramSpec); Type type = type(paramSpec);
result = new Result(paramSpec, result = new Result(paramSpec,
Classes.forCanonicalName(loader, paramSpec), Classes.forCanonicalName(loader, paramSpec),
type.return_); type.return_);
parameters = list; parameters = list;
} }
return parameters; return parameters;
} }
@ -234,18 +244,18 @@ public final class MethodType implements java.io.Serializable {
case 'V': case 'V':
return Type.VoidType; return Type.VoidType;
default: throw new AssertionError(); default: throw new AssertionError();
} }
} }
private static enum Type { private static enum Type {
ObjectType(aload, areturn, 1), ObjectType(aload, areturn, 1),
IntegerType(iload, ireturn, 1), IntegerType(iload, ireturn, 1),
FloatType(fload, freturn, 1), FloatType(fload, freturn, 1),
LongType(lload, lreturn, 1), LongType(lload, lreturn, 2),
DoubleType(dload, dreturn, 1), DoubleType(dload, dreturn, 2),
VoidType(-1, Assembler.return_, -1); VoidType(-1, Assembler.return_, -1);
public final int load; public final int load;
public final int return_; public final int return_;
public final int size; public final int size;
@ -256,7 +266,7 @@ public final class MethodType implements java.io.Serializable {
this.size = size; this.size = size;
} }
} }
public static class Parameter { public static class Parameter {
private final int index; private final int index;
private final int position; private final int position;

View File

@ -0,0 +1,48 @@
/* Copyright (c) 2008-2016, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.invoke;
public class SerializedLambda implements java.io.Serializable {
public int getImplMethodKind() {
// todo
return 0;
}
public String getImplClass() {
// todo
return null;
}
public String getImplMethodName() {
// todo
return null;
}
public String getImplMethodSignature() {
// todo
return null;
}
public String getFunctionalInterfaceClass() {
// todo
return null;
}
public String getFunctionalInterfaceMethodName() {
// todo
return null;
}
public String getFunctionalInterfaceMethodSignature() {
// todo
return null;
}
}

View File

@ -523,6 +523,9 @@ class MyClasspath : public Classpath {
GcJobject* blockerLock = makeJobject(t); GcJobject* blockerLock = makeJobject(t);
thread->setBlockerLock(t, blockerLock); thread->setBlockerLock(t, blockerLock);
#if HAVE_ThreadName_Ljava_lang_String_
GcString* name = vm::makeString(t, "Thread-%p", thread);
#else
const unsigned BufferSize = 256; const unsigned BufferSize = 256;
char buffer[BufferSize]; char buffer[BufferSize];
unsigned length = vm::snprintf(buffer, BufferSize, "Thread-%p", thread); unsigned length = vm::snprintf(buffer, BufferSize, "Thread-%p", thread);
@ -530,6 +533,7 @@ class MyClasspath : public Classpath {
for (unsigned i = 0; i < length; ++i) { for (unsigned i = 0; i < length; ++i) {
name->body()[i] = buffer[i]; name->body()[i] = buffer[i];
} }
#endif
thread->setName(t, name); thread->setName(t, name);
return thread; return thread;

View File

@ -4040,15 +4040,26 @@ bool isLambda(Thread* t,
return vm::strcmp(reinterpret_cast<const int8_t*>( return vm::strcmp(reinterpret_cast<const int8_t*>(
"java/lang/invoke/LambdaMetafactory"), "java/lang/invoke/LambdaMetafactory"),
bootstrap->class_()->name()->body().begin()) == 0 bootstrap->class_()->name()->body().begin()) == 0
and vm::strcmp(reinterpret_cast<const int8_t*>("metafactory"), and ((vm::strcmp(reinterpret_cast<const int8_t*>("metafactory"),
bootstrap->name()->body().begin()) == 0 bootstrap->name()->body().begin()) == 0
and vm::strcmp( and vm::strcmp(
reinterpret_cast<const int8_t*>( reinterpret_cast<const int8_t*>(
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/" "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/"
"String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/" "String;Ljava/lang/invoke/MethodType;Ljava/lang/"
"MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/" "invoke/"
"invoke/MethodType;)Ljava/lang/invoke/CallSite;"), "MethodType;Ljava/lang/invoke/MethodHandle;Ljava/"
bootstrap->spec()->body().begin()) == 0; "lang/"
"invoke/MethodType;)Ljava/lang/invoke/CallSite;"),
bootstrap->spec()->body().begin()) == 0)
or (vm::strcmp(reinterpret_cast<const int8_t*>("altMetafactory"),
bootstrap->name()->body().begin()) == 0
and vm::strcmp(
reinterpret_cast<const int8_t*>(
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/"
"lang/"
"String;Ljava/lang/invoke/MethodType;[Ljava/lang/"
"Object;)Ljava/lang/invoke/CallSite;"),
bootstrap->spec()->body().begin()) == 0));
} }
void compile(MyThread* t, void compile(MyThread* t,
@ -5133,120 +5144,147 @@ loop:
GcClass* c = context->method->class_(); GcClass* c = context->method->class_();
PROTECT(t, c); PROTECT(t, c);
GcCharArray* bootstrapArray = cast<GcCharArray>( GcMethod* target
t, = c->addendum()->bootstrapLambdaTable()
cast<GcArray>(t, c->addendum()->bootstrapMethodTable()) ? cast<GcMethod>(
->body()[invocation->bootstrap()]); t,
PROTECT(t, bootstrapArray); cast<GcArray>(t, c->addendum()->bootstrapLambdaTable())
->body()[invocation->bootstrap()])
: nullptr;
PROTECT(t, target);
if (isLambda(t, c->loader(), bootstrapArray, invocation)) { if (target == nullptr) {
if (bc->hostVM == 0) { GcCharArray* bootstrapArray = cast<GcCharArray>(
t,
cast<GcArray>(t, c->addendum()->bootstrapMethodTable())
->body()[invocation->bootstrap()]);
PROTECT(t, bootstrapArray);
if (isLambda(t, c->loader(), bootstrapArray, invocation)) {
if (bc->hostVM == 0) {
throwNew(
t,
GcVirtualMachineError::Type,
"lambda expression encountered, but host VM is not "
"available; use -hostvm option to bootimage-generator to "
"fix this");
}
JNIEnv* e;
if (bc->hostVM->vtable->AttachCurrentThread(bc->hostVM, &e, 0)
== 0) {
e->vtable->PushLocalFrame(e, 256);
jclass lmfClass = e->vtable->FindClass(
e, "java/lang/invoke/LambdaMetafactory");
jmethodID makeLambda = e->vtable->GetStaticMethodID(
e,
lmfClass,
"makeLambda",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
"String;Ljava/"
"lang/String;Ljava/lang/String;Ljava/lang/String;I)[B");
GcReference* reference = cast<GcReference>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[2]));
int kind = reference->kind();
GcMethod* method
= cast<GcMethod>(t,
resolve(t,
c->loader(),
invocation->pool(),
bootstrapArray->body()[2],
findMethodInClass,
GcNoSuchMethodError::Type));
jarray lambda = e->vtable->CallStaticObjectMethod(
e,
lmfClass,
makeLambda,
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
invocation->template_()->name()->body().begin())),
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
invocation->template_()->spec()->body().begin())),
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
cast<GcByteArray>(
t,
singletonObject(t,
invocation->pool(),
bootstrapArray->body()[1]))
->body()
.begin())),
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
method->class_()->name()->body().begin())),
e->vtable->NewStringUTF(e,
reinterpret_cast<const char*>(
method->name()->body().begin())),
e->vtable->NewStringUTF(e,
reinterpret_cast<const char*>(
method->spec()->body().begin())),
kind);
uint8_t* bytes = reinterpret_cast<uint8_t*>(
e->vtable->GetPrimitiveArrayCritical(e, lambda, 0));
GcClass* lambdaClass
= defineClass(t,
roots(t)->appLoader(),
bytes,
e->vtable->GetArrayLength(e, lambda));
bc->resolver->addClass(
t, lambdaClass, bytes, e->vtable->GetArrayLength(e, lambda));
e->vtable->ReleasePrimitiveArrayCritical(e, lambda, bytes, 0);
e->vtable->PopLocalFrame(e, 0);
THREAD_RUNTIME_ARRAY(
t, char, spec, invocation->template_()->spec()->length());
memcpy(RUNTIME_ARRAY_BODY(spec),
invocation->template_()->spec()->body().begin(),
invocation->template_()->spec()->length());
target = resolveMethod(
t, lambdaClass, "make", RUNTIME_ARRAY_BODY(spec));
GcArray* table
= cast<GcArray>(t, c->addendum()->bootstrapLambdaTable());
if (table == nullptr) {
table = makeArray(
t,
cast<GcArray>(t, c->addendum()->bootstrapMethodTable())
->length());
c->addendum()->setBootstrapLambdaTable(t, table);
}
table->setBodyElement(t, invocation->bootstrap(), target);
} else {
throwNew(t,
GcVirtualMachineError::Type,
"unable to attach to host VM");
}
} else {
throwNew(t, throwNew(t,
GcVirtualMachineError::Type, GcVirtualMachineError::Type,
"lambda expression encountered, but host VM is not " "invokedynamic not supported for AOT-compiled code except "
"available; use -hostvm option to bootimage-generator to " "in the case of lambda expressions");
"fix this");
} }
JNIEnv* e;
if (bc->hostVM->vtable->AttachCurrentThread(bc->hostVM, &e, 0) == 0) {
e->vtable->PushLocalFrame(e, 256);
jclass lmfClass
= e->vtable->FindClass(e, "java/lang/invoke/LambdaMetafactory");
jmethodID makeLambda = e->vtable->GetStaticMethodID(
e,
lmfClass,
"makeLambda",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/"
"lang/String;Ljava/lang/String;Ljava/lang/String;I)[B");
GcReference* reference = cast<GcReference>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[2]));
int kind = reference->kind();
GcMethod* method
= cast<GcMethod>(t,
resolve(t,
c->loader(),
invocation->pool(),
bootstrapArray->body()[2],
findMethodInClass,
GcNoSuchMethodError::Type));
jarray lambda = e->vtable->CallStaticObjectMethod(
e,
lmfClass,
makeLambda,
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
invocation->template_()->name()->body().begin())),
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
invocation->template_()->spec()->body().begin())),
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
cast<GcByteArray>(
t,
singletonObject(t,
invocation->pool(),
bootstrapArray->body()[1]))
->body()
.begin())),
e->vtable->NewStringUTF(
e,
reinterpret_cast<const char*>(
method->class_()->name()->body().begin())),
e->vtable->NewStringUTF(e,
reinterpret_cast<const char*>(
method->name()->body().begin())),
e->vtable->NewStringUTF(e,
reinterpret_cast<const char*>(
method->spec()->body().begin())),
kind);
uint8_t* bytes = reinterpret_cast<uint8_t*>(
e->vtable->GetPrimitiveArrayCritical(e, lambda, 0));
GcClass* lambdaClass
= defineClass(t,
roots(t)->appLoader(),
bytes,
e->vtable->GetArrayLength(e, lambda));
bc->resolver->addClass(
t, lambdaClass, bytes, e->vtable->GetArrayLength(e, lambda));
e->vtable->ReleasePrimitiveArrayCritical(e, lambda, bytes, 0);
e->vtable->PopLocalFrame(e, 0);
THREAD_RUNTIME_ARRAY(
t, char, spec, invocation->template_()->spec()->length());
memcpy(RUNTIME_ARRAY_BODY(spec),
invocation->template_()->spec()->body().begin(),
invocation->template_()->spec()->length());
GcMethod* target = resolveMethod(
t, lambdaClass, "make", RUNTIME_ARRAY_BODY(spec));
bool tailCall = isTailCall(t, code, ip, context->method, target);
compileDirectInvoke(t, frame, target, tailCall);
} else {
throwNew(
t, GcVirtualMachineError::Type, "unable to attach to host VM");
}
} else {
throwNew(t,
GcVirtualMachineError::Type,
"invokedynamic not supported for AOT-compiled code except "
"in the case of lambda expressions");
} }
bool tailCall = isTailCall(t, code, ip, context->method, target);
compileDirectInvoke(t, frame, target, tailCall);
} else { } else {
unsigned index = addDynamic(t, invocation); unsigned index = addDynamic(t, invocation);

View File

@ -1220,7 +1220,7 @@ GcClassAddendum* getClassAddendum(Thread* t, GcClass* class_, GcSingleton* pool)
if (addendum == 0) { if (addendum == 0) {
PROTECT(t, class_); PROTECT(t, class_);
addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, -1, 0, 0, 0); addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, -1, 0, 0, 0, 0);
setField(t, class_, ClassAddendum, addendum); setField(t, class_, ClassAddendum, addendum);
} }
return addendum; return addendum;
@ -6055,8 +6055,6 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
GcNoSuchMethodError::Type)); GcNoSuchMethodError::Type));
PROTECT(t, bootstrap); PROTECT(t, bootstrap);
assertT(t, bootstrap->parameterCount() == 2 + bootstrapArray->length());
GcLookup* lookup GcLookup* lookup
= makeLookup(t, c, ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC); = makeLookup(t, c, ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC);
PROTECT(t, lookup); PROTECT(t, lookup);
@ -6078,14 +6076,47 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
array->setBodyElement(t, argument++, name); array->setBodyElement(t, argument++, name);
array->setBodyElement(t, argument++, type); array->setBodyElement(t, argument++, type);
MethodSpecIterator it( const char* spec;
t, reinterpret_cast<const char*>(bootstrap->spec()->body().begin())); 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) for (unsigned i = 0; i < argument; ++i)
it.next(); it.next();
if (argArray != array) {
argument = 0;
}
unsigned i = 0; unsigned i = 0;
while (it.hasNext()) { while (i + 1 < bootstrapArray->length() && it.hasNext()) {
const char* p = it.next(); const char* p = it.next();
switch (*p) { switch (*p) {
case 'L': { case 'L': {
@ -6162,8 +6193,12 @@ GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
? 0 ? 0
: makeMethodHandle(t, REF_invokeSpecial, c->loader(), bootstrap, 0); : makeMethodHandle(t, REF_invokeSpecial, c->loader(), bootstrap, 0);
if (argArray != array) {
argArray->setBodyElement(t, 3, array);
}
return cast<GcCallSite>( return cast<GcCallSite>(
t, t->m->processor->invokeArray(t, bootstrap, handle, array)); t, t->m->processor->invokeArray(t, bootstrap, handle, argArray));
} }
void noop() void noop()

View File

@ -19,6 +19,7 @@
#include <vector> #include <vector>
#include <set> #include <set>
#include <sstream> #include <sstream>
#include <algorithm>
#include "avian/constants.h" #include "avian/constants.h"
#include "avian/finder.h" #include "avian/finder.h"
@ -908,8 +909,6 @@ std::string cppFieldType(Module& module, Field* f)
void writeAccessor(Output* out, Class* cl, Field* f) void writeAccessor(Output* out, Class* cl, Field* f)
{ {
std::string typeName = f->typeName;
out->write("const unsigned "); out->write("const unsigned ");
out->write(capitalize(cl->name)); out->write(capitalize(cl->name));
out->write(capitalize(f->name)); out->write(capitalize(f->name));
@ -920,7 +919,22 @@ void writeAccessor(Output* out, Class* cl, Field* f)
out->write("#define HAVE_"); out->write("#define HAVE_");
out->write(capitalize(cl->name)); out->write(capitalize(cl->name));
out->write(capitalize(f->name)); out->write(capitalize(f->name));
out->write(" 1\n\n"); out->write(" 1\n");
if (! f->javaSpec.empty()) {
std::string s = f->javaSpec;
std::replace(s.begin(), s.end(), '/', '_');
std::replace(s.begin(), s.end(), '$', '_');
std::replace(s.begin(), s.end(), ';', '_');
std::replace(s.begin(), s.end(), '[', '_');
out->write("#define HAVE_");
out->write(capitalize(cl->name));
out->write(capitalize(f->name));
out->write("_");
out->write(s);
out->write(" 1\n\n");
}
} }
void writeAccessors(Output* out, Module& module) void writeAccessors(Output* out, Module& module)

View File

@ -4,15 +4,33 @@ public class InvokeDynamic {
private InvokeDynamic(int foo) { private InvokeDynamic(int foo) {
this.foo = foo; this.foo = foo;
} }
private interface Operation { private interface Operation {
int operate(int a, int b); 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) { private static void expect(boolean v) {
if (! v) throw new RuntimeException(); if (! v) throw new RuntimeException();
} }
public static void main(String[] args) { public static void main(String[] args) {
int c = 4; int c = 4;
Operation op = (a, b) -> a + b - c; Operation op = (a, b) -> a + b - c;
@ -24,8 +42,19 @@ public class InvokeDynamic {
} }
private void test() { private void test() {
int c = 2; { int c = 2;
Operation op = (a, b) -> ((a + b) * c) - foo; Operation op = (a, b) -> ((a + b) * c) - foo;
expect(op.operate(2, 3) == ((2 + 3) * 2) - 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);
}
} }
} }