diff options
author | 2022-06-24 11:16:35 +0100 | |
---|---|---|
committer | 2022-10-07 14:48:14 +0000 | |
commit | ab1d559aee05873f70494514922ad4b767c6a709 (patch) | |
tree | 0a0831e8b9fe543b050a56fc03b2e395721cca46 /runtime/quick_exception_handler.cc | |
parent | 8c5e881904c30de5dbc03536ea67bbe2d48088fd (diff) |
Runtime implementation of try catch inlining
The main differences in the runtime are:
1) We now use a list of dex_pcs to find the correct catch handler
instead of a single dex pc
2) We now need to restore vregs of the whole frame, which may be
an inline frame.
Bug: 227283224
Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: I95d2f32088e1d420c83962a1693be18f3b63f8b4
Diffstat (limited to 'runtime/quick_exception_handler.cc')
-rw-r--r-- | runtime/quick_exception_handler.cc | 98 |
1 files changed, 71 insertions, 27 deletions
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 82f50346e2..b9dd3e11b6 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -15,11 +15,14 @@ */ #include "quick_exception_handler.h" + #include <ios> #include <queue> +#include <sstream> #include "arch/context.h" #include "art_method-inl.h" +#include "base/array_ref.h" #include "base/enums.h" #include "base/globals.h" #include "base/logging.h" // For VLOG_IS_ON. @@ -56,7 +59,6 @@ QuickExceptionHandler::QuickExceptionHandler(Thread* self, bool is_deoptimizatio handler_quick_frame_pc_(0), handler_method_header_(nullptr), handler_quick_arg0_(0), - handler_dex_pc_(0), clear_exception_(false), handler_frame_depth_(kInvalidFrameDepth), full_fragment_done_(false) {} @@ -133,10 +135,12 @@ class CatchBlockStackVisitor final : public StackVisitor { uint32_t found_dex_pc = method->FindCatchBlock(to_find, dex_pc, &clear_exception); exception_handler_->SetClearException(clear_exception); if (found_dex_pc != dex::kDexNoIndex) { - exception_handler_->SetHandlerDexPc(found_dex_pc); + exception_handler_->SetHandlerDexPcList(ComputeDexPcList(found_dex_pc)); + uint32_t stack_map_row = -1; exception_handler_->SetHandlerQuickFramePc( - GetCurrentOatQuickMethodHeader()->ToNativeQuickPc( - method, found_dex_pc, /* is_for_catch_handler= */ true)); + GetCurrentOatQuickMethodHeader()->ToNativeQuickPcForCatchHandlers( + method, exception_handler_->GetHandlerDexPcList(), &stack_map_row)); + exception_handler_->SetCatchStackMapRow(stack_map_row); exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame()); exception_handler_->SetHandlerMethodHeader(GetCurrentOatQuickMethodHeader()); return false; // End stack walk. @@ -215,10 +219,24 @@ void QuickExceptionHandler::FindCatch(ObjPtr<mirror::Throwable> exception, } if (GetHandlerMethod() != nullptr) { const DexFile* dex_file = GetHandlerMethod()->GetDexFile(); - int line_number = - annotations::GetLineNumFromPC(dex_file, GetHandlerMethod(), handler_dex_pc_); + DCHECK_GE(handler_dex_pc_list_.size(), 1u); + int line_number = annotations::GetLineNumFromPC( + dex_file, GetHandlerMethod(), handler_dex_pc_list_.front()); + + // We may have an inlined method. If so, we can add some extra logging. + std::stringstream ss; + ArtMethod* maybe_inlined_method = visitor.GetMethod(); + if (maybe_inlined_method != GetHandlerMethod()) { + const DexFile* inlined_dex_file = maybe_inlined_method->GetDexFile(); + DCHECK_GE(handler_dex_pc_list_.size(), 2u); + int inlined_line_number = annotations::GetLineNumFromPC( + inlined_dex_file, maybe_inlined_method, handler_dex_pc_list_.back()); + ss << " which ends up calling inlined method " << maybe_inlined_method->PrettyMethod() + << " (line: " << inlined_line_number << ")"; + } + LOG(INFO) << "Handler: " << GetHandlerMethod()->PrettyMethod() << " (line: " - << line_number << ")"; + << line_number << ")" << ss.str(); } } // Exception was cleared as part of delivery. @@ -283,15 +301,18 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* self_->DumpStack(LOG_STREAM(INFO) << "Setting catch phis: "); } - CodeItemDataAccessor accessor(GetHandlerMethod()->DexInstructionData()); - const size_t number_of_vregs = accessor.RegistersSize(); CodeInfo code_info(handler_method_header_); // Find stack map of the catch block. - StackMap catch_stack_map = code_info.GetCatchStackMapForDexPc(GetHandlerDexPc()); + ArrayRef<const uint32_t> dex_pc_list = GetHandlerDexPcList(); + DCHECK_GE(dex_pc_list.size(), 1u); + StackMap catch_stack_map = code_info.GetStackMapAt(GetCatchStackMapRow()); DCHECK(catch_stack_map.IsValid()); - DexRegisterMap catch_vreg_map = code_info.GetDexRegisterMapOf(catch_stack_map); - DCHECK_EQ(catch_vreg_map.size(), number_of_vregs); + DCHECK_EQ(catch_stack_map.Row(), code_info.GetCatchStackMapForDexPc(dex_pc_list).Row()); + const uint32_t catch_depth = dex_pc_list.size() - 1; + const size_t number_of_registers = stack_visitor->GetNumberOfRegisters(&code_info, catch_depth); + DexRegisterMap catch_vreg_map = + code_info.GetDexRegisterMapOf(catch_stack_map, /* first= */ 0, number_of_registers); if (!catch_vreg_map.HasAnyLiveDexRegisters()) { return; @@ -301,26 +322,47 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* StackMap throw_stack_map = code_info.GetStackMapForNativePcOffset(stack_visitor->GetNativePcOffset()); DCHECK(throw_stack_map.IsValid()); - DexRegisterMap throw_vreg_map = code_info.GetDexRegisterMapOf(throw_stack_map); - DCHECK_EQ(throw_vreg_map.size(), number_of_vregs); + const uint32_t throw_depth = stack_visitor->InlineDepth(); + DCHECK_EQ(throw_depth, catch_depth); + DexRegisterMap throw_vreg_map = + code_info.GetDexRegisterMapOf(throw_stack_map, /* first= */ 0, number_of_registers); + DCHECK_EQ(throw_vreg_map.size(), catch_vreg_map.size()); + + // First vreg that it is part of the catch's environment. + const size_t catch_vreg_start = catch_depth == 0 + ? 0 + : stack_visitor->GetNumberOfRegisters(&code_info, catch_depth - 1); + + // We don't need to copy anything in the parent's environment. + for (size_t vreg = 0; vreg < catch_vreg_start; ++vreg) { + DexRegisterLocation::Kind catch_location_kind = catch_vreg_map[vreg].GetKind(); + DCHECK(catch_location_kind == DexRegisterLocation::Kind::kNone || + catch_location_kind == DexRegisterLocation::Kind::kConstant || + catch_location_kind == DexRegisterLocation::Kind::kInStack) + << "Unexpected catch_location_kind: " << catch_location_kind; + } - // Copy values between them. - for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) { - DexRegisterLocation::Kind catch_location = catch_vreg_map[vreg].GetKind(); - if (catch_location == DexRegisterLocation::Kind::kNone) { + // Copy values between the throw and the catch. + for (size_t vreg = catch_vreg_start; vreg < catch_vreg_map.size(); ++vreg) { + DexRegisterLocation::Kind catch_location_kind = catch_vreg_map[vreg].GetKind(); + if (catch_location_kind == DexRegisterLocation::Kind::kNone) { continue; } - DCHECK(catch_location == DexRegisterLocation::Kind::kInStack); - // Get vreg value from its current location. + // Consistency checks. + DCHECK_EQ(catch_location_kind, DexRegisterLocation::Kind::kInStack); uint32_t vreg_value; VRegKind vreg_kind = ToVRegKind(throw_vreg_map[vreg].GetKind()); - bool get_vreg_success = - stack_visitor->GetVReg(stack_visitor->GetMethod(), - vreg, - vreg_kind, - &vreg_value, - throw_vreg_map[vreg]); + DCHECK_NE(vreg_kind, kReferenceVReg) + << "The fast path in GetVReg doesn't expect a kReferenceVReg."; + + // Get vreg value from its current location. + bool get_vreg_success = stack_visitor->GetVReg(stack_visitor->GetMethod(), + vreg, + vreg_kind, + &vreg_value, + throw_vreg_map[vreg], + /* need_full_register_list= */ true); CHECK(get_vreg_success) << "VReg " << vreg << " was optimized out (" << "method=" << ArtMethod::PrettyMethod(stack_visitor->GetMethod()) << ", dex_pc=" << stack_visitor->GetDexPc() << ", " @@ -701,8 +743,10 @@ void QuickExceptionHandler::DoLongJump(bool smash_caller_saves) { if (!is_deoptimization_ && handler_method_header_ != nullptr && handler_method_header_->IsNterpMethodHeader()) { + // Interpreter procceses one method at a time i.e. not inlining + DCHECK_EQ(handler_dex_pc_list_.size(), 1u) << "We shouldn't have any inlined frames."; context_->SetNterpDexPC(reinterpret_cast<uintptr_t>( - GetHandlerMethod()->DexInstructions().Insns() + handler_dex_pc_)); + GetHandlerMethod()->DexInstructions().Insns() + handler_dex_pc_list_.front())); } context_->DoLongJump(); UNREACHABLE(); |