summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/Android.mk2
-rw-r--r--runtime/catch_block_stack_visitor.cc111
-rw-r--r--runtime/catch_block_stack_visitor.h58
-rw-r--r--runtime/catch_finder.cc135
-rw-r--r--runtime/catch_finder.h95
-rw-r--r--runtime/thread.cc195
6 files changed, 405 insertions, 191 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 576ed1b..a3a8bec 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -34,6 +34,8 @@ LIBART_COMMON_SRC_FILES := \
base/unix_file/random_access_file_utils.cc \
base/unix_file/string_file.cc \
check_jni.cc \
+ catch_block_stack_visitor.cc \
+ catch_finder.cc \
class_linker.cc \
common_throws.cc \
debugger.cc \
diff --git a/runtime/catch_block_stack_visitor.cc b/runtime/catch_block_stack_visitor.cc
new file mode 100644
index 0000000..f9acffb
--- /dev/null
+++ b/runtime/catch_block_stack_visitor.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "catch_block_stack_visitor.h"
+
+#include "dex_instruction.h"
+#include "catch_finder.h"
+#include "sirt_ref.h"
+#include "verifier/method_verifier.h"
+
+namespace art {
+
+bool CatchBlockStackVisitor::VisitFrame() {
+ catch_finder_->SetHandlerFrameId(GetFrameId());
+ mirror::ArtMethod* method = GetMethod();
+ if (method == nullptr) {
+ // This is the upcall, we remember the frame and last pc so that we may long jump to them.
+ catch_finder_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
+ catch_finder_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+ return false; // End stack walk.
+ } else {
+ if (method->IsRuntimeMethod()) {
+ // Ignore callee save method.
+ DCHECK(method->IsCalleeSaveMethod());
+ return true;
+ } else if (is_deoptimization_) {
+ return HandleDeoptimization(method);
+ } else {
+ return HandleTryItems(method);
+ }
+ }
+}
+
+bool CatchBlockStackVisitor::HandleTryItems(mirror::ArtMethod* method) {
+ uint32_t dex_pc = DexFile::kDexNoIndex;
+ if (method->IsNative()) {
+ ++native_method_count_;
+ } else {
+ dex_pc = GetDexPc();
+ }
+ if (dex_pc != DexFile::kDexNoIndex) {
+ bool clear_exception = false;
+ uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc, &clear_exception);
+ catch_finder_->SetClearException(clear_exception);
+ if (found_dex_pc != DexFile::kDexNoIndex) {
+ catch_finder_->SetHandlerDexPc(found_dex_pc);
+ catch_finder_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc));
+ catch_finder_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+ return false; // End stack walk.
+ }
+ }
+ return true; // Continue stack walk.
+}
+
+bool CatchBlockStackVisitor::HandleDeoptimization(mirror::ArtMethod* m) {
+ MethodHelper mh(m);
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
+ CHECK(code_item != nullptr);
+ uint16_t num_regs = code_item->registers_size_;
+ uint32_t dex_pc = GetDexPc();
+ const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
+ uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits();
+ ShadowFrame* new_frame = ShadowFrame::Create(num_regs, nullptr, m, new_dex_pc);
+ SirtRef<mirror::DexCache> dex_cache(self_, mh.GetDexCache());
+ SirtRef<mirror::ClassLoader> class_loader(self_, mh.GetClassLoader());
+ verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
+ &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
+ m->GetAccessFlags(), false, true);
+ verifier.Verify();
+ std::vector<int32_t> kinds = verifier.DescribeVRegs(dex_pc);
+ for (uint16_t reg = 0; reg < num_regs; ++reg) {
+ VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
+ switch (kind) {
+ case kUndefined:
+ new_frame->SetVReg(reg, 0xEBADDE09);
+ break;
+ case kConstant:
+ new_frame->SetVReg(reg, kinds.at((reg * 2) + 1));
+ break;
+ case kReferenceVReg:
+ new_frame->SetVRegReference(reg,
+ reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kind)));
+ break;
+ default:
+ new_frame->SetVReg(reg, GetVReg(m, reg, kind));
+ break;
+ }
+ }
+ if (prev_shadow_frame_ != nullptr) {
+ prev_shadow_frame_->SetLink(new_frame);
+ } else {
+ catch_finder_->SetTopShadowFrame(new_frame);
+ }
+ prev_shadow_frame_ = new_frame;
+ return true;
+}
+
+} // namespace art
diff --git a/runtime/catch_block_stack_visitor.h b/runtime/catch_block_stack_visitor.h
new file mode 100644
index 0000000..175ad7d
--- /dev/null
+++ b/runtime/catch_block_stack_visitor.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 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_RUNTIME_CATCH_BLOCK_STACK_VISITOR_H_
+#define ART_RUNTIME_CATCH_BLOCK_STACK_VISITOR_H_
+
+#include "mirror/throwable.h"
+#include "thread.h"
+
+namespace art {
+class CatchFinder;
+class ThrowLocation;
+
+// Finds catch handler or prepares deoptimization.
+class CatchBlockStackVisitor : public StackVisitor {
+ public:
+ CatchBlockStackVisitor(Thread* self, Context* context, mirror::Throwable* exception,
+ bool is_deoptimization, CatchFinder* catch_finder)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : StackVisitor(self, context),
+ self_(self), is_deoptimization_(is_deoptimization),
+ to_find_(is_deoptimization ? nullptr : exception->GetClass()),
+ catch_finder_(catch_finder), native_method_count_(0), prev_shadow_frame_(nullptr) {
+ }
+
+ bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+ bool HandleTryItems(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ Thread* const self_;
+ const bool is_deoptimization_;
+ // The type of the exception catch block to find.
+ mirror::Class* const to_find_;
+ CatchFinder* const catch_finder_;
+ // Number of native methods passed in crawl (equates to number of SIRTs to pop)
+ uint32_t native_method_count_;
+ ShadowFrame* prev_shadow_frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor);
+};
+
+} // namespace art
+#endif // ART_RUNTIME_CATCH_BLOCK_STACK_VISITOR_H_
diff --git a/runtime/catch_finder.cc b/runtime/catch_finder.cc
new file mode 100644
index 0000000..f0293d7
--- /dev/null
+++ b/runtime/catch_finder.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "catch_finder.h"
+#include "catch_block_stack_visitor.h"
+
+namespace art {
+
+CatchFinder::CatchFinder(Thread* self, const ThrowLocation& throw_location,
+ mirror::Throwable* exception, bool is_deoptimization)
+ : self_(self), context_(self->GetLongJumpContext()),
+ exception_(exception), is_deoptimization_(is_deoptimization), throw_location_(throw_location),
+ method_tracing_active_(is_deoptimization ||
+ Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()),
+ handler_quick_frame_(nullptr), handler_quick_frame_pc_(0),
+ handler_dex_pc_(0), clear_exception_(false), top_shadow_frame_(nullptr),
+ handler_frame_id_(kInvalidFrameId) {
+ // Exception not in root sets, can't allow GC.
+ last_no_assert_suspension_cause_ = self->StartAssertNoThreadSuspension("Finding catch block");
+}
+
+void CatchFinder::FindCatch() {
+ // Walk the stack to find catch handler or prepare for deoptimization.
+ CatchBlockStackVisitor visitor(self_, context_, exception_, is_deoptimization_, this);
+ visitor.WalkStack(true);
+
+ mirror::ArtMethod* catch_method = *handler_quick_frame_;
+ if (catch_method == nullptr) {
+ if (kDebugExceptionDelivery) {
+ LOG(INFO) << "Handler is upcall";
+ }
+ } else {
+ CHECK(!is_deoptimization_);
+ if (kDebugExceptionDelivery) {
+ const DexFile& dex_file = *catch_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+ int line_number = dex_file.GetLineNumFromPC(catch_method, handler_dex_pc_);
+ LOG(INFO) << "Handler: " << PrettyMethod(catch_method) << " (line: " << line_number << ")";
+ }
+ }
+ if (clear_exception_) {
+ // Exception was cleared as part of delivery.
+ DCHECK(!self_->IsExceptionPending());
+ } else {
+ // Put exception back in root set with clear throw location.
+ self_->SetException(ThrowLocation(), exception_);
+ }
+ self_->EndAssertNoThreadSuspension(last_no_assert_suspension_cause_);
+ // Do instrumentation events after allowing thread suspension again.
+ if (!is_deoptimization_) {
+ // The debugger may suspend this thread and walk its stack. Let's do this before popping
+ // instrumentation frames.
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+ instrumentation->ExceptionCaughtEvent(self_, throw_location_, catch_method, handler_dex_pc_,
+ exception_);
+ }
+}
+
+// Unwinds all instrumentation stack frame prior to catch handler or upcall.
+class InstrumentationStackVisitor : public StackVisitor {
+ public:
+ InstrumentationStackVisitor(Thread* self, bool is_deoptimization, size_t frame_id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : StackVisitor(self, nullptr),
+ self_(self), frame_id_(frame_id),
+ instrumentation_frames_to_pop_(0) {
+ CHECK_NE(frame_id_, kInvalidFrameId);
+ }
+
+ bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ size_t current_frame_id = GetFrameId();
+ if (current_frame_id > frame_id_) {
+ CHECK(GetMethod() != nullptr);
+ if (UNLIKELY(GetQuickInstrumentationExitPc() == GetReturnPc())) {
+ ++instrumentation_frames_to_pop_;
+ }
+ return true;
+ } else {
+ // We reached the frame of the catch handler or the upcall.
+ return false;
+ }
+ }
+
+ size_t GetInstrumentationFramesToPop() const {
+ return instrumentation_frames_to_pop_;
+ }
+
+ private:
+ Thread* const self_;
+ const size_t frame_id_;
+ size_t instrumentation_frames_to_pop_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstrumentationStackVisitor);
+};
+
+void CatchFinder::UpdateInstrumentationStack() {
+ if (method_tracing_active_) {
+ InstrumentationStackVisitor visitor(self_, is_deoptimization_, handler_frame_id_);
+ visitor.WalkStack(true);
+
+ size_t instrumentation_frames_to_pop = visitor.GetInstrumentationFramesToPop();
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+ for (size_t i = 0; i < instrumentation_frames_to_pop; ++i) {
+ instrumentation->PopMethodForUnwind(self_, is_deoptimization_);
+ }
+ }
+}
+
+void CatchFinder::DoLongJump() {
+ if (is_deoptimization_) {
+ // TODO: proper return value.
+ self_->SetDeoptimizationShadowFrame(top_shadow_frame_);
+ }
+ // Place context back on thread so it will be available when we continue.
+ self_->ReleaseLongJumpContext(context_);
+ context_->SetSP(reinterpret_cast<uintptr_t>(handler_quick_frame_));
+ CHECK_NE(handler_quick_frame_pc_, 0u);
+ context_->SetPC(handler_quick_frame_pc_);
+ context_->SmashCallerSaves();
+ context_->DoLongJump();
+}
+
+} // namespace art
diff --git a/runtime/catch_finder.h b/runtime/catch_finder.h
new file mode 100644
index 0000000..ebbafe2
--- /dev/null
+++ b/runtime/catch_finder.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 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_RUNTIME_CATCH_FINDER_H_
+#define ART_RUNTIME_CATCH_FINDER_H_
+
+#include "mirror/art_method-inl.h"
+#include "thread.h"
+
+namespace art {
+
+static constexpr bool kDebugExceptionDelivery = false;
+static constexpr size_t kInvalidFrameId = 0xffffffff;
+
+// Manages exception delivery for Quick backend. Not used by Portable backend.
+class CatchFinder {
+ public:
+ CatchFinder(Thread* self, const ThrowLocation& throw_location, mirror::Throwable* exception,
+ bool is_deoptimization)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ ~CatchFinder() {
+ LOG(FATAL) << "UNREACHABLE"; // Expected to take long jump.
+ }
+
+ void FindCatch() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void UpdateInstrumentationStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void DoLongJump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ void SetHandlerQuickFrame(mirror::ArtMethod** handler_quick_frame) {
+ handler_quick_frame_ = handler_quick_frame;
+ }
+
+ void SetHandlerQuickFramePc(uintptr_t handler_quick_frame_pc) {
+ handler_quick_frame_pc_ = handler_quick_frame_pc;
+ }
+
+ void SetHandlerDexPc(uint32_t dex_pc) {
+ handler_dex_pc_ = dex_pc;
+ }
+
+ void SetClearException(bool clear_exception) {
+ clear_exception_ = clear_exception;
+ }
+
+ void SetTopShadowFrame(ShadowFrame* top_shadow_frame) {
+ top_shadow_frame_ = top_shadow_frame;
+ }
+
+ void SetHandlerFrameId(size_t frame_id) {
+ handler_frame_id_ = frame_id;
+ }
+
+ private:
+ Thread* const self_;
+ Context* const context_;
+ mirror::Throwable* const exception_;
+ const bool is_deoptimization_;
+ // Location of the throw.
+ const ThrowLocation& throw_location_;
+ // Is method tracing active?
+ const bool method_tracing_active_;
+ // Support for nesting no thread suspension checks.
+ const char* last_no_assert_suspension_cause_;
+ // Quick frame with found handler or last frame if no handler found.
+ mirror::ArtMethod** handler_quick_frame_;
+ // PC to branch to for the handler.
+ uintptr_t handler_quick_frame_pc_;
+ // Associated dex PC.
+ uint32_t handler_dex_pc_;
+ // Should the exception be cleared as the catch block has no move-exception?
+ bool clear_exception_;
+ // Deoptimization top shadow frame.
+ ShadowFrame* top_shadow_frame_;
+ // Frame id of the catch handler or the upcall.
+ size_t handler_frame_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(CatchFinder);
+};
+
+} // namespace art
+#endif // ART_RUNTIME_CATCH_FINDER_H_
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 7a09818..621e350 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -32,6 +32,7 @@
#include "arch/context.h"
#include "base/mutex.h"
+#include "catch_finder.h"
#include "class_linker.h"
#include "class_linker-inl.h"
#include "cutils/atomic.h"
@@ -65,7 +66,6 @@
#include "thread_list.h"
#include "utils.h"
#include "verifier/dex_gc_map.h"
-#include "verifier/method_verifier.h"
#include "vmap_table.h"
#include "well_known_classes.h"
@@ -1740,194 +1740,6 @@ void Thread::DumpThreadOffset(std::ostream& os, uint32_t offset, size_t size_of_
os << offset;
}
-static const bool kDebugExceptionDelivery = false;
-class CatchBlockStackVisitor : public StackVisitor {
- public:
- CatchBlockStackVisitor(Thread* self, const ThrowLocation& throw_location,
- mirror::Throwable* exception, bool is_deoptimization)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : StackVisitor(self, self->GetLongJumpContext()),
- self_(self), exception_(exception), is_deoptimization_(is_deoptimization),
- to_find_(is_deoptimization ? nullptr : exception->GetClass()), throw_location_(throw_location),
- handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_dex_pc_(0),
- native_method_count_(0), clear_exception_(false),
- method_tracing_active_(is_deoptimization ||
- Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()),
- instrumentation_frames_to_pop_(0), top_shadow_frame_(nullptr), prev_shadow_frame_(nullptr) {
- // Exception not in root sets, can't allow GC.
- last_no_assert_suspension_cause_ = self->StartAssertNoThreadSuspension("Finding catch block");
- }
-
- ~CatchBlockStackVisitor() {
- LOG(FATAL) << "UNREACHABLE"; // Expected to take long jump.
- }
-
- bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* method = GetMethod();
- if (method == nullptr) {
- // This is the upcall, we remember the frame and last pc so that we may long jump to them.
- handler_quick_frame_pc_ = GetCurrentQuickFramePc();
- handler_quick_frame_ = GetCurrentQuickFrame();
- return false; // End stack walk.
- } else {
- if (UNLIKELY(method_tracing_active_ &&
- GetQuickInstrumentationExitPc() == GetReturnPc())) {
- // Keep count of the number of unwinds during instrumentation.
- ++instrumentation_frames_to_pop_;
- }
- if (method->IsRuntimeMethod()) {
- // Ignore callee save method.
- DCHECK(method->IsCalleeSaveMethod());
- return true;
- } else if (is_deoptimization_) {
- return HandleDeoptimization(method);
- } else {
- return HandleTryItems(method);
- }
- }
- }
-
- bool HandleTryItems(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- uint32_t dex_pc = DexFile::kDexNoIndex;
- if (method->IsNative()) {
- ++native_method_count_;
- } else {
- dex_pc = GetDexPc();
- }
- if (dex_pc != DexFile::kDexNoIndex) {
- uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc, &clear_exception_);
- if (found_dex_pc != DexFile::kDexNoIndex) {
- handler_dex_pc_ = found_dex_pc;
- handler_quick_frame_pc_ = method->ToNativePc(found_dex_pc);
- handler_quick_frame_ = GetCurrentQuickFrame();
- return false; // End stack walk.
- }
- }
- return true; // Continue stack walk.
- }
-
- bool HandleDeoptimization(mirror::ArtMethod* m)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- MethodHelper mh(m);
- const DexFile::CodeItem* code_item = mh.GetCodeItem();
- CHECK(code_item != nullptr);
- uint16_t num_regs = code_item->registers_size_;
- uint32_t dex_pc = GetDexPc();
- const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
- uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits();
- ShadowFrame* new_frame = ShadowFrame::Create(num_regs, nullptr, m, new_dex_pc);
- SirtRef<mirror::DexCache> dex_cache(self_, mh.GetDexCache());
- SirtRef<mirror::ClassLoader> class_loader(self_, mh.GetClassLoader());
- verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
- &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
- m->GetAccessFlags(), false, true);
- verifier.Verify();
- std::vector<int32_t> kinds = verifier.DescribeVRegs(dex_pc);
- for (uint16_t reg = 0; reg < num_regs; ++reg) {
- VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
- switch (kind) {
- case kUndefined:
- new_frame->SetVReg(reg, 0xEBADDE09);
- break;
- case kConstant:
- new_frame->SetVReg(reg, kinds.at((reg * 2) + 1));
- break;
- case kReferenceVReg:
- new_frame->SetVRegReference(reg,
- reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kind)));
- break;
- default:
- new_frame->SetVReg(reg, GetVReg(m, reg, kind));
- break;
- }
- }
- if (prev_shadow_frame_ != nullptr) {
- prev_shadow_frame_->SetLink(new_frame);
- } else {
- top_shadow_frame_ = new_frame;
- }
- prev_shadow_frame_ = new_frame;
- return true;
- }
-
- void DoLongJump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::ArtMethod* catch_method = *handler_quick_frame_;
- if (catch_method == nullptr) {
- if (kDebugExceptionDelivery) {
- LOG(INFO) << "Handler is upcall";
- }
- } else {
- CHECK(!is_deoptimization_);
- if (kDebugExceptionDelivery) {
- const DexFile& dex_file = *catch_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
- int line_number = dex_file.GetLineNumFromPC(catch_method, handler_dex_pc_);
- LOG(INFO) << "Handler: " << PrettyMethod(catch_method) << " (line: " << line_number << ")";
- }
- }
- if (clear_exception_) {
- // Exception was cleared as part of delivery.
- DCHECK(!self_->IsExceptionPending());
- } else {
- // Put exception back in root set with clear throw location.
- self_->SetException(ThrowLocation(), exception_);
- }
- self_->EndAssertNoThreadSuspension(last_no_assert_suspension_cause_);
- // Do instrumentation events after allowing thread suspension again.
- instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
- if (!is_deoptimization_) {
- // The debugger may suspend this thread and walk its stack. Let's do this before popping
- // instrumentation frames.
- instrumentation->ExceptionCaughtEvent(self_, throw_location_, catch_method, handler_dex_pc_,
- exception_);
- }
- for (size_t i = 0; i < instrumentation_frames_to_pop_; ++i) {
- // We pop the instrumentation stack here so as not to corrupt it during the stack walk.
- if (i != instrumentation_frames_to_pop_ - 1 || self_->GetInstrumentationStack()->front().method_ != catch_method) {
- // Don't pop the instrumentation frame of the catch handler.
- instrumentation->PopMethodForUnwind(self_, is_deoptimization_);
- }
- }
- if (is_deoptimization_) {
- // TODO: proper return value.
- self_->SetDeoptimizationShadowFrame(top_shadow_frame_);
- }
- // Place context back on thread so it will be available when we continue.
- self_->ReleaseLongJumpContext(context_);
- context_->SetSP(reinterpret_cast<uintptr_t>(handler_quick_frame_));
- CHECK_NE(handler_quick_frame_pc_, 0u);
- context_->SetPC(handler_quick_frame_pc_);
- context_->SmashCallerSaves();
- context_->DoLongJump();
- }
-
- private:
- Thread* const self_;
- mirror::Throwable* const exception_;
- const bool is_deoptimization_;
- // The type of the exception catch block to find.
- mirror::Class* const to_find_;
- // Location of the throw.
- const ThrowLocation& throw_location_;
- // Quick frame with found handler or last frame if no handler found.
- mirror::ArtMethod** handler_quick_frame_;
- // PC to branch to for the handler.
- uintptr_t handler_quick_frame_pc_;
- // Associated dex PC.
- uint32_t handler_dex_pc_;
- // Number of native methods passed in crawl (equates to number of SIRTs to pop)
- uint32_t native_method_count_;
- // Should the exception be cleared as the catch block has no move-exception?
- bool clear_exception_;
- // Is method tracing active?
- const bool method_tracing_active_;
- // Support for nesting no thread suspension checks.
- const char* last_no_assert_suspension_cause_;
- // Number of frames to pop in long jump.
- size_t instrumentation_frames_to_pop_;
- ShadowFrame* top_shadow_frame_;
- ShadowFrame* prev_shadow_frame_;
-};
-
void Thread::QuickDeliverException() {
// Get exception from thread.
ThrowLocation throw_location;
@@ -1947,8 +1759,9 @@ void Thread::QuickDeliverException() {
DumpStack(LOG(INFO) << "Deoptimizing: ");
}
}
- CatchBlockStackVisitor catch_finder(this, throw_location, exception, is_deoptimization);
- catch_finder.WalkStack(true);
+ CatchFinder catch_finder(this, throw_location, exception, is_deoptimization);
+ catch_finder.FindCatch();
+ catch_finder.UpdateInstrumentationStack();
catch_finder.DoLongJump();
LOG(FATAL) << "UNREACHABLE";
}