1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_ 18 #define ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_ 19 20 #include <android-base/logging.h> 21 #include <cstdint> 22 #include <memory> 23 #include <optional> 24 25 #include "base/array_ref.h" 26 #include "base/macros.h" 27 #include "base/mutex.h" 28 #include "deoptimization_kind.h" 29 #include "oat/stack_map.h" 30 #include "stack_reference.h" 31 32 namespace art HIDDEN { 33 34 namespace mirror { 35 class Throwable; 36 } // namespace mirror 37 class ArtMethod; 38 class Context; 39 class OatQuickMethodHeader; 40 class Thread; 41 class ShadowFrame; 42 class StackVisitor; 43 44 // Manages exception delivery for Quick backend. 45 class QuickExceptionHandler { 46 public: 47 QuickExceptionHandler(Thread* self, bool is_deoptimization) 48 REQUIRES_SHARED(Locks::mutator_lock_); 49 50 // Find the catch handler for the given exception and call all required Instrumentation methods. 51 // Note this might result in the exception being caught being different from 'exception'. 52 void FindCatch(ObjPtr<mirror::Throwable> exception, bool is_method_exit_exception) 53 REQUIRES_SHARED(Locks::mutator_lock_); 54 55 // Deoptimize the stack to the upcall/some code that's not deoptimizeable. For 56 // every compiled frame, we create a "copy" shadow frame that will be executed 57 // with the interpreter. 58 // skip_method_exit_callbacks specifies if we should skip method exit callbacks for the top frame. 59 // It is set if a deopt is needed after calling method exit callback for ex: if the callback 60 // throws or performs other actions that require a deopt. 61 void DeoptimizeStack(bool skip_method_exit_callbacks) REQUIRES_SHARED(Locks::mutator_lock_); 62 63 // Deoptimize a single frame. It's directly triggered from compiled code. It 64 // has the following properties: 65 // - It deoptimizes a single frame, which can include multiple inlined frames. 66 // - It doesn't have return result or pending exception at the deoptimization point. 67 // - It always deoptimizes, even if IsDeoptimizeable() returns false for the 68 // code, since HDeoptimize always saves the full environment. So it overrides 69 // the result of IsDeoptimizeable(). 70 // - It can be either full-fragment, or partial-fragment deoptimization, depending 71 // on whether that single frame covers full or partial fragment. 72 void DeoptimizeSingleFrame(DeoptimizationKind kind) REQUIRES_SHARED(Locks::mutator_lock_); 73 74 void DeoptimizePartialFragmentFixup() REQUIRES_SHARED(Locks::mutator_lock_); 75 76 // Set up environment before delivering an exception to optimized code. 77 void SetCatchEnvironmentForOptimizedHandler(StackVisitor* stack_visitor) 78 REQUIRES_SHARED(Locks::mutator_lock_); 79 80 // Prepares a long jump context for a jump to either to a catch handler or to the upcall. 81 std::unique_ptr<Context> PrepareLongJump(bool smash_caller_saves = true) 82 REQUIRES_SHARED(Locks::mutator_lock_); 83 SetHandlerQuickFrame(ArtMethod ** handler_quick_frame)84 void SetHandlerQuickFrame(ArtMethod** handler_quick_frame) { 85 handler_quick_frame_ = handler_quick_frame; 86 } 87 SetHandlerQuickFramePc(uintptr_t handler_quick_frame_pc)88 void SetHandlerQuickFramePc(uintptr_t handler_quick_frame_pc) { 89 handler_quick_frame_pc_ = handler_quick_frame_pc; 90 } 91 SetHandlerMethodHeader(const OatQuickMethodHeader * handler_method_header)92 void SetHandlerMethodHeader(const OatQuickMethodHeader* handler_method_header) { 93 handler_method_header_ = handler_method_header; 94 } 95 SetHandlerQuickArg0(uintptr_t handler_quick_arg0)96 void SetHandlerQuickArg0(uintptr_t handler_quick_arg0) { 97 handler_quick_arg0_ = handler_quick_arg0; 98 } 99 GetHandlerMethod()100 ArtMethod* GetHandlerMethod() const { 101 return *handler_quick_frame_; 102 } 103 GetHandlerDexPcList()104 ArrayRef<const uint32_t> GetHandlerDexPcList() const { 105 DCHECK(handler_dex_pc_list_.has_value()); 106 return ArrayRef<const uint32_t>(handler_dex_pc_list_.value()); 107 } 108 SetHandlerDexPcList(std::vector<uint32_t> && handler_dex_pc_list)109 void SetHandlerDexPcList(std::vector<uint32_t>&& handler_dex_pc_list) { 110 handler_dex_pc_list_ = std::move(handler_dex_pc_list); 111 } 112 GetCatchStackMapRow()113 uint32_t GetCatchStackMapRow() const { 114 return catch_stack_map_row_; 115 } 116 SetCatchStackMapRow(uint32_t stack_map_row)117 void SetCatchStackMapRow(uint32_t stack_map_row) { 118 catch_stack_map_row_ = stack_map_row; 119 } 120 GetClearException()121 bool GetClearException() const { 122 return clear_exception_; 123 } 124 SetClearException(bool clear_exception)125 void SetClearException(bool clear_exception) { 126 clear_exception_ = clear_exception; 127 } 128 SetHandlerFrameDepth(size_t frame_depth)129 void SetHandlerFrameDepth(size_t frame_depth) { 130 handler_frame_depth_ = frame_depth; 131 } 132 IsFullFragmentDone()133 bool IsFullFragmentDone() const { 134 return full_fragment_done_; 135 } 136 SetFullFragmentDone(bool full_fragment_done)137 void SetFullFragmentDone(bool full_fragment_done) { 138 full_fragment_done_ = full_fragment_done; 139 } 140 141 // Walk the stack frames of the given thread, printing out non-runtime methods with their types 142 // of frames. Helps to verify that partial-fragment deopt really works as expected. 143 static void DumpFramesWithType(Thread* self, bool details = false) 144 REQUIRES_SHARED(Locks::mutator_lock_); 145 146 private: 147 Thread* const self_; 148 std::unique_ptr<Context> context_; 149 // Should we deoptimize the stack? 150 const bool is_deoptimization_; 151 // Quick frame with found handler or last frame if no handler found. 152 ArtMethod** handler_quick_frame_; 153 // PC to branch to for the handler. 154 uintptr_t handler_quick_frame_pc_; 155 // Quick code of the handler. 156 const OatQuickMethodHeader* handler_method_header_; 157 // The value for argument 0. 158 uintptr_t handler_quick_arg0_; 159 // The handler's dex PC list including the inline dex_pcs. The dex_pcs are ordered from outermost 160 // to innermost. An empty list implies an uncaught exception. 161 // Marked as optional so that we can make sure we destroy it before doing a long jump. 162 std::optional<std::vector<uint32_t>> handler_dex_pc_list_; 163 // StackMap row corresponding to the found catch. 164 uint32_t catch_stack_map_row_; 165 // Should the exception be cleared as the catch block has no move-exception? 166 bool clear_exception_; 167 // Frame depth of the catch handler or the upcall. 168 size_t handler_frame_depth_; 169 // Does the handler successfully walk the full fragment (not stopped 170 // by some code that's not deoptimizeable)? Even single-frame deoptimization 171 // can set this to true if the fragment contains only one quick frame. 172 bool full_fragment_done_; 173 174 void PrepareForLongJumpToInvokeStubOrInterpreterBridge() 175 REQUIRES_SHARED(Locks::mutator_lock_); 176 177 DISALLOW_COPY_AND_ASSIGN(QuickExceptionHandler); 178 }; 179 180 } // namespace art 181 #endif // ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_ 182