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