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 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;
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;
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;
import static avian.Stream.write1;
@ -306,4 +316,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]);
}
}

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;
import avian.Classes;

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;
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;
import static avian.Assembler.*;
@ -242,8 +252,8 @@ public final class MethodType implements java.io.Serializable {
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;

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

View File

@ -4040,15 +4040,26 @@ bool isLambda(Thread* t,
return vm::strcmp(reinterpret_cast<const int8_t*>(
"java/lang/invoke/LambdaMetafactory"),
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
and vm::strcmp(
reinterpret_cast<const int8_t*>(
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/"
"String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/"
"MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/"
"String;Ljava/lang/invoke/MethodType;Ljava/lang/"
"invoke/"
"MethodType;Ljava/lang/invoke/MethodHandle;Ljava/"
"lang/"
"invoke/MethodType;)Ljava/lang/invoke/CallSite;"),
bootstrap->spec()->body().begin()) == 0;
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,
@ -5133,6 +5144,16 @@ loop:
GcClass* c = context->method->class_();
PROTECT(t, c);
GcMethod* target
= c->addendum()->bootstrapLambdaTable()
? cast<GcMethod>(
t,
cast<GcArray>(t, c->addendum()->bootstrapLambdaTable())
->body()[invocation->bootstrap()])
: nullptr;
PROTECT(t, target);
if (target == nullptr) {
GcCharArray* bootstrapArray = cast<GcCharArray>(
t,
cast<GcArray>(t, c->addendum()->bootstrapMethodTable())
@ -5141,7 +5162,8 @@ loop:
if (isLambda(t, c->loader(), bootstrapArray, invocation)) {
if (bc->hostVM == 0) {
throwNew(t,
throwNew(
t,
GcVirtualMachineError::Type,
"lambda expression encountered, but host VM is not "
"available; use -hostvm option to bootimage-generator to "
@ -5149,16 +5171,18 @@ loop:
}
JNIEnv* e;
if (bc->hostVM->vtable->AttachCurrentThread(bc->hostVM, &e, 0) == 0) {
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");
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/"
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
"String;Ljava/"
"lang/String;Ljava/lang/String;Ljava/lang/String;I)[B");
GcReference* reference = cast<GcReference>(
@ -5232,14 +5256,24 @@ loop:
invocation->template_()->spec()->body().begin(),
invocation->template_()->spec()->length());
GcMethod* target = resolveMethod(
target = resolveMethod(
t, lambdaClass, "make", RUNTIME_ARRAY_BODY(spec));
bool tailCall = isTailCall(t, code, ip, context->method, target);
compileDirectInvoke(t, frame, target, tailCall);
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");
throwNew(t,
GcVirtualMachineError::Type,
"unable to attach to host VM");
}
} else {
throwNew(t,
@ -5247,6 +5281,10 @@ loop:
"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 {
unsigned index = addDynamic(t, invocation);

View File

@ -1220,7 +1220,7 @@ GcClassAddendum* getClassAddendum(Thread* t, GcClass* class_, GcSingleton* pool)
if (addendum == 0) {
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);
}
return addendum;
@ -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()

View File

@ -19,6 +19,7 @@
#include <vector>
#include <set>
#include <sstream>
#include <algorithm>
#include "avian/constants.h"
#include "avian/finder.h"
@ -908,8 +909,6 @@ std::string cppFieldType(Module& module, Field* f)
void writeAccessor(Output* out, Class* cl, Field* f)
{
std::string typeName = f->typeName;
out->write("const unsigned ");
out->write(capitalize(cl->name));
out->write(capitalize(f->name));
@ -920,7 +919,22 @@ void writeAccessor(Output* out, Class* cl, Field* f)
out->write("#define HAVE_");
out->write(capitalize(cl->name));
out->write(capitalize(f->name));
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)

View File

@ -9,6 +9,24 @@ public class InvokeDynamic {
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();
}
@ -24,8 +42,19 @@ public class InvokeDynamic {
}
private void test() {
int c = 2;
{ 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);
}
}
}