summaryrefslogtreecommitdiffstats
path: root/runtime/catch_block_stack_visitor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/catch_block_stack_visitor.cc')
-rw-r--r--runtime/catch_block_stack_visitor.cc111
1 files changed, 111 insertions, 0 deletions
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