add invokedynamic support to interpreter

This commit is contained in:
Joel Dice 2015-08-06 17:22:14 -06:00
parent 8a7944d25c
commit 66712a8cff
5 changed files with 168 additions and 136 deletions

View File

@ -2349,6 +2349,8 @@ GcClass* findLoadedClass(Thread* t, GcClassLoader* loader, GcByteArray* spec);
GcJclass* getDeclaringClass(Thread* t, GcClass* c);
GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation);
inline bool emptyMethod(Thread* t UNUSED, GcMethod* method)
{
return ((method->flags() & ACC_NATIVE) == 0)

View File

@ -58,7 +58,7 @@ namespace {
namespace local {
const bool DebugCompile = true;
const bool DebugCompile = false;
const bool DebugNatives = false;
const bool DebugCallTable = false;
const bool DebugMethodTree = false;
@ -7278,140 +7278,6 @@ uint64_t compileVirtualMethod(MyThread* t)
return reinterpret_cast<uintptr_t>(compileVirtualMethod2(t, class_, index));
}
GcCallSite* resolveDynamic(MyThread* t, GcInvocation* invocation)
{
PROTECT(t, invocation);
GcClass* c = invocation->class_();
PROTECT(t, c);
GcCharArray* bootstrapArray = cast<GcCharArray>(
t,
cast<GcArray>(t, c->addendum()->bootstrapMethodTable())
->body()[invocation->bootstrap()]);
PROTECT(t, bootstrapArray);
GcMethod* bootstrap = cast<GcMethod>(t,
resolve(t,
c->loader(),
invocation->pool(),
bootstrapArray->body()[0],
findMethodInClass,
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);
GcByteArray* nameBytes = invocation->template_()->name();
GcString* name
= t->m->classpath->makeString(t, nameBytes, 0, nameBytes->length() - 1);
PROTECT(t, name);
GcMethodType* type = makeMethodType(
t, c->loader(), invocation->template_()->spec(), 0, 0, 0);
PROTECT(t, type);
GcArray* array = makeArray(t, bootstrap->parameterCount());
PROTECT(t, array);
unsigned argument = 0;
array->setBodyElement(t, argument++, lookup);
array->setBodyElement(t, argument++, name);
array->setBodyElement(t, argument++, type);
MethodSpecIterator it(
t, reinterpret_cast<const char*>(bootstrap->spec()->body().begin()));
for (unsigned i = 0; i < argument; ++i)
it.next();
unsigned i = 0;
while (it.hasNext()) {
const char* p = it.next();
switch (*p) {
case 'L': {
const char* const methodType = "Ljava/lang/invoke/MethodType;";
const char* const methodHandle = "Ljava/lang/invoke/MethodHandle;";
if (strncmp(p, methodType, strlen(methodType)) == 0) {
GcMethodType* type = makeMethodType(
t,
c->loader(),
cast<GcByteArray>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[i + 1])),
0,
0,
0);
array->setBodyElement(t, i + argument, type);
} else if (strncmp(p, methodHandle, strlen(methodHandle)) == 0) {
GcReference* reference = cast<GcReference>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[i + 1]));
int kind = reference->kind();
GcMethod* method = cast<GcMethod>(t,
resolve(t,
c->loader(),
invocation->pool(),
bootstrapArray->body()[i + 1],
findMethodInClass,
GcNoSuchMethodError::Type));
GcMethodHandle* handle
= makeMethodHandle(t, kind, c->loader(), method, 0);
array->setBodyElement(t, i + argument, handle);
} else {
abort(t);
}
} break;
case 'I':
case 'F': {
GcInt* box = makeInt(
t,
singletonValue(t, invocation->pool(), bootstrapArray->body()[i + 1]));
array->setBodyElement(t, i + argument, box);
} break;
case 'J':
case 'D': {
uint64_t v;
memcpy(
&v,
&singletonValue(t, invocation->pool(), bootstrapArray->body()[i + 1]),
8);
GcLong* box = makeLong(t, v);
array->setBodyElement(t, i + argument, box);
} break;
default:
abort(t);
}
++i;
}
GcMethodHandle* handle
= (bootstrap->flags() & ACC_STATIC)
? 0
: makeMethodHandle(t, REF_invokeSpecial, c->loader(), bootstrap, 0);
return cast<GcCallSite>(
t, t->m->processor->invokeArray(t, bootstrap, handle, array));
}
void* linkDynamicMethod2(MyThread* t, unsigned index)
{
GcInvocation* invocation

View File

@ -1981,6 +1981,34 @@ loop:
}
goto loop;
case invokedynamic: {
uint16_t index = codeReadInt16(t, code, ip);
ip += 2;
GcInvocation* invocation = cast<GcInvocation>(t, singletonObject(t, code->pool(), index - 1));
GcCallSite* site = invocation->site();
loadMemoryBarrier();
if (site == 0) {
PROTECT(t, invocation);
invocation->setClass(t, frameMethod(t, frame)->class_());
site = resolveDynamic(t, invocation);
PROTECT(t, site);
storeStoreMemoryBarrier();
invocation->setSite(t, site);
site->setInvocation(t, invocation);
}
method = site->target()->method();
} goto invoke;
case invokeinterface: {
uint16_t index = codeReadInt16(t, code, ip);

View File

@ -6032,6 +6032,140 @@ GcJclass* getDeclaringClass(Thread* t, GcClass* c)
return 0;
}
GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
{
PROTECT(t, invocation);
GcClass* c = invocation->class_();
PROTECT(t, c);
GcCharArray* bootstrapArray = cast<GcCharArray>(
t,
cast<GcArray>(t, c->addendum()->bootstrapMethodTable())
->body()[invocation->bootstrap()]);
PROTECT(t, bootstrapArray);
GcMethod* bootstrap = cast<GcMethod>(t,
resolve(t,
c->loader(),
invocation->pool(),
bootstrapArray->body()[0],
findMethodInClass,
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);
GcByteArray* nameBytes = invocation->template_()->name();
GcString* name
= t->m->classpath->makeString(t, nameBytes, 0, nameBytes->length() - 1);
PROTECT(t, name);
GcMethodType* type = makeMethodType(
t, c->loader(), invocation->template_()->spec(), 0, 0, 0);
PROTECT(t, type);
GcArray* array = makeArray(t, bootstrap->parameterCount());
PROTECT(t, array);
unsigned argument = 0;
array->setBodyElement(t, argument++, lookup);
array->setBodyElement(t, argument++, name);
array->setBodyElement(t, argument++, type);
MethodSpecIterator it(
t, reinterpret_cast<const char*>(bootstrap->spec()->body().begin()));
for (unsigned i = 0; i < argument; ++i)
it.next();
unsigned i = 0;
while (it.hasNext()) {
const char* p = it.next();
switch (*p) {
case 'L': {
const char* const methodType = "Ljava/lang/invoke/MethodType;";
const char* const methodHandle = "Ljava/lang/invoke/MethodHandle;";
if (strncmp(p, methodType, strlen(methodType)) == 0) {
GcMethodType* type = makeMethodType(
t,
c->loader(),
cast<GcByteArray>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[i + 1])),
0,
0,
0);
array->setBodyElement(t, i + argument, type);
} else if (strncmp(p, methodHandle, strlen(methodHandle)) == 0) {
GcReference* reference = cast<GcReference>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[i + 1]));
int kind = reference->kind();
GcMethod* method = cast<GcMethod>(t,
resolve(t,
c->loader(),
invocation->pool(),
bootstrapArray->body()[i + 1],
findMethodInClass,
GcNoSuchMethodError::Type));
GcMethodHandle* handle
= makeMethodHandle(t, kind, c->loader(), method, 0);
array->setBodyElement(t, i + argument, handle);
} else {
abort(t);
}
} break;
case 'I':
case 'F': {
GcInt* box = makeInt(
t,
singletonValue(t, invocation->pool(), bootstrapArray->body()[i + 1]));
array->setBodyElement(t, i + argument, box);
} break;
case 'J':
case 'D': {
uint64_t v;
memcpy(
&v,
&singletonValue(t, invocation->pool(), bootstrapArray->body()[i + 1]),
8);
GcLong* box = makeLong(t, v);
array->setBodyElement(t, i + argument, box);
} break;
default:
abort(t);
}
++i;
}
GcMethodHandle* handle
= (bootstrap->flags() & ACC_STATIC)
? 0
: makeMethodHandle(t, REF_invokeSpecial, c->loader(), bootstrap, 0);
return cast<GcCallSite>(
t, t->m->processor->invokeArray(t, bootstrap, handle, array));
}
void noop()
{
}

View File

@ -18,7 +18,9 @@ public class InvokeDynamic {
Operation op = (a, b) -> a + b - c;
expect(op.operate(2, 3) == (2 + 3) - 4);
new InvokeDynamic(3).test();
for (int i = 0; i < 4; ++i) {
new InvokeDynamic(i).test();
}
}
private void test() {