Initial implementation of throw+unwind+Frame.

Unit tests on Exception Handling pass.

Change-Id: I33505dacc6648e72e2ed80c2cca83643cfaef86b
diff --git a/src/thread.cc b/src/thread.cc
index e92f23c..db4c59f 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -49,6 +49,24 @@
   SetOwner(NULL);
 }
 
+void Frame::Next() {
+  byte* next_sp = reinterpret_cast<byte*>(sp_) +
+      GetMethod()->GetFrameSize();
+  sp_ = reinterpret_cast<const Method**>(next_sp);
+}
+
+void* Frame::GetPC() const {
+  byte* pc_addr = reinterpret_cast<byte*>(sp_) +
+      GetMethod()->GetPcOffset();
+  return reinterpret_cast<void*>(pc_addr);
+}
+
+const Method* Frame::NextMethod() const {
+  byte* next_sp = reinterpret_cast<byte*>(sp_) +
+      GetMethod()->GetFrameSize();
+  return reinterpret_cast<const Method*>(next_sp);
+}
+
 void* ThreadStart(void *arg) {
   UNIMPLEMENTED(FATAL);
   return NULL;
@@ -190,6 +208,67 @@
   ThrowNewException(exception_class, msg.c_str());
 }
 
+Frame Thread::FindExceptionHandler(void* throw_pc, void** handler_pc) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  DCHECK(class_linker != NULL);
+
+  Frame cur_frame = GetTopOfStack();
+  for (int unwind_depth = 0; ; unwind_depth++) {
+    const Method* cur_method = cur_frame.GetMethod();
+    DexCache* dex_cache = cur_method->GetDeclaringClass()->GetDexCache();
+    const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
+
+    void* handler_addr = FindExceptionHandlerInMethod(cur_method,
+                                                      throw_pc,
+                                                      dex_file,
+                                                      class_linker);
+    if (handler_addr) {
+      *handler_pc = handler_addr;
+      return cur_frame;
+    } else {
+      // Check if we are at the last frame
+      if (cur_frame.HasNext()) {
+        cur_frame.Next();
+      } else {
+        // Either at the top of stack or next frame is native.
+        break;
+      }
+    }
+  }
+  *handler_pc = NULL;
+  return Frame();
+}
+
+void* Thread::FindExceptionHandlerInMethod(const Method* method,
+                                           void* throw_pc,
+                                           const DexFile& dex_file,
+                                           ClassLinker* class_linker) {
+  Object* exception_obj = exception_;
+  exception_ = NULL;
+
+  intptr_t dex_pc = -1;
+  const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->code_off_);
+  DexFile::CatchHandlerIterator iter;
+  for (iter = dex_file.dexFindCatchHandler(*code_item,
+                                           method->ToDexPC(reinterpret_cast<intptr_t>(throw_pc)));
+       !iter.HasNext();
+       iter.Next()) {
+    Class* klass = class_linker->FindSystemClass(dex_file.dexStringByTypeIdx(iter.Get().type_idx_));
+    DCHECK(klass != NULL);
+    if (exception_obj->InstanceOf(klass)) {
+      dex_pc = iter.Get().address_;
+      break;
+    }
+  }
+
+  exception_ = exception_obj;
+  if (iter.HasNext()) {
+    return NULL;
+  } else {
+    return reinterpret_cast<void*>( method->ToNativePC(dex_pc) );
+  }
+}
+
 static const char* kStateNames[] = {
   "New",
   "Runnable",