OSDN Git Service

Fix wrong handling of Generic JNI not finding native method.
authorAndreas Gampe <agampe@google.com>
Fri, 4 Apr 2014 23:20:13 +0000 (16:20 -0700)
committerAndreas Gampe <agampe@google.com>
Fri, 4 Apr 2014 23:28:13 +0000 (16:28 -0700)
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

compiler/jni/jni_compiler_test.cc
runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
test/MyClassNatives/MyClassNatives.java

index 3204282..a0797f3 100644 (file)
@@ -1268,4 +1268,14 @@ TEST_F(JniCompilerTest, MaxParamNumber) {
   env_->CallNonvirtualVoidMethodA(jobj_, jklass_, jmethod_, args);
 }
 
+TEST_F(JniCompilerTest, WithoutImplementation) {
+  TEST_DISABLED_FOR_PORTABLE();
+  SetUpForTest(false, "withoutImplementation", "()V", nullptr);
+
+  env_->CallVoidMethod(jobj_, jmethod_);
+
+  EXPECT_TRUE(Thread::Current()->IsExceptionPending());
+  EXPECT_TRUE(env_->ExceptionCheck() == JNI_TRUE);
+}
+
 }  // namespace art
index 963c3d1..fcbcac2 100644 (file)
@@ -1496,6 +1496,22 @@ void BuildGenericJniFrameVisitor::FinalizeSirt(Thread* self) {
 
 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 @@ extern "C" ssize_t artQuickGenericJniTrampoline(Thread* self, mirror::ArtMethod*
 
     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 @@ extern "C" uint64_t artQuickGenericJniEndTrampoline(Thread* self, mirror::ArtMet
   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.
index 6e7a426..09f1783 100644 (file)
@@ -79,4 +79,5 @@ class MyClassNatives {
         Object o240, Object o241, Object o242, Object o243, Object o244, Object o245, Object o246, Object o247,
         Object o248, Object o249, Object o250, Object o251, Object o252, Object o253);
 
+    native void withoutImplementation();
 }