Support for local references allocated in SHBs.
Local references passed in the stack handle block by the managed to
native bridge code generated jni_compiler need support for decoding. Add
support and extend jni_compiler_test to check the validity of jobject
arguments in the stack handle block.
Change-Id: Ibba60451c21f6e41023b8d837310f15ea69c44f8
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 39ba6ed..8a5155f 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -85,8 +85,7 @@
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
EXPECT_TRUE(thisObj != NULL);
- // TODO: check JNIEnv and thisObj are sane
- // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
+ EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_foo_calls++;
}
@@ -106,8 +105,7 @@
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
EXPECT_TRUE(thisObj != NULL);
- // TODO: check JNIEnv and thisObj are sane
- // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
+ EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_fooI_calls++;
return x;
}
@@ -131,8 +129,7 @@
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
EXPECT_TRUE(thisObj != NULL);
- // TODO: check JNIEnv and thisObj are sane
- // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
+ EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_fooII_calls++;
return x - y; // non-commutative operator
}
@@ -157,8 +154,7 @@
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
EXPECT_TRUE(thisObj != NULL);
- // TODO: check JNIEnv and thisObj are sane
- // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
+ EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_fooDD_calls++;
return x - y; // non-commutative operator
}
@@ -186,8 +182,7 @@
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
EXPECT_TRUE(thisObj != NULL);
- // TODO: check JNIEnv and thisObj are sane
- // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
+ EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_fooIOO_calls++;
switch (x) {
case 1:
@@ -237,8 +232,7 @@
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
EXPECT_TRUE(klass != NULL);
- // TODO: check JNIEnv and klass are sane
- // EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
+ EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
gJava_MyClass_fooSIOO_calls++;
switch (x) {
case 1:
@@ -289,8 +283,7 @@
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
EXPECT_TRUE(klass != NULL);
- // TODO: check JNIEnv and klass are sane
- // EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
+ EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
gJava_MyClass_fooSSIOO_calls++;
switch (x) {
case 1:
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index dbb2674..733a307 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -283,6 +283,11 @@
}
case kInvalid:
default:
+ // TODO: make stack handle blocks more efficient
+ // Check if this is a local reference in a stack handle block
+ if (ts.Self()->ShbContains(obj)) {
+ return *reinterpret_cast<T*>(obj); // Read from stack handle block
+ }
if (false /*gDvmJni.workAroundAppJniBugs*/) { // TODO
// Assume an invalid local reference is actually a direct pointer.
return reinterpret_cast<T>(obj);
diff --git a/src/thread.cc b/src/thread.cc
index dd333d7..1cb037e 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -135,6 +135,27 @@
return true;
}
+size_t Thread::NumShbHandles() {
+ size_t count = 0;
+ for (StackHandleBlock* cur = top_shb_; cur; cur = cur->Link()) {
+ count += cur->NumberOfReferences();
+ }
+ return count;
+}
+
+bool Thread::ShbContains(jobject obj) {
+ Object **shb_entry = reinterpret_cast<Object**>(obj);
+ for (StackHandleBlock* cur = top_shb_; cur; cur = cur->Link()) {
+ size_t num_refs = cur->NumberOfReferences();
+ DCHECK_GT(num_refs, 0u); // A SHB should always have a jobject/jclass
+ if ((&cur->Handles()[0] >= shb_entry) &&
+ (shb_entry <= (&cur->Handles()[num_refs-1]))) {
+ return true;
+ }
+ }
+ return false;
+}
+
void ThrowNewException(Thread* thread, const char* exception_class_name, const char* msg) {
CHECK(thread != NULL);
diff --git a/src/thread.h b/src/thread.h
index 66b5e28..ac332e0 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -80,6 +80,10 @@
return link_;
}
+ Object** Handles() {
+ return handles_;
+ }
+
// Offset of length within SHB, used by generated code
static size_t NumberOfReferencesOffset() {
return OFFSETOF_MEMBER(StackHandleBlock, number_of_references_);
@@ -96,6 +100,9 @@
size_t number_of_references_;
StackHandleBlock* link_;
+ // Fake array, really allocated and filled in by jni_compiler.
+ Object* handles_[0];
+
DISALLOW_COPY_AND_ASSIGN(StackHandleBlock);
};
@@ -216,13 +223,10 @@
}
// Number of references allocated in StackHandleBlocks on this thread
- size_t NumShbHandles() {
- size_t count = 0;
- for (StackHandleBlock* cur = top_shb_; cur; cur = cur->Link()) {
- count += cur->NumberOfReferences();
- }
- return count;
- }
+ size_t NumShbHandles();
+
+ // Is the given obj in this thread's stack handle blocks?
+ bool ShbContains(jobject obj);
// Offset of exception_entry_point_ within Thread, used by generated code
static ThreadOffset ExceptionEntryPointOffset() {