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) {