diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Android.mk | 2 | ||||
-rw-r--r-- | runtime/catch_block_stack_visitor.cc | 111 | ||||
-rw-r--r-- | runtime/catch_block_stack_visitor.h | 58 | ||||
-rw-r--r-- | runtime/catch_finder.cc | 135 | ||||
-rw-r--r-- | runtime/catch_finder.h | 95 | ||||
-rw-r--r-- | runtime/thread.cc | 195 |
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"; } |