Compute the right catch location for the debugger.

Also remove tls ThrowLocation, it is not needed anymore.

Change-Id: I78fddf09ce968ca475e39c17fa76d699c589c8d9
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 029fd46..98abc18 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1610,7 +1610,7 @@
 static void CheckAndClearResolveException(Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   CHECK(self->IsExceptionPending());
-  mirror::Throwable* exception = self->GetException(nullptr);
+  mirror::Throwable* exception = self->GetException();
   std::string temp;
   const char* descriptor = exception->GetClass()->GetDescriptor(&temp);
   const char* expected_exceptions[] = {
@@ -1755,7 +1755,7 @@
 
   if (klass == nullptr) {
     CHECK(soa.Self()->IsExceptionPending());
-    mirror::Throwable* exception = soa.Self()->GetException(nullptr);
+    mirror::Throwable* exception = soa.Self()->GetException();
     VLOG(compiler) << "Exception during type resolution: " << exception->Dump();
     if (exception->GetClass()->DescriptorEquals("Ljava/lang/OutOfMemoryError;")) {
       // There's little point continuing compilation if the heap is exhausted.
@@ -1970,7 +1970,7 @@
 
             if (!success) {
               CHECK(soa.Self()->IsExceptionPending());
-              mirror::Throwable* exception = soa.Self()->GetException(nullptr);
+              mirror::Throwable* exception = soa.Self()->GetException();
               VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
                   << exception->Dump();
               std::ostream* file_log = manager->GetCompiler()->
@@ -2233,7 +2233,7 @@
   if (self->IsExceptionPending()) {
     ScopedObjectAccess soa(self);
     LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n"
-        << self->GetException(nullptr)->Dump();
+        << self->GetException()->Dump();
   }
 }
 
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index c32a992..b3bb438 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -930,7 +930,7 @@
       LOG(ERROR) << "Unexpected failure to resolve a method: "
                  << PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
       soa.Self()->AssertPendingException();
-      mirror::Throwable* exc = soa.Self()->GetException(nullptr);
+      mirror::Throwable* exc = soa.Self()->GetException();
       std::string dump = exc->Dump();
       LOG(FATAL) << dump;
     }
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 0d41a8f..0769687 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -1171,7 +1171,7 @@
                             reinterpret_cast<size_t>(nullptr),
                             StubTest::GetEntrypoint(self, kQuickAllocArrayResolved),
                             self);
-    EXPECT_FALSE(self->IsExceptionPending()) << PrettyTypeOf(self->GetException(nullptr));
+    EXPECT_FALSE(self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
     EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
     mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
     EXPECT_TRUE(obj->IsArrayInstance());
@@ -2060,7 +2060,7 @@
 
   env->CallBooleanMethod(jarray_list, add_jmethod, jobj);
 
-  ASSERT_FALSE(self->IsExceptionPending()) << PrettyTypeOf(self->GetException(nullptr));
+  ASSERT_FALSE(self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
 
   // Contains.
 
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 7db1d72..2b0167d 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -1065,11 +1065,10 @@
     // Verify that, if an exception has been raised, the native code doesn't
     // make any JNI calls other than the Exception* methods.
     if ((flags_ & kFlag_ExcepOkay) == 0 && self->IsExceptionPending()) {
-      ThrowLocation throw_location;
-      mirror::Throwable* exception = self->GetException(&throw_location);
-      std::string type(PrettyTypeOf(exception));
-      AbortF("JNI %s called with pending exception '%s' thrown in %s",
-             function_name_, type.c_str(), throw_location.Dump().c_str());
+      mirror::Throwable* exception = self->GetException();
+      AbortF("JNI %s called with pending exception %s",
+             function_name_,
+             exception->Dump().c_str());
       return false;
     }
     return true;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 2989b8c..f0c8819 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -103,7 +103,7 @@
   if (runtime->IsAotCompiler()) {
     // At compile time, accurate errors and NCDFE are disabled to speed compilation.
     mirror::Throwable* pre_allocated = runtime->GetPreAllocatedNoClassDefFoundError();
-    self->SetException(ThrowLocation(), pre_allocated);
+    self->SetException(pre_allocated);
   } else {
     ThrowLocation throw_location = self->GetCurrentLocationForThrow();
     if (c->GetVerifyErrorClass() != NULL) {
@@ -123,7 +123,7 @@
   if (VLOG_IS_ON(class_linker)) {
     std::string temp;
     LOG(INFO) << "Failed to initialize class " << klass->GetDescriptor(&temp) << " from "
-              << klass->GetLocation() << "\n" << Thread::Current()->GetException(nullptr)->Dump();
+              << klass->GetLocation() << "\n" << Thread::Current()->GetException()->Dump();
   }
 }
 
@@ -2195,7 +2195,7 @@
       // expected and will be wrapped in a ClassNotFoundException. Use the pre-allocated error to
       // trigger the chaining with a proper stack trace.
       mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
-      self->SetException(ThrowLocation(), pre_allocated);
+      self->SetException(pre_allocated);
       return nullptr;
     }
   } else if (Runtime::Current()->UseCompileTimeClassPath()) {
@@ -2227,7 +2227,7 @@
     } else {
       // Use the pre-allocated NCDFE at compile time to avoid wasting time constructing exceptions.
       mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
-      self->SetException(ThrowLocation(), pre_allocated);
+      self->SetException(pre_allocated);
       return nullptr;
     }
   } else {
@@ -3529,13 +3529,13 @@
                        PrettyDescriptor(klass.Get()).c_str(),
                        PrettyDescriptor(super.Get()).c_str()));
       LOG(WARNING) << error_msg  << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
-      Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException(nullptr)));
+      Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException()));
       if (cause.Get() != nullptr) {
         self->ClearException();
       }
       ThrowVerifyError(klass.Get(), "%s", error_msg.c_str());
       if (cause.Get() != nullptr) {
-        self->GetException(nullptr)->SetCause(cause.Get());
+        self->GetException()->SetCause(cause.Get());
       }
       ClassReference ref(klass->GetDexCache()->GetDexFile(), klass->GetDexClassDefIndex());
       if (Runtime::Current()->IsAotCompiler()) {
@@ -4168,7 +4168,7 @@
             << PrettyDescriptor(handle_scope_super.Get())
             << " that has unexpected status " << handle_scope_super->GetStatus()
             << "\nPending exception:\n"
-            << (self->GetException(nullptr) != nullptr ? self->GetException(nullptr)->Dump() : "");
+            << (self->GetException() != nullptr ? self->GetException()->Dump() : "");
         ObjectLock<mirror::Class> lock(self, klass);
         // Initialization failed because the super-class is erroneous.
         klass->SetStatus(mirror::Class::kStatusError, self);
@@ -5671,12 +5671,12 @@
           << "Expected pending exception for failed resolution of: " << descriptor;
       // Convert a ClassNotFoundException to a NoClassDefFoundError.
       StackHandleScope<1> hs(self);
-      Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException(nullptr)));
+      Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException()));
       if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
         DCHECK(resolved == nullptr);  // No Handle needed to preserve resolved.
         self->ClearException();
         ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
-        self->GetException(nullptr)->SetCause(cause.Get());
+        self->GetException()->SetCause(cause.Get());
       }
     }
   }
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 64e129c..1789ab1 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -48,7 +48,7 @@
     Thread* self = Thread::Current();
     EXPECT_TRUE(class_linker_->FindSystemClass(self, descriptor.c_str()) == nullptr);
     EXPECT_TRUE(self->IsExceptionPending());
-    mirror::Object* exception = self->GetException(nullptr);
+    mirror::Object* exception = self->GetException();
     self->ClearException();
     mirror::Class* exception_class =
         class_linker_->FindSystemClass(self, "Ljava/lang/NoClassDefFoundError;");
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 246125b..964e84c 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -280,11 +280,9 @@
     Dbg::PostFieldModificationEvent(method, dex_pc, this_object, field, &field_value);
   }
 
-  void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED, const ThrowLocation& throw_location,
-                       mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
-                       mirror::Throwable* exception_object)
+  void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED, mirror::Throwable* exception_object)
       OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Dbg::PostException(throw_location, catch_method, catch_dex_pc, exception_object);
+    Dbg::PostException(exception_object);
   }
 
   // We only care about how many backward branches were executed in the Jit.
@@ -2785,19 +2783,110 @@
   gJdwpState->PostFieldEvent(&location, f, this_object, field_value, true);
 }
 
-void Dbg::PostException(const ThrowLocation& throw_location,
-                        mirror::ArtMethod* catch_method,
-                        uint32_t catch_dex_pc, mirror::Throwable* exception_object) {
+/**
+ * Finds the location where this exception will be caught. We search until we reach the top
+ * frame, in which case this exception is considered uncaught.
+ */
+class CatchLocationFinder : public StackVisitor {
+ public:
+  CatchLocationFinder(Thread* self, const Handle<mirror::Throwable>& exception, Context* context)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+    : StackVisitor(self, context),
+      self_(self),
+      exception_(exception),
+      handle_scope_(self),
+      this_at_throw_(handle_scope_.NewHandle<mirror::Object>(nullptr)),
+      catch_method_(handle_scope_.NewHandle<mirror::ArtMethod>(nullptr)),
+      throw_method_(handle_scope_.NewHandle<mirror::ArtMethod>(nullptr)),
+      catch_dex_pc_(DexFile::kDexNoIndex),
+      throw_dex_pc_(DexFile::kDexNoIndex) {
+  }
+
+  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ArtMethod* method = GetMethod();
+    DCHECK(method != nullptr);
+    if (method->IsRuntimeMethod()) {
+      // Ignore callee save method.
+      DCHECK(method->IsCalleeSaveMethod());
+      return true;
+    }
+
+    uint32_t dex_pc = GetDexPc();
+    if (throw_method_.Get() == nullptr) {
+      // First Java method found. It is either the method that threw the exception,
+      // or the Java native method that is reporting an exception thrown by
+      // native code.
+      this_at_throw_.Assign(GetThisObject());
+      throw_method_.Assign(method);
+      throw_dex_pc_ = dex_pc;
+    }
+
+    if (dex_pc != DexFile::kDexNoIndex) {
+      StackHandleScope<2> hs(self_);
+      uint32_t found_dex_pc;
+      Handle<mirror::Class> exception_class(hs.NewHandle(exception_->GetClass()));
+      Handle<mirror::ArtMethod> h_method(hs.NewHandle(method));
+      bool unused_clear_exception;
+      found_dex_pc = mirror::ArtMethod::FindCatchBlock(
+          h_method, exception_class, dex_pc, &unused_clear_exception);
+      if (found_dex_pc != DexFile::kDexNoIndex) {
+        catch_method_.Assign(method);
+        catch_dex_pc_ = found_dex_pc;
+        return false;  // End stack walk.
+      }
+    }
+    return true;  // Continue stack walk.
+  }
+
+  mirror::ArtMethod* GetCatchMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return catch_method_.Get();
+  }
+
+  mirror::ArtMethod* GetThrowMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return throw_method_.Get();
+  }
+
+  mirror::Object* GetThisAtThrow() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return this_at_throw_.Get();
+  }
+
+  uint32_t GetCatchDexPc() const {
+    return catch_dex_pc_;
+  }
+
+  uint32_t GetThrowDexPc() const {
+    return throw_dex_pc_;
+  }
+
+ private:
+  Thread* const self_;
+  const Handle<mirror::Throwable>& exception_;
+  StackHandleScope<3> handle_scope_;
+  MutableHandle<mirror::Object> this_at_throw_;
+  MutableHandle<mirror::ArtMethod> catch_method_;
+  MutableHandle<mirror::ArtMethod> throw_method_;
+  uint32_t catch_dex_pc_;
+  uint32_t throw_dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(CatchLocationFinder);
+};
+
+void Dbg::PostException(mirror::Throwable* exception_object) {
   if (!IsDebuggerActive()) {
     return;
   }
+  StackHandleScope<1> handle_scope(Thread::Current());
+  Handle<mirror::Throwable> h_exception(handle_scope.NewHandle(exception_object));
+  std::unique_ptr<Context> context(Context::Create());
+  CatchLocationFinder clf(Thread::Current(), h_exception, context.get());
+  clf.WalkStack(/* include_transitions */ false);
   JDWP::EventLocation exception_throw_location;
-  SetEventLocation(&exception_throw_location, throw_location.GetMethod(), throw_location.GetDexPc());
+  SetEventLocation(&exception_throw_location, clf.GetThrowMethod(), clf.GetThrowDexPc());
   JDWP::EventLocation exception_catch_location;
-  SetEventLocation(&exception_catch_location, catch_method, catch_dex_pc);
+  SetEventLocation(&exception_catch_location, clf.GetCatchMethod(), clf.GetCatchDexPc());
 
-  gJdwpState->PostException(&exception_throw_location, exception_object, &exception_catch_location,
-                            throw_location.GetThis());
+  gJdwpState->PostException(&exception_throw_location, h_exception.Get(), &exception_catch_location,
+                            clf.GetThisAtThrow());
 }
 
 void Dbg::PostClassPrepare(mirror::Class* c) {
@@ -3704,18 +3793,12 @@
 
   // We can be called while an exception is pending. We need
   // to preserve that across the method invocation.
-  StackHandleScope<4> hs(soa.Self());
-  auto old_throw_this_object = hs.NewHandle<mirror::Object>(nullptr);
-  auto old_throw_method = hs.NewHandle<mirror::ArtMethod>(nullptr);
+  StackHandleScope<2> hs(soa.Self());
   auto old_exception = hs.NewHandle<mirror::Throwable>(nullptr);
-  uint32_t old_throw_dex_pc;
   {
     ThrowLocation old_throw_location;
-    mirror::Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
-    old_throw_this_object.Assign(old_throw_location.GetThis());
-    old_throw_method.Assign(old_throw_location.GetMethod());
+    mirror::Throwable* old_exception_obj = soa.Self()->GetException();
     old_exception.Assign(old_exception_obj);
-    old_throw_dex_pc = old_throw_location.GetDexPc();
     soa.Self()->ClearException();
   }
 
@@ -3738,7 +3821,7 @@
   pReq->result_value = InvokeWithJValues(soa, pReq->receiver, soa.EncodeMethod(m.Get()),
                                          reinterpret_cast<jvalue*>(pReq->arg_values));
 
-  mirror::Throwable* exception = soa.Self()->GetException(nullptr);
+  mirror::Throwable* exception = soa.Self()->GetException();
   soa.Self()->ClearException();
   pReq->exception = gRegistry->Add(exception);
   pReq->result_tag = BasicTagFromDescriptor(m.Get()->GetShorty());
@@ -3767,9 +3850,7 @@
   }
 
   if (old_exception.Get() != nullptr) {
-    ThrowLocation gc_safe_throw_location(old_throw_this_object.Get(), old_throw_method.Get(),
-                                         old_throw_dex_pc);
-    soa.Self()->SetException(gc_safe_throw_location, old_exception.Get());
+    soa.Self()->SetException(old_exception.Get());
   }
 }
 
diff --git a/runtime/debugger.h b/runtime/debugger.h
index 0c22148..428ded7 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -529,8 +529,7 @@
                                          mirror::Object* this_object, mirror::ArtField* f,
                                          const JValue* field_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void PostException(const ThrowLocation& throw_location, mirror::ArtMethod* catch_method,
-                            uint32_t catch_dex_pc, mirror::Throwable* exception)
+  static void PostException(mirror::Throwable* exception)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void PostThreadStart(Thread* t)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 9d84e4a..149c6b4 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -613,9 +613,8 @@
 inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) {
   // Save any pending exception over monitor exit call.
   mirror::Throwable* saved_exception = NULL;
-  ThrowLocation saved_throw_location;
   if (UNLIKELY(self->IsExceptionPending())) {
-    saved_exception = self->GetException(&saved_throw_location);
+    saved_exception = self->GetException();
     self->ClearException();
   }
   // Decode locked object and unlock, before popping local references.
@@ -624,11 +623,11 @@
     LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
         << saved_exception->Dump()
         << "\nEncountered second exception during implicit MonitorExit:\n"
-        << self->GetException(NULL)->Dump();
+        << self->GetException()->Dump();
   }
   // Restore pending exception.
   if (saved_exception != NULL) {
-    self->SetException(saved_throw_location, saved_exception);
+    self->SetException(saved_exception);
   }
 }
 
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 5ea9f70..af528b7 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -187,8 +187,7 @@
         error_msg = "Could not create stack trace.";
       }
       // Throw the exception.
-      self->SetException(self->GetCurrentLocationForThrow(),
-                         reinterpret_cast<mirror::Throwable*>(self->DecodeJObject(exc.get())));
+      self->SetException(reinterpret_cast<mirror::Throwable*>(self->DecodeJObject(exc.get())));
     } else {
       // Could not allocate a string object.
       error_msg = "Couldn't throw new StackOverflowError because JNI NewStringUTF failed.";
@@ -302,7 +301,7 @@
   } else {
     // In the case of checked exceptions that aren't declared, the exception must be wrapped by
     // a UndeclaredThrowableException.
-    mirror::Throwable* exception = soa.Self()->GetException(NULL);
+    mirror::Throwable* exception = soa.Self()->GetException();
     if (exception->IsCheckedException()) {
       mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
       mirror::Class* proxy_class = rcvr->GetClass();
diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
index 14ab320..d88d262 100644
--- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
@@ -29,7 +29,7 @@
 
 extern "C" void artDeoptimize(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
-  self->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
+  self->SetException(Thread::GetDeoptimizationException());
   self->QuickDeliverException();
 }
 
diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
index 25df40b..127f9e0 100644
--- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
@@ -41,12 +41,12 @@
    * exception_ in thread and delivering the exception.
    */
   ScopedQuickEntrypointChecks sqec(self);
-  ThrowLocation throw_location = self->GetCurrentLocationForThrow();
   if (exception == nullptr) {
+    ThrowLocation throw_location = self->GetCurrentLocationForThrow();
     self->ThrowNewException(throw_location, "Ljava/lang/NullPointerException;",
                             "throw with null exception");
   } else {
-    self->SetException(throw_location, exception);
+    self->SetException(exception);
   }
   self->QuickDeliverException();
 }
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 9173357..0fdfcb3 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -93,8 +93,7 @@
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, opeer, jpeer, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, jpeer, stack_begin, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_begin, stack_size, sizeof(void*));
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, throw_location, sizeof(void*));
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, throw_location, stack_trace_sample, sizeof(ThrowLocation));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, stack_trace_sample, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_trace_sample, wait_next, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, wait_next, monitor_enter_object, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, monitor_enter_object, top_handle_scope, sizeof(void*));
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index c94dab9..085062c 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -949,19 +949,16 @@
   }
 }
 
-void Instrumentation::ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
-                                           mirror::ArtMethod* catch_method,
-                                           uint32_t catch_dex_pc,
+void Instrumentation::ExceptionCaughtEvent(Thread* thread,
                                            mirror::Throwable* exception_object) const {
   if (HasExceptionCaughtListeners()) {
-    DCHECK_EQ(thread->GetException(nullptr), exception_object);
+    DCHECK_EQ(thread->GetException(), exception_object);
     thread->ClearException();
     std::shared_ptr<std::list<InstrumentationListener*>> original(exception_caught_listeners_);
     for (InstrumentationListener* listener : *original.get()) {
-      listener->ExceptionCaught(thread, throw_location, catch_method, catch_dex_pc,
-                                exception_object);
+      listener->ExceptionCaught(thread, exception_object);
     }
-    thread->SetException(throw_location, exception_object);
+    thread->SetException(exception_object);
   }
 }
 
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index b667a40..e3f18f1 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -90,9 +90,7 @@
                             uint32_t dex_pc, mirror::ArtField* field, const JValue& field_value) = 0;
 
   // Call-back when an exception is caught.
-  virtual void ExceptionCaught(Thread* thread, const ThrowLocation& throw_location,
-                               mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
-                               mirror::Throwable* exception_object)
+  virtual void ExceptionCaught(Thread* thread, mirror::Throwable* exception_object)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
 
   // Call-back for when we get a backward branch.
@@ -322,9 +320,7 @@
   }
 
   // Inform listeners that an exception was caught.
-  void ExceptionCaughtEvent(Thread* thread, const ThrowLocation& throw_location,
-                            mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
-                            mirror::Throwable* exception_object) const
+  void ExceptionCaughtEvent(Thread* thread, mirror::Throwable* exception_object) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Called when an instrumented method is entered. The intended link register (lr) is saved so
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 754602f..3f09bd3 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -413,90 +413,16 @@
 #undef EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL
 #undef EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL
 
-/**
- * Finds the location where this exception will be caught. We search until we reach either the top
- * frame or a native frame, in which cases this exception is considered uncaught.
- */
-class CatchLocationFinder : public StackVisitor {
- public:
-  explicit CatchLocationFinder(Thread* self, Handle<mirror::Throwable>* exception)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-    : StackVisitor(self, nullptr), self_(self), handle_scope_(self), exception_(exception),
-      catch_method_(handle_scope_.NewHandle<mirror::ArtMethod>(nullptr)),
-      catch_dex_pc_(DexFile::kDexNoIndex), clear_exception_(false) {
-  }
-
-  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    mirror::ArtMethod* method = GetMethod();
-    if (method == nullptr) {
-      return true;
-    }
-    if (method->IsRuntimeMethod()) {
-      // Ignore callee save method.
-      DCHECK(method->IsCalleeSaveMethod());
-      return true;
-    }
-    if (method->IsNative()) {
-      return false;  // End stack walk.
-    }
-    DCHECK(!method->IsNative());
-    uint32_t dex_pc = GetDexPc();
-    if (dex_pc != DexFile::kDexNoIndex) {
-      uint32_t found_dex_pc;
-      {
-        StackHandleScope<3> hs(self_);
-        Handle<mirror::Class> exception_class(hs.NewHandle((*exception_)->GetClass()));
-        Handle<mirror::ArtMethod> h_method(hs.NewHandle(method));
-        found_dex_pc = mirror::ArtMethod::FindCatchBlock(h_method, exception_class, dex_pc,
-                                                         &clear_exception_);
-      }
-      if (found_dex_pc != DexFile::kDexNoIndex) {
-        catch_method_.Assign(method);
-        catch_dex_pc_ = found_dex_pc;
-        return false;  // End stack walk.
-      }
-    }
-    return true;  // Continue stack walk.
-  }
-
-  ArtMethod* GetCatchMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return catch_method_.Get();
-  }
-
-  uint32_t GetCatchDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return catch_dex_pc_;
-  }
-
-  bool NeedClearException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return clear_exception_;
-  }
-
- private:
-  Thread* const self_;
-  StackHandleScope<1> handle_scope_;
-  Handle<mirror::Throwable>* exception_;
-  MutableHandle<mirror::ArtMethod> catch_method_;
-  uint32_t catch_dex_pc_;
-  bool clear_exception_;
-
-
-  DISALLOW_COPY_AND_ASSIGN(CatchLocationFinder);
-};
-
 uint32_t FindNextInstructionFollowingException(Thread* self,
                                                ShadowFrame& shadow_frame,
                                                uint32_t dex_pc,
                                                const instrumentation::Instrumentation* instrumentation) {
   self->VerifyStack();
-  ThrowLocation throw_location;
   StackHandleScope<3> hs(self);
-  Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException(&throw_location)));
+  Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException()));
   if (instrumentation->HasExceptionCaughtListeners()
       && self->IsExceptionThrownByCurrentMethod(exception.Get())) {
-    CatchLocationFinder clf(self, &exception);
-    clf.WalkStack(false);
-    instrumentation->ExceptionCaughtEvent(self, throw_location, clf.GetCatchMethod(),
-                                          clf.GetCatchDexPc(), exception.Get());
+    instrumentation->ExceptionCaughtEvent(self, exception.Get());
   }
   bool clear_exception = false;
   uint32_t found_dex_pc;
@@ -848,7 +774,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   if (self->IsExceptionPending()) {
     // If it is not an InternalError, wrap it.
-    std::string type(PrettyTypeOf(self->GetException(nullptr)));
+    std::string type(PrettyTypeOf(self->GetException()));
     if (type != "java.lang.InternalError") {
       self->ThrowNewWrappedException(self->GetCurrentLocationForThrow(),
                                      "Ljava/lang/ClassNotFoundException;",
@@ -903,7 +829,7 @@
     // This might have an error pending. But semantics are to just return null.
     if (self->IsExceptionPending()) {
       // If it is an InternalError, keep it. See CheckExceptionGenerateClassNotFound.
-      std::string type(PrettyTypeOf(self->GetException(nullptr)));
+      std::string type(PrettyTypeOf(self->GetException()));
       if (type != "java.lang.InternalError") {
         self->ClearException();
       }
@@ -936,7 +862,7 @@
     if (!ok) {
       std::string error_msg = StringPrintf("Failed in Class.newInstance for '%s' with %s",
                                            PrettyClass(h_klass.Get()).c_str(),
-                                           PrettyTypeOf(self->GetException(nullptr)).c_str());
+                                           PrettyTypeOf(self->GetException()).c_str());
       self->ThrowNewWrappedException(self->GetCurrentLocationForThrow(),
                                      "Ljava/lang/InternalError;",
                                      error_msg.c_str());
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 37324ea..f1ab747 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -244,7 +244,7 @@
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(MOVE_EXCEPTION) {
-    Throwable* exception = self->GetException(nullptr);
+    Throwable* exception = self->GetException();
     DCHECK(exception != nullptr) << "No pending exception on MOVE_EXCEPTION instruction";
     shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), exception);
     self->ClearException();
@@ -605,7 +605,7 @@
                                "Throwing '%s' that is not instance of Throwable",
                                exception->GetClass()->GetDescriptor(&temp));
     } else {
-      self->SetException(shadow_frame.GetCurrentLocationForThrow(), exception->AsThrowable());
+      self->SetException(exception->AsThrowable());
     }
     HANDLE_PENDING_EXCEPTION();
   }
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 2f85587..dceed47 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -163,7 +163,7 @@
         break;
       case Instruction::MOVE_EXCEPTION: {
         PREAMBLE();
-        Throwable* exception = self->GetException(nullptr);
+        Throwable* exception = self->GetException();
         DCHECK(exception != nullptr) << "No pending exception on MOVE_EXCEPTION instruction";
         shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), exception);
         self->ClearException();
@@ -515,7 +515,7 @@
                                    "Throwing '%s' that is not instance of Throwable",
                                    exception->GetClass()->GetDescriptor(&temp));
         } else {
-          self->SetException(shadow_frame.GetCurrentLocationForThrow(), exception->AsThrowable());
+          self->SetException(exception->AsThrowable());
         }
         HANDLE_PENDING_EXCEPTION();
         break;
diff --git a/runtime/jit/jit_instrumentation.h b/runtime/jit/jit_instrumentation.h
index 9576f4b..9d122e0 100644
--- a/runtime/jit/jit_instrumentation.h
+++ b/runtime/jit/jit_instrumentation.h
@@ -83,8 +83,7 @@
                             mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/,
                             mirror::ArtField* /*field*/, const JValue& /*field_value*/)
       OVERRIDE { }
-  virtual void ExceptionCaught(Thread* /*thread*/, const ThrowLocation& /*throw_location*/,
-                               mirror::ArtMethod* /*catch_method*/, uint32_t /*catch_dex_pc*/,
+  virtual void ExceptionCaught(Thread* /*thread*/,
                                mirror::Throwable* /*exception_object*/) OVERRIDE { }
 
   virtual void DexPcMoved(Thread* /*self*/, mirror::Object* /*this_object*/,
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 561302e..213de6f 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -196,16 +196,16 @@
   if (field_type == nullptr) {
     // Failed to find type from the signature of the field.
     DCHECK(soa.Self()->IsExceptionPending());
-    ThrowLocation throw_location;
     StackHandleScope<1> hs2(soa.Self());
-    Handle<mirror::Throwable> cause(hs2.NewHandle(soa.Self()->GetException(&throw_location)));
+    Handle<mirror::Throwable> cause(hs2.NewHandle(soa.Self()->GetException()));
     soa.Self()->ClearException();
     std::string temp;
+    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
                                    "no type \"%s\" found and so no field \"%s\" "
                                    "could be found in class \"%s\" or its superclasses", sig, name,
                                    c->GetDescriptor(&temp));
-    soa.Self()->GetException(nullptr)->SetCause(cause.Get());
+    soa.Self()->GetException()->SetCause(cause.Get());
     return nullptr;
   }
   std::string temp;
@@ -282,8 +282,7 @@
     return JNI_ERR;
   }
   ScopedObjectAccess soa(env);
-  ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
-  soa.Self()->SetException(throw_location, soa.Decode<mirror::Throwable*>(exception.get()));
+  soa.Self()->SetException(soa.Decode<mirror::Throwable*>(exception.get()));
   return JNI_OK;
 }
 
@@ -433,8 +432,7 @@
     if (exception == nullptr) {
       return JNI_ERR;
     }
-    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
-    soa.Self()->SetException(throw_location, exception);
+    soa.Self()->SetException(exception);
     return JNI_OK;
   }
 
@@ -456,25 +454,14 @@
     ScopedObjectAccess soa(env);
 
     // If we have no exception to describe, pass through.
-    if (!soa.Self()->GetException(nullptr)) {
+    if (!soa.Self()->GetException()) {
       return;
     }
 
-    StackHandleScope<3> hs(soa.Self());
-    // TODO: Use nullptr instead of null handles?
-    auto old_throw_this_object(hs.NewHandle<mirror::Object>(nullptr));
-    auto old_throw_method(hs.NewHandle<mirror::ArtMethod>(nullptr));
-    auto old_exception(hs.NewHandle<mirror::Throwable>(nullptr));
-    uint32_t old_throw_dex_pc;
-    {
-      ThrowLocation old_throw_location;
-      mirror::Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
-      old_throw_this_object.Assign(old_throw_location.GetThis());
-      old_throw_method.Assign(old_throw_location.GetMethod());
-      old_exception.Assign(old_exception_obj);
-      old_throw_dex_pc = old_throw_location.GetDexPc();
-      soa.Self()->ClearException();
-    }
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::Throwable> old_exception(
+        hs.NewHandle<mirror::Throwable>(soa.Self()->GetException()));
+    soa.Self()->ClearException();
     ScopedLocalRef<jthrowable> exception(env,
                                          soa.AddLocalReference<jthrowable>(old_exception.Get()));
     ScopedLocalRef<jclass> exception_class(env, env->GetObjectClass(exception.get()));
@@ -485,20 +472,17 @@
     } else {
       env->CallVoidMethod(exception.get(), mid);
       if (soa.Self()->IsExceptionPending()) {
-        LOG(WARNING) << "JNI WARNING: " << PrettyTypeOf(soa.Self()->GetException(nullptr))
+        LOG(WARNING) << "JNI WARNING: " << PrettyTypeOf(soa.Self()->GetException())
                      << " thrown while calling printStackTrace";
         soa.Self()->ClearException();
       }
     }
-    ThrowLocation gc_safe_throw_location(old_throw_this_object.Get(), old_throw_method.Get(),
-                                         old_throw_dex_pc);
-
-    soa.Self()->SetException(gc_safe_throw_location, old_exception.Get());
+    soa.Self()->SetException(old_exception.Get());
   }
 
   static jthrowable ExceptionOccurred(JNIEnv* env) {
     ScopedObjectAccess soa(env);
-    mirror::Object* exception = soa.Self()->GetException(nullptr);
+    mirror::Object* exception = soa.Self()->GetException();
     return soa.AddLocalReference<jthrowable>(exception);
   }
 
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 85fc5f3..bc58709 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -271,9 +271,8 @@
   const DexFile::CodeItem* code_item = h_this->GetCodeItem();
   // Set aside the exception while we resolve its type.
   Thread* self = Thread::Current();
-  ThrowLocation throw_location;
   StackHandleScope<1> hs(self);
-  Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException(&throw_location)));
+  Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException()));
   self->ClearException();
   // Default to handler not found.
   uint32_t found_dex_pc = DexFile::kDexNoIndex;
@@ -309,7 +308,7 @@
   }
   // Put the exception back.
   if (exception.Get() != nullptr) {
-    self->SetException(throw_location, exception.Get());
+    self->SetException(exception.Get());
   }
   return found_dex_pc;
 }
@@ -434,7 +433,7 @@
 #else
       (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
 #endif
-      if (UNLIKELY(self->GetException(nullptr) == Thread::GetDeoptimizationException())) {
+      if (UNLIKELY(self->GetException() == Thread::GetDeoptimizationException())) {
         // Unusual case where we were running generated code and an
         // exception was thrown to force the activations to be removed from the
         // stack. Continue execution in the interpreter.
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 96b15dd..6f4ef60 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -77,13 +77,9 @@
         << "Attempt to set as erroneous an already erroneous class " << PrettyClass(this);
 
     // Stash current exception.
-    StackHandleScope<3> hs(self);
-    ThrowLocation old_throw_location;
-    Handle<mirror::Throwable> old_exception(hs.NewHandle(self->GetException(&old_throw_location)));
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Throwable> old_exception(hs.NewHandle(self->GetException()));
     CHECK(old_exception.Get() != nullptr);
-    Handle<mirror::Object> old_throw_this_object(hs.NewHandle(old_throw_location.GetThis()));
-    Handle<mirror::ArtMethod> old_throw_method(hs.NewHandle(old_throw_location.GetMethod()));
-    uint32_t old_throw_dex_pc = old_throw_location.GetDexPc();
     Class* eiie_class;
     // Do't attempt to use FindClass if we have an OOM error since this can try to do more
     // allocations and may cause infinite loops.
@@ -109,9 +105,7 @@
     }
 
     // Restore exception.
-    ThrowLocation gc_safe_throw_location(old_throw_this_object.Get(), old_throw_method.Get(),
-                                         old_throw_dex_pc);
-    self->SetException(gc_safe_throw_location, old_exception.Get());
+    self->SetException(old_exception.Get());
   }
   static_assert(sizeof(Status) == sizeof(uint32_t), "Size of status not equal to uint32");
   if (Runtime::Current()->IsActiveTransaction()) {
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 9b345a6..21972a1 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -124,12 +124,12 @@
 
   EXPECT_TRUE(oa->Get(-1) == NULL);
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass());
   soa.Self()->ClearException();
 
   EXPECT_TRUE(oa->Get(2) == NULL);
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass());
   soa.Self()->ClearException();
 
   ASSERT_TRUE(oa->GetClass() != NULL);
@@ -213,12 +213,12 @@
 
   EXPECT_EQ(0, a->Get(-1));
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass());
   soa.Self()->ClearException();
 
   EXPECT_EQ(0, a->Get(2));
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass());
   soa.Self()->ClearException();
 }
 
@@ -262,12 +262,12 @@
 
   EXPECT_DOUBLE_EQ(0, a->Get(-1));
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass());
   soa.Self()->ClearException();
 
   EXPECT_DOUBLE_EQ(0, a->Get(2));
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass());
   soa.Self()->ClearException();
 }
 
@@ -292,12 +292,12 @@
 
   EXPECT_FLOAT_EQ(0, a->Get(-1));
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass());
   soa.Self()->ClearException();
 
   EXPECT_FLOAT_EQ(0, a->Get(2));
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(aioobe, soa.Self()->GetException(NULL)->GetClass());
+  EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass());
   soa.Self()->ClearException();
 }
 
@@ -335,7 +335,7 @@
   dims->Set<false>(0, -1);
   multi = Array::CreateMultiArray(soa.Self(), c, dims);
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
-  EXPECT_EQ(PrettyDescriptor(soa.Self()->GetException(NULL)->GetClass()),
+  EXPECT_EQ(PrettyDescriptor(soa.Self()->GetException()->GetClass()),
             "java.lang.NegativeArraySizeException");
   soa.Self()->ClearException();
 
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 45a971d..dce8bac 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -306,7 +306,7 @@
     std::ostringstream ss;
     self->Dump(ss);
     LOG(Runtime::Current()->IsStarted() ? INFO : ERROR)
-        << self->GetException(NULL)->Dump() << "\n" << ss.str();
+        << self->GetException()->Dump() << "\n" << ss.str();
   }
   va_end(args);
 }
diff --git a/runtime/oat.h b/runtime/oat.h
index f973b28..5540ade 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  static constexpr uint8_t kOatVersion[] = { '0', '5', '6', '\0' };
+  static constexpr uint8_t kOatVersion[] = { '0', '5', '7', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 1ddb761..0eb8eca 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -114,8 +114,7 @@
   DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor);
 };
 
-void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,
-                                      mirror::Throwable* exception) {
+void QuickExceptionHandler::FindCatch(mirror::Throwable* exception) {
   DCHECK(!is_deoptimization_);
   if (kDebugExceptionDelivery) {
     mirror::String* msg = exception->GetDetailMessage();
@@ -145,15 +144,14 @@
     DCHECK(!self_->IsExceptionPending());
   } else {
     // Put exception back in root set with clear throw location.
-    self_->SetException(ThrowLocation(), exception_ref.Get());
+    self_->SetException(exception_ref.Get());
   }
   // The debugger may suspend this thread and walk its stack. Let's do this before popping
   // instrumentation frames.
   instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
   if (instrumentation->HasExceptionCaughtListeners()
       && self_->IsExceptionThrownByCurrentMethod(exception)) {
-    instrumentation->ExceptionCaughtEvent(self_, throw_location, handler_method_, handler_dex_pc_,
-                                          exception_ref.Get());
+    instrumentation->ExceptionCaughtEvent(self_, exception_ref.Get());
   }
 }
 
@@ -283,7 +281,7 @@
   visitor.WalkStack(true);
 
   // Restore deoptimization exception
-  self_->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
+  self_->SetException(Thread::GetDeoptimizationException());
 }
 
 // Unwinds all instrumentation stack frame prior to catch handler or upcall.
diff --git a/runtime/quick_exception_handler.h b/runtime/quick_exception_handler.h
index a0e6a79..08619fa 100644
--- a/runtime/quick_exception_handler.h
+++ b/runtime/quick_exception_handler.h
@@ -44,8 +44,7 @@
     UNREACHABLE();
   }
 
-  void FindCatch(const ThrowLocation& throw_location, mirror::Throwable* exception)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FindCatch(mirror::Throwable* exception) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void DeoptimizeStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void UpdateInstrumentationStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   NO_RETURN void DoLongJump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 2aeb92d..4acd07f 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -366,7 +366,7 @@
       CHECK(self->IsExceptionPending());
       LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
           << h_m->GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
-          << self->GetException(nullptr)->Dump();
+          << self->GetException()->Dump();
       self->ClearException();
       ++error_count;
     } else if (!param_type->IsPrimitive()) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 383308c..2043672 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -306,11 +306,8 @@
     DCHECK(Locks::mutator_lock_->IsExclusiveHeld(self) || Locks::mutator_lock_->IsSharedHeld(self));
     self->Dump(os);
     if (self->IsExceptionPending()) {
-      ThrowLocation throw_location;
-      mirror::Throwable* exception = self->GetException(&throw_location);
-      os << "Pending exception " << PrettyTypeOf(exception)
-          << " thrown by '" << throw_location.Dump() << "'\n"
-          << exception->Dump();
+      mirror::Throwable* exception = self->GetException();
+      os << "Pending exception " << exception->Dump();
     }
   }
 
@@ -1020,14 +1017,14 @@
   self->ThrowNewException(ThrowLocation(), "Ljava/lang/OutOfMemoryError;",
                           "OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
                           "no stack trace available");
-  pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException(NULL));
+  pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException());
   self->ClearException();
 
   // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class
   // ahead of checking the application's class loader.
   self->ThrowNewException(ThrowLocation(), "Ljava/lang/NoClassDefFoundError;",
                           "Class not found using the boot class loader; no stack trace available");
-  pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException(NULL));
+  pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException());
   self->ClearException();
 
   // Look for a native bridge.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index fdb1f9d..e31af16 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1033,18 +1033,11 @@
   // assumption that there is no exception pending on entry. Thus, stash any pending exception.
   // Thread::Current() instead of this in case a thread is dumping the stack of another suspended
   // thread.
-  StackHandleScope<3> scope(Thread::Current());
+  StackHandleScope<1> scope(Thread::Current());
   Handle<mirror::Throwable> exc;
-  Handle<mirror::Object> throw_location_this_object;
-  Handle<mirror::ArtMethod> throw_location_method;
-  uint32_t throw_location_dex_pc;
   bool have_exception = false;
   if (IsExceptionPending()) {
-    ThrowLocation exc_location;
-    exc = scope.NewHandle(GetException(&exc_location));
-    throw_location_this_object = scope.NewHandle(exc_location.GetThis());
-    throw_location_method = scope.NewHandle(exc_location.GetMethod());
-    throw_location_dex_pc = exc_location.GetDexPc();
+    exc = scope.NewHandle(GetException());
     const_cast<Thread*>(this)->ClearException();
     have_exception = true;
   }
@@ -1055,10 +1048,7 @@
   dumper.WalkStack();
 
   if (have_exception) {
-    ThrowLocation exc_location(throw_location_this_object.Get(),
-                               throw_location_method.Get(),
-                               throw_location_dex_pc);
-    const_cast<Thread*>(this)->SetException(exc_location, exc.Get());
+    const_cast<Thread*>(this)->SetException(exc.Get());
   }
 }
 
@@ -1188,7 +1178,7 @@
 void Thread::AssertNoPendingException() const {
   if (UNLIKELY(IsExceptionPending())) {
     ScopedObjectAccess soa(Thread::Current());
-    mirror::Throwable* exception = GetException(nullptr);
+    mirror::Throwable* exception = GetException();
     LOG(FATAL) << "No pending exception expected: " << exception->Dump();
   }
 }
@@ -1196,7 +1186,7 @@
 void Thread::AssertNoPendingExceptionForNewException(const char* msg) const {
   if (UNLIKELY(IsExceptionPending())) {
     ScopedObjectAccess soa(Thread::Current());
-    mirror::Throwable* exception = GetException(nullptr);
+    mirror::Throwable* exception = GetException();
     LOG(FATAL) << "Throwing new exception '" << msg << "' with unexpected pending exception: "
         << exception->Dump();
   }
@@ -1740,25 +1730,24 @@
   ThrowNewWrappedException(throw_location, exception_class_descriptor, msg);
 }
 
+static mirror::ClassLoader* GetClassLoaderFromThrowLocation(const ThrowLocation& throw_location)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return throw_location.GetMethod() != nullptr
+      ? throw_location.GetMethod()->GetDeclaringClass()->GetClassLoader()
+      : nullptr;
+}
+
 void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
                                       const char* exception_class_descriptor,
                                       const char* msg) {
   DCHECK_EQ(this, Thread::Current());
   ScopedObjectAccessUnchecked soa(this);
-  StackHandleScope<5> hs(soa.Self());
-  // Ensure we don't forget arguments over object allocation.
-  Handle<mirror::Object> saved_throw_this(hs.NewHandle(throw_location.GetThis()));
-  Handle<mirror::ArtMethod> saved_throw_method(hs.NewHandle(throw_location.GetMethod()));
-  // Ignore the cause throw location. TODO: should we report this as a re-throw?
-  ScopedLocalRef<jobject> cause(GetJniEnv(), soa.AddLocalReference<jobject>(GetException(nullptr)));
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(GetClassLoaderFromThrowLocation(throw_location)));
+  ScopedLocalRef<jobject> cause(GetJniEnv(), soa.AddLocalReference<jobject>(GetException()));
   ClearException();
   Runtime* runtime = Runtime::Current();
-
-  mirror::ClassLoader* cl = nullptr;
-  if (saved_throw_method.Get() != nullptr) {
-    cl = saved_throw_method.Get()->GetDeclaringClass()->GetClassLoader();
-  }
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(cl));
   Handle<mirror::Class> exception_class(
       hs.NewHandle(runtime->GetClassLinker()->FindClass(this, exception_class_descriptor,
                                                         class_loader)));
@@ -1779,9 +1768,7 @@
 
   // If we couldn't allocate the exception, throw the pre-allocated out of memory exception.
   if (exception.Get() == nullptr) {
-    ThrowLocation gc_safe_throw_location(saved_throw_this.Get(), saved_throw_method.Get(),
-                                         throw_location.GetDexPc());
-    SetException(gc_safe_throw_location, Runtime::Current()->GetPreAllocatedOutOfMemoryError());
+    SetException(Runtime::Current()->GetPreAllocatedOutOfMemoryError());
     return;
   }
 
@@ -1831,9 +1818,7 @@
     if (trace.get() != nullptr) {
       exception->SetStackState(down_cast<mirror::Throwable*>(DecodeJObject(trace.get())));
     }
-    ThrowLocation gc_safe_throw_location(saved_throw_this.Get(), saved_throw_method.Get(),
-                                         throw_location.GetDexPc());
-    SetException(gc_safe_throw_location, exception.Get());
+    SetException(exception.Get());
   } else {
     jvalue jv_args[2];
     size_t i = 0;
@@ -1848,9 +1833,7 @@
     }
     InvokeWithJValues(soa, exception.Get(), soa.EncodeMethod(exception_init_method), jv_args);
     if (LIKELY(!IsExceptionPending())) {
-      ThrowLocation gc_safe_throw_location(saved_throw_this.Get(), saved_throw_method.Get(),
-                                           throw_location.GetDexPc());
-      SetException(gc_safe_throw_location, exception.Get());
+      SetException(exception.Get());
     }
   }
 }
@@ -1858,14 +1841,13 @@
 void Thread::ThrowOutOfMemoryError(const char* msg) {
   LOG(WARNING) << StringPrintf("Throwing OutOfMemoryError \"%s\"%s",
       msg, (tls32_.throwing_OutOfMemoryError ? " (recursive case)" : ""));
-  ThrowLocation throw_location = GetCurrentLocationForThrow();
   if (!tls32_.throwing_OutOfMemoryError) {
     tls32_.throwing_OutOfMemoryError = true;
-    ThrowNewException(throw_location, "Ljava/lang/OutOfMemoryError;", msg);
+    ThrowNewException(GetCurrentLocationForThrow(), "Ljava/lang/OutOfMemoryError;", msg);
     tls32_.throwing_OutOfMemoryError = false;
   } else {
     Dump(LOG(WARNING));  // The pre-allocated OOME has no stack, so help out and log one.
-    SetException(throw_location, Runtime::Current()->GetPreAllocatedOutOfMemoryError());
+    SetException(Runtime::Current()->GetPreAllocatedOutOfMemoryError());
   }
 }
 
@@ -2030,8 +2012,7 @@
 
 void Thread::QuickDeliverException() {
   // Get exception from thread.
-  ThrowLocation throw_location;
-  mirror::Throwable* exception = GetException(&throw_location);
+  mirror::Throwable* exception = GetException();
   CHECK(exception != nullptr);
   // Don't leave exception visible while we try to find the handler, which may cause class
   // resolution.
@@ -2041,7 +2022,7 @@
   if (is_deoptimization) {
     exception_handler.DeoptimizeStack();
   } else {
-    exception_handler.FindCatch(throw_location, exception);
+    exception_handler.FindCatch(exception);
   }
   exception_handler.UpdateInstrumentationStack();
   exception_handler.DoLongJump();
@@ -2302,7 +2283,6 @@
     visitor(reinterpret_cast<mirror::Object**>(&tlsPtr_.exception), arg,
             RootInfo(kRootNativeStack, thread_id));
   }
-  tlsPtr_.throw_location.VisitRoots(visitor, arg);
   if (tlsPtr_.monitor_enter_object != nullptr) {
     visitor(&tlsPtr_.monitor_enter_object, arg, RootInfo(kRootNativeStack, thread_id));
   }
diff --git a/runtime/thread.h b/runtime/thread.h
index e4c91b7..af02dc7 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -326,11 +326,7 @@
     return tlsPtr_.exception != nullptr;
   }
 
-  mirror::Throwable* GetException(ThrowLocation* throw_location) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (throw_location != nullptr) {
-      *throw_location = tlsPtr_.throw_location;
-    }
+  mirror::Throwable* GetException() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return tlsPtr_.exception;
   }
 
@@ -338,17 +334,15 @@
   void AssertNoPendingException() const;
   void AssertNoPendingExceptionForNewException(const char* msg) const;
 
-  void SetException(const ThrowLocation& throw_location, mirror::Throwable* new_exception)
+  void SetException(mirror::Throwable* new_exception)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     CHECK(new_exception != NULL);
     // TODO: DCHECK(!IsExceptionPending());
     tlsPtr_.exception = new_exception;
-    tlsPtr_.throw_location = throw_location;
   }
 
   void ClearException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     tlsPtr_.exception = nullptr;
-    tlsPtr_.throw_location.Clear();
   }
 
   // Find catch block and perform long jump to appropriate exception handle
@@ -1034,7 +1028,7 @@
   struct PACKED(4) tls_ptr_sized_values {
       tls_ptr_sized_values() : card_table(nullptr), exception(nullptr), stack_end(nullptr),
       managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), self(nullptr), opeer(nullptr),
-      jpeer(nullptr), stack_begin(nullptr), stack_size(0), throw_location(),
+      jpeer(nullptr), stack_begin(nullptr), stack_size(0),
       stack_trace_sample(nullptr), wait_next(nullptr), monitor_enter_object(nullptr),
       top_handle_scope(nullptr), class_loader_override(nullptr), long_jump_context(nullptr),
       instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr),
@@ -1084,9 +1078,6 @@
     // Size of the stack.
     size_t stack_size;
 
-    // The location the current exception was thrown from.
-    ThrowLocation throw_location;
-
     // Pointer to previous stack trace captured by sampling profiler.
     std::vector<mirror::ArtMethod*>* stack_trace_sample;
 
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 93b3877..a1296f4 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -619,11 +619,9 @@
                       thread_clock_diff, wall_clock_diff);
 }
 
-void Trace::ExceptionCaught(Thread* thread, const ThrowLocation& throw_location,
-                            mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
-                            mirror::Throwable* exception_object)
+void Trace::ExceptionCaught(Thread* thread, mirror::Throwable* exception_object)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  UNUSED(thread, throw_location, catch_method, catch_dex_pc, exception_object);
+  UNUSED(thread, exception_object);
   LOG(ERROR) << "Unexpected exception caught event in tracing";
 }
 
diff --git a/runtime/trace.h b/runtime/trace.h
index 9ba30d5..dd8186a 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -95,9 +95,7 @@
                     mirror::ArtMethod* method, uint32_t dex_pc, mirror::ArtField* field,
                     const JValue& field_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
-  void ExceptionCaught(Thread* thread, const ThrowLocation& throw_location,
-                       mirror::ArtMethod* catch_method, uint32_t catch_dex_pc,
-                       mirror::Throwable* exception_object)
+  void ExceptionCaught(Thread* thread, mirror::Throwable* exception_object)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
   void BackwardBranch(Thread* thread, mirror::ArtMethod* method, int32_t dex_pc_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;