Fix wrong handling of Generic JNI not finding native method.
Code did not properly call JNIMethodEnd, such that locks etc
where not correctly handled.
Add a test case to jni_compiler_test.
Change-Id: If2d5c628517d65a56dd6bb5c4cabdff77c7664a1
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 963c3d1..fcbcac2 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1496,6 +1496,22 @@
extern "C" void* artFindNativeMethod();
+uint64_t artQuickGenericJniEndJNIRef(Thread* self, uint32_t cookie, jobject l, jobject lock) {
+ if (lock != nullptr) {
+ return reinterpret_cast<uint64_t>(JniMethodEndWithReferenceSynchronized(l, cookie, lock, self));
+ } else {
+ return reinterpret_cast<uint64_t>(JniMethodEndWithReference(l, cookie, self));
+ }
+}
+
+void artQuickGenericJniEndJNINonRef(Thread* self, uint32_t cookie, jobject lock) {
+ if (lock != nullptr) {
+ JniMethodEndSynchronized(cookie, lock, self);
+ } else {
+ JniMethodEnd(cookie, self);
+ }
+}
+
/*
* Initializes an alloca region assumed to be directly below sp for a native call:
* Create a Sirt and call stack and fill a mini stack with values to be pushed to registers.
@@ -1555,6 +1571,15 @@
if (nativeCode == nullptr) {
DCHECK(self->IsExceptionPending()); // There should be an exception pending now.
+
+ // End JNI, as the assembly will move to deliver the exception.
+ jobject lock = called->IsSynchronized() ? visitor.GetFirstSirtEntry() : nullptr;
+ if (mh.GetShorty()[0] == 'L') {
+ artQuickGenericJniEndJNIRef(self, cookie, nullptr, lock);
+ } else {
+ artQuickGenericJniEndJNINonRef(self, cookie, lock);
+ }
+
return -1;
}
// Note that the native code pointer will be automatically set by artFindNativeMethod().
@@ -1580,33 +1605,21 @@
mirror::ArtMethod* called = *sp;
uint32_t cookie = *(sp32 - 1);
+ jobject lock = nullptr;
+ if (called->IsSynchronized()) {
+ StackIndirectReferenceTable* table =
+ reinterpret_cast<StackIndirectReferenceTable*>(
+ reinterpret_cast<uint8_t*>(sp) + kPointerSize);
+ lock = reinterpret_cast<jobject>(table->GetStackReference(0));
+ }
+
MethodHelper mh(called);
char return_shorty_char = mh.GetShorty()[0];
if (return_shorty_char == 'L') {
- // the only special ending call
- if (called->IsSynchronized()) {
- StackIndirectReferenceTable* table =
- reinterpret_cast<StackIndirectReferenceTable*>(
- reinterpret_cast<uint8_t*>(sp) + kPointerSize);
- jobject tmp = reinterpret_cast<jobject>(table->GetStackReference(0));
-
- return reinterpret_cast<uint64_t>(JniMethodEndWithReferenceSynchronized(result.l, cookie, tmp,
- self));
- } else {
- return reinterpret_cast<uint64_t>(JniMethodEndWithReference(result.l, cookie, self));
- }
+ return artQuickGenericJniEndJNIRef(self, cookie, result.l, lock);
} else {
- if (called->IsSynchronized()) {
- StackIndirectReferenceTable* table =
- reinterpret_cast<StackIndirectReferenceTable*>(
- reinterpret_cast<uint8_t*>(sp) + kPointerSize);
- jobject tmp = reinterpret_cast<jobject>(table->GetStackReference(0));
-
- JniMethodEndSynchronized(cookie, tmp, self);
- } else {
- JniMethodEnd(cookie, self);
- }
+ artQuickGenericJniEndJNINonRef(self, cookie, lock);
switch (return_shorty_char) {
case 'F': // Fall-through.