diff --git a/src/avian/machine.h b/src/avian/machine.h index b028981c76..9f5654303d 100644 --- a/src/avian/machine.h +++ b/src/avian/machine.h @@ -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) diff --git a/src/compile.cpp b/src/compile.cpp index 21b81af337..74605cc9b5 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -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(compileVirtualMethod2(t, class_, index)); } -GcCallSite* resolveDynamic(MyThread* t, GcInvocation* invocation) -{ - PROTECT(t, invocation); - - GcClass* c = invocation->class_(); - PROTECT(t, c); - - GcCharArray* bootstrapArray = cast( - t, - cast(t, c->addendum()->bootstrapMethodTable()) - ->body()[invocation->bootstrap()]); - - PROTECT(t, bootstrapArray); - - GcMethod* bootstrap = cast(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(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( - 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( - t, - singletonObject( - t, invocation->pool(), bootstrapArray->body()[i + 1])); - int kind = reference->kind(); - - GcMethod* method = cast(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( - t, t->m->processor->invokeArray(t, bootstrap, handle, array)); -} - void* linkDynamicMethod2(MyThread* t, unsigned index) { GcInvocation* invocation diff --git a/src/interpret.cpp b/src/interpret.cpp index 49507ffca5..67871b40d8 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1981,6 +1981,34 @@ loop: } goto loop; + case invokedynamic: { + uint16_t index = codeReadInt16(t, code, ip); + + ip += 2; + + GcInvocation* invocation = cast(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); diff --git a/src/machine.cpp b/src/machine.cpp index 1cd581f9ba..87cdf5f626 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -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( + t, + cast(t, c->addendum()->bootstrapMethodTable()) + ->body()[invocation->bootstrap()]); + + PROTECT(t, bootstrapArray); + + GcMethod* bootstrap = cast(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(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( + 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( + t, + singletonObject( + t, invocation->pool(), bootstrapArray->body()[i + 1])); + int kind = reference->kind(); + + GcMethod* method = cast(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( + t, t->m->processor->invokeArray(t, bootstrap, handle, array)); +} + void noop() { } diff --git a/test/InvokeDynamic.java b/test/InvokeDynamic.java index 86f1d1a412..90d88d6fc6 100644 --- a/test/InvokeDynamic.java +++ b/test/InvokeDynamic.java @@ -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() {