Create JNIEnv*s on the right threads.
This exposes a bug in jni_compiler.cc --- it passes the right JNIEnv* to the
native method and to MonitorExit, but it passes a bogus value to MonitorEnter.
Change-Id: Icbf505d24294d14ce3e40180a20254789cb69904
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 7677a7a..cfedb85 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -171,8 +171,9 @@
}
int gJava_MyClass_fooSIOO_calls = 0;
-jobject Java_MyClass_fooSIOO(JNIEnv*, jclass klass, jint x, jobject y,
+jobject Java_MyClass_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
jobject z) {
+ EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
gJava_MyClass_fooSIOO_calls++;
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index dbdfc45..f77e4d0 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -43,8 +43,9 @@
Thread* env_self = reinterpret_cast<JNIEnvExt*>(env)->self;
Thread* self = workAroundAppJniBugs ? Thread::Current() : env_self;
if (self != env_self) {
- LOG(ERROR) << "JNI ERROR: JNIEnv for thread " << env_self << " used on "
- << "thread " << self << ")";
+ LOG(ERROR) << "JNI ERROR: JNIEnv for " << *env_self
+ << " used on " << *self;
+ // TODO: dump stack
}
return self;
}
@@ -1757,17 +1758,21 @@
};
void MonitorEnterHelper(JNIEnv* env, jobject obj) {
+ CHECK_EQ(Thread::Current()->GetJniEnv(), env);
MonitorEnter(env, obj); // Ignore the result.
}
void MonitorExitHelper(JNIEnv* env, jobject obj) {
+ CHECK_EQ(Thread::Current()->GetJniEnv(), env);
MonitorExit(env, obj); // Ignore the result.
}
JNIEnv* CreateJNIEnv() {
+ Thread* self = Thread::Current();
+ CHECK(self != NULL);
JNIEnvExt* result = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
result->fns = &gNativeInterface;
- result->self = Thread::Current();
+ result->self = self;
result->MonitorEnterHelper = &MonitorEnterHelper;
result->MonitorExitHelper = &MonitorExitHelper;
return reinterpret_cast<JNIEnv*>(result);
diff --git a/src/thread.cc b/src/thread.cc
index 68f4566..b98d1e5 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -101,6 +101,8 @@
PLOG(FATAL) << "pthread_setspecific failed";
}
+ thread->jni_env_ = CreateJNIEnv();
+
return thread;
}
@@ -144,6 +146,14 @@
return os;
}
+std::ostream& operator<<(std::ostream& os, const Thread& thread) {
+ os << "Thread[" << &thread
+ << ",id=" << thread.GetId()
+ << ",tid=" << thread.GetNativeId()
+ << ",state=" << thread.GetState() << "]";
+ return os;
+}
+
ThreadList* ThreadList::Create() {
return new ThreadList;
}
diff --git a/src/thread.h b/src/thread.h
index 02b2f65..a6e137f 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -171,7 +171,7 @@
return runtime_;
}
- State GetState() {
+ State GetState() const {
return state_;
}
@@ -241,8 +241,11 @@
private:
Thread()
- : id_(1234), top_shb_(NULL), exception_(NULL), suspend_count_(0) {
- jni_env_ = CreateJNIEnv();
+ : id_(1234),
+ top_shb_(NULL),
+ jni_env_(NULL),
+ exception_(NULL),
+ suspend_count_(0) {
}
~Thread() {
@@ -304,6 +307,7 @@
DISALLOW_COPY_AND_ASSIGN(Thread);
};
+std::ostream& operator<<(std::ostream& os, const Thread& thread);
std::ostream& operator<<(std::ostream& os, const Thread::State& state);
class ThreadList {