Switch to Thread::WalkStack rather than manual Frame::Next.
Also fix test 039.
Change-Id: I07d0559bb86d67a7f7947768bd8370fb4cf06c26
diff --git a/src/dalvik_system_VMStack.cc b/src/dalvik_system_VMStack.cc
index 696d723..8401ec1 100644
--- a/src/dalvik_system_VMStack.cc
+++ b/src/dalvik_system_VMStack.cc
@@ -16,10 +16,10 @@
#include "jni_internal.h"
#include "class_loader.h"
+#include "nth_caller_visitor.h"
#include "object.h"
#include "scoped_heap_lock.h"
#include "scoped_thread_list_lock.h"
-#include "shadow_frame.h"
#include "thread_list.h"
#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -43,23 +43,11 @@
return depth;
}
+// Returns the defining class loader of the caller's caller.
static jobject VMStack_getCallingClassLoader(JNIEnv* env, jclass) {
- // Returns the defining class loader of the caller's caller.
- // TODO: need SmartFrame (Thread::WalkStack-like iterator).
-#if !defined(ART_USE_LLVM_COMPILER)
- Frame frame = Thread::Current()->GetTopOfStack();
- frame.Next();
- frame.Next();
- Method* callerCaller = frame.GetMethod();
-#else
- ShadowFrame* frame = Thread::Current()->GetTopOfShadowFrame();
- frame = frame->GetLink();
- frame = frame->GetLink();
- Method* callerCaller = frame->GetMethod();
-#endif
- DCHECK(callerCaller != NULL);
- const Object* cl = callerCaller->GetDeclaringClass()->GetClassLoader();
- return AddLocalReference<jobject>(env, cl);
+ NthCallerVisitor visitor(2);
+ Thread::Current()->WalkStack(&visitor);
+ return AddLocalReference<jobject>(env, visitor.class_loader);
}
static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass, jobject javaBootstrap, jobject javaSystem) {
@@ -87,17 +75,11 @@
return AddLocalReference<jobject>(env, visitor.class_loader);
}
+// Returns the class of the caller's caller's caller.
static jclass VMStack_getStackClass2(JNIEnv* env, jclass) {
- // Returns the class of the caller's caller's caller.
- // TODO: need SmartFrame (Thread::WalkStack-like iterator).
- Frame frame = Thread::Current()->GetTopOfStack();
- frame.Next();
- frame.Next();
- frame.Next();
- Method* callerCallerCaller = frame.GetMethod();
- DCHECK(callerCallerCaller != NULL);
- Class* c = callerCallerCaller->GetDeclaringClass();
- return AddLocalReference<jclass>(env, c);
+ NthCallerVisitor visitor(3);
+ Thread::Current()->WalkStack(&visitor);
+ return AddLocalReference<jclass>(env, visitor.declaring_class);
}
static jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject javaThread) {
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index fcd1689..17b584a 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -17,6 +17,7 @@
#include "jni_internal.h"
#include "class_linker.h"
#include "class_loader.h"
+#include "nth_caller_visitor.h"
#include "object.h"
#include "object_utils.h"
#include "ScopedLocalRef.h"
@@ -422,12 +423,10 @@
// Second, make sure it has permission to invoke the constructor. The
// constructor must be public or, if the caller is in the same package,
// have package scope.
- // TODO: need SmartFrame (Thread::WalkStack-like iterator).
- Frame frame = Thread::Current()->GetTopOfStack();
- frame.Next();
- frame.Next();
- Method* caller_caller = frame.GetMethod();
- Class* caller_class = caller_caller->GetDeclaringClass();
+
+ NthCallerVisitor visitor(2);
+ Thread::Current()->WalkStack(&visitor);
+ Class* caller_class = visitor.declaring_class;
ClassHelper caller_ch(caller_class);
if (!caller_class->CanAccess(c)) {
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index c5ffec1..3bbd3cd 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -356,8 +356,7 @@
}
static const ClassLoader* GetClassLoader(Thread* self) {
- Frame frame = self->GetTopOfStack();
- Method* method = frame.GetMethod();
+ Method* method = self->GetCurrentMethod();
if (method == NULL || PrettyMethod(method, false) == "java.lang.Runtime.nativeLoad") {
return self->GetClassLoaderOverride();
}
@@ -2655,11 +2654,10 @@
static jint DestroyJavaVM(JavaVM* vm) {
if (vm == NULL) {
return JNI_ERR;
- } else {
- JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
- delete raw_vm->runtime;
- return JNI_OK;
}
+ JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
+ delete raw_vm->runtime;
+ return JNI_OK;
}
static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
@@ -2673,12 +2671,11 @@
static jint DetachCurrentThread(JavaVM* vm) {
if (vm == NULL) {
return JNI_ERR;
- } else {
- JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
- Runtime* runtime = raw_vm->runtime;
- runtime->DetachCurrentThread();
- return JNI_OK;
}
+ JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
+ Runtime* runtime = raw_vm->runtime;
+ runtime->DetachCurrentThread();
+ return JNI_OK;
}
static jint GetEnv(JavaVM* vm, void** env, jint version) {
diff --git a/src/nth_caller_visitor.h b/src/nth_caller_visitor.h
new file mode 100644
index 0000000..6f82fa9
--- /dev/null
+++ b/src/nth_caller_visitor.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_NTH_CALLER_VISITOR_H_
+#define ART_SRC_NTH_CALLER_VISITOR_H_
+
+#include "object.h"
+#include "thread.h"
+
+namespace art {
+
+// Walks up the stack 'n' callers, when used with Thread::WalkStack.
+struct NthCallerVisitor : public Thread::StackVisitor {
+ NthCallerVisitor(size_t n) : n(n), count(0), declaring_class(NULL), class_loader(NULL) {}
+ bool VisitFrame(const Frame& f, uintptr_t) {
+ DCHECK(class_loader == NULL);
+ if (count++ == n) {
+ Method* m = f.GetMethod();
+ declaring_class = m->GetDeclaringClass();
+ class_loader = declaring_class->GetClassLoader();
+ return false;
+ }
+ return true;
+ }
+ size_t n;
+ size_t count;
+ Class* declaring_class;
+ Object* class_loader;
+};
+
+} // namespace art
+
+#endif // ART_SRC_NTH_CALLER_VISITOR_H_
diff --git a/src/oat/runtime/support_throw.cc b/src/oat/runtime/support_throw.cc
index e2e5c94..45600fd 100644
--- a/src/oat/runtime/support_throw.cc
+++ b/src/oat/runtime/support_throw.cc
@@ -50,10 +50,10 @@
// Called by generated call to throw a NPE exception.
extern "C" void artThrowNullPointerExceptionFromCode(Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
- Frame fr = self->GetTopOfStack();
- uintptr_t throw_native_pc = fr.GetReturnPC();
- fr.Next();
- Method* throw_method = fr.GetMethod();
+ Frame frame = self->GetTopOfStack();
+ uintptr_t throw_native_pc = frame.GetReturnPC();
+ frame.Next();
+ Method* throw_method = frame.GetMethod();
uint32_t dex_pc = throw_method->ToDexPC(throw_native_pc - 2);
const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem();
CHECK_LT(dex_pc, code->insns_size_in_code_units_);
diff --git a/src/thread.h b/src/thread.h
index 08187bb..40409b6 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -228,10 +228,6 @@
return top_of_managed_stack_;
}
- ShadowFrame* GetTopOfShadowFrame() const {
- return top_shadow_frame_;
- }
-
// TODO: this is here for testing, remove when we have exception unit tests
// that use the real stack
void SetTopOfStack(void* stack, uintptr_t pc) {
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 706a2ef..0e01c0d 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -35,15 +35,15 @@
}
ThreadList::~ThreadList() {
- WaitForOtherNonDaemonThreadsToExit();
- SuspendAllDaemonThreads();
-
// Detach the current thread if necessary. If we failed to start, there might not be any threads.
- // We don't deal with the current thread before this point because the thread/thread-list
- // diagnostics and debugging machinery requires the current thread to be attached.
+ // We need to detach the current thread here in case there's another thread waiting to join with
+ // us.
if (Contains(Thread::Current())) {
Runtime::Current()->DetachCurrentThread();
}
+
+ WaitForOtherNonDaemonThreadsToExit();
+ SuspendAllDaemonThreads();
}
bool ThreadList::Contains(Thread* thread) {