Give WalkStack's callback a way to terminate early.

Also combine WalkStack and WalkStackUntilUpcall.

Change-Id: Ida25665de72e5fd8e17946886a387b27cf841457
diff --git a/src/thread.cc b/src/thread.cc
index 8470b8d..b511aa7 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -566,9 +566,9 @@
   virtual ~StackDumpVisitor() {
   }
 
-  void VisitFrame(const Frame& frame, uintptr_t pc) {
+  bool VisitFrame(const Frame& frame, uintptr_t pc) {
     if (!frame.HasMethod()) {
-      return;
+      return true;
     }
     const int kMaxRepetition = 3;
     Method* m = frame.GetMethod();
@@ -606,6 +606,7 @@
     if (frame_count++ == 0) {
       Monitor::DescribeWait(os, thread);
     }
+    return true;
   }
   MethodHelper mh;
   Method* last_method;
@@ -1066,7 +1067,7 @@
  public:
   CountStackDepthVisitor() : depth_(0), skip_depth_(0), skipping_(true) {}
 
-  virtual void VisitFrame(const Frame& frame, uintptr_t pc) {
+  bool VisitFrame(const Frame& frame, uintptr_t pc) {
     // We want to skip frames up to and including the exception's constructor.
     // Note we also skip the frame if it doesn't have a method (namely the callee
     // save frame)
@@ -1081,6 +1082,7 @@
     } else {
       ++skip_depth_;
     }
+    return true;
   }
 
   int GetDepth() const {
@@ -1127,20 +1129,21 @@
 
   virtual ~BuildInternalStackTraceVisitor() {}
 
-  virtual void VisitFrame(const Frame& frame, uintptr_t pc) {
+  bool VisitFrame(const Frame& frame, uintptr_t pc) {
     if (method_trace_ == NULL || pc_trace_ == NULL) {
-      return; // We're probably trying to fillInStackTrace for an OutOfMemoryError.
+      return true; // We're probably trying to fillInStackTrace for an OutOfMemoryError.
     }
     if (skip_depth_ > 0) {
       skip_depth_--;
-      return;
+      return true;
     }
     if (!frame.HasMethod()) {
-      return;  // ignore callee save frames
+      return true;  // ignore callee save frames
     }
     method_trace_->Set(count_, frame.GetMethod());
     pc_trace_->Set(count_, pc);
     ++count_;
+    return true;
   }
 
   jobject GetInternalStackTrace() const {
@@ -1190,7 +1193,7 @@
   return sirt;
 }
 
-void Thread::WalkStack(StackVisitor* visitor) const {
+void Thread::WalkStack(StackVisitor* visitor, bool include_upcalls) const {
   Frame frame = GetTopOfStack();
   uintptr_t pc = ManglePc(top_of_managed_stack_pc_);
 #if defined(__arm__)
@@ -1200,10 +1203,13 @@
   // CHECK(native_to_managed_record_ != NULL);
   NativeToManagedRecord* record = native_to_managed_record_;
 
-  while (frame.GetSP() != 0) {
-    for ( ; frame.GetMethod() != 0; frame.Next()) {
+  while (frame.GetSP() != NULL) {
+    for ( ; frame.GetMethod() != NULL; frame.Next()) {
       // DCHECK(frame.GetMethod()->IsWithinCode(pc));  // TODO: restore IsWithinCode
-      visitor->VisitFrame(frame, pc);
+      bool should_continue = visitor->VisitFrame(frame, pc);
+      if (!should_continue) {
+        return;
+      }
       pc = ManglePc(frame.GetReturnPC());
       if (Runtime::Current()->IsMethodTracingActive()) {
 #if defined(__arm__)
@@ -1216,8 +1222,14 @@
 #endif
       }
     }
+    if (include_upcalls) {
+      bool should_continue = visitor->VisitFrame(frame, pc);
+      if (!should_continue) {
+        return;
+      }
+    }
     if (record == NULL) {
-      break;
+      return;
     }
     // last_tos should return Frame instead of sp?
     frame.SetSP(reinterpret_cast<Method**>(record->last_top_of_managed_stack_));
@@ -1226,22 +1238,6 @@
   }
 }
 
-void Thread::WalkStackUntilUpCall(StackVisitor* visitor, bool include_upcall) const {
-  Frame frame = GetTopOfStack();
-  uintptr_t pc = ManglePc(top_of_managed_stack_pc_);
-
-  if (frame.GetSP() != 0) {
-    for ( ; frame.GetMethod() != 0; frame.Next()) {
-      // DCHECK(frame.GetMethod()->IsWithinCode(pc));  // TODO: restore IsWithinCode
-      visitor->VisitFrame(frame, pc);
-      pc = ManglePc(frame.GetReturnPC());
-    }
-    if (include_upcall) {
-      visitor->VisitFrame(frame, pc);
-    }
-  }
-}
-
 jobject Thread::CreateInternalStackTrace(JNIEnv* env) const {
   // Compute depth of stack
   CountStackDepthVisitor count_visitor;
@@ -1430,59 +1426,54 @@
 class CatchBlockStackVisitor : public Thread::StackVisitor {
  public:
   CatchBlockStackVisitor(Class* to_find, Context* ljc)
-      : found_(false), to_find_(to_find), long_jump_context_(ljc), native_method_count_(0) {
+      : to_find_(to_find), long_jump_context_(ljc), native_method_count_(0) {
 #ifndef NDEBUG
     handler_pc_ = 0xEBADC0DE;
     handler_frame_.SetSP(reinterpret_cast<Method**>(0xEBADF00D));
 #endif
   }
 
-  virtual void VisitFrame(const Frame& fr, uintptr_t pc) {
-    if (!found_) {
-      Method* method = fr.GetMethod();
-      if (method == NULL) {
-        // This is the upcall, we remember the frame and last_pc so that we may
-        // long jump to them
-        handler_pc_ = DemanglePc(pc);
-        handler_frame_ = fr;
-        return;
-      }
-      uint32_t dex_pc = DexFile::kDexNoIndex;
-      if (method->IsCalleeSaveMethod()) {
-        // ignore callee save method
-      } else if (method->IsNative()) {
-        native_method_count_++;
-      } else {
-        // Unwind stack during method tracing
-        if (Runtime::Current()->IsMethodTracingActive()) {
+  bool VisitFrame(const Frame& fr, uintptr_t pc) {
+    Method* method = fr.GetMethod();
+    if (method == NULL) {
+      // This is the upcall, we remember the frame and last_pc so that we may
+      // long jump to them
+      handler_pc_ = DemanglePc(pc);
+      handler_frame_ = fr;
+      return false;
+    }
+    uint32_t dex_pc = DexFile::kDexNoIndex;
+    if (method->IsCalleeSaveMethod()) {
+      // ignore callee save method
+    } else if (method->IsNative()) {
+      native_method_count_++;
+    } else {
+      // Unwind stack during method tracing
+      if (Runtime::Current()->IsMethodTracingActive()) {
 #if defined(__arm__)
-          uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code);
-          if (ManglePc(trace_exit) == pc) {
-            pc = ManglePc(TraceMethodUnwindFromCode(Thread::Current()));
-          }
+        uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code);
+        if (ManglePc(trace_exit) == pc) {
+          pc = ManglePc(TraceMethodUnwindFromCode(Thread::Current()));
+        }
 #else
-          UNIMPLEMENTED(WARNING);
+        UNIMPLEMENTED(WARNING);
 #endif
-        }
-        dex_pc = method->ToDexPC(pc);
       }
-      if (dex_pc != DexFile::kDexNoIndex) {
-        uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc);
-        if (found_dex_pc != DexFile::kDexNoIndex) {
-          found_ = true;
-          handler_pc_ = method->ToNativePC(found_dex_pc);
-          handler_frame_ = fr;
-        }
-      }
-      if (!found_) {
-        // Caller may be handler, fill in callee saves in context
-        long_jump_context_->FillCalleeSaves(fr);
+      dex_pc = method->ToDexPC(pc);
+    }
+    if (dex_pc != DexFile::kDexNoIndex) {
+      uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc);
+      if (found_dex_pc != DexFile::kDexNoIndex) {
+        handler_pc_ = method->ToNativePC(found_dex_pc);
+        handler_frame_ = fr;
+        return false;
       }
     }
+    // Caller may be handler, fill in callee saves in context
+    long_jump_context_->FillCalleeSaves(fr);
+    return true;
   }
 
-  // Did we find a catch block yet?
-  bool found_;
   // The type of the exception catch block to find
   Class* to_find_;
   // Frame with found handler or last frame if no handler found
@@ -1511,7 +1502,7 @@
 
   Context* long_jump_context = GetLongJumpContext();
   CatchBlockStackVisitor catch_finder(exception->GetClass(), long_jump_context);
-  WalkStackUntilUpCall(&catch_finder, true);
+  WalkStack(&catch_finder, true);
 
   Method** sp;
   uintptr_t throw_native_pc;
@@ -1589,7 +1580,7 @@
     context_(context), root_visitor_(root_visitor), arg_(arg) {
   }
 
-  void VisitFrame(const Frame& frame, uintptr_t pc) {
+  bool VisitFrame(const Frame& frame, uintptr_t pc) {
     Method* m = frame.GetMethod();
     if (false) {
       LOG(INFO) << "Visiting stack roots in " << PrettyMethod(m, false)
@@ -1641,6 +1632,7 @@
       }
     }
     context_->FillCalleeSaves(frame);
+    return true;
   }
 
  private: