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 22 #include "base/macros.h" 23 #include "base/mutex.h" 24 #include "deoptimization_kind.h" 25 #include "stack_reference.h" 26 27 namespace art { 28 29 namespace mirror { 30 class Throwable; 31 } // namespace mirror 32 class ArtMethod; 33 class Context; 34 class OatQuickMethodHeader; 35 class Thread; 36 class ShadowFrame; 37 class StackVisitor; 38 39 // Manages exception delivery for Quick backend. 40 class QuickExceptionHandler { 41 public: 42 QuickExceptionHandler(Thread* self, bool is_deoptimization) 43 REQUIRES_SHARED(Locks::mutator_lock_); 44 ~QuickExceptionHandler()45 NO_RETURN ~QuickExceptionHandler() { 46 LOG(FATAL) << "UNREACHABLE"; // Expected to take long jump. 47 UNREACHABLE(); 48 } 49 50 // Find the catch handler for the given exception. 51 void FindCatch(ObjPtr<mirror::Throwable> exception) REQUIRES_SHARED(Locks::mutator_lock_); 52 53 // Deoptimize the stack to the upcall/some code that's not deoptimizeable. For 54 // every compiled frame, we create a "copy" shadow frame that will be executed 55 // with the interpreter. 56 void DeoptimizeStack() REQUIRES_SHARED(Locks::mutator_lock_); 57 58 // Deoptimize a single frame. It's directly triggered from compiled code. It 59 // has the following properties: 60 // - It deoptimizes a single frame, which can include multiple inlined frames. 61 // - It doesn't have return result or pending exception at the deoptimization point. 62 // - It always deoptimizes, even if IsDeoptimizeable() returns false for the 63 // code, since HDeoptimize always saves the full environment. So it overrides 64 // the result of IsDeoptimizeable(). 65 // - It can be either full-fragment, or partial-fragment deoptimization, depending 66 // on whether that single frame covers full or partial fragment. 67 void DeoptimizeSingleFrame(DeoptimizationKind kind) REQUIRES_SHARED(Locks::mutator_lock_); 68 69 void DeoptimizePartialFragmentFixup(uintptr_t return_pc) 70 REQUIRES_SHARED(Locks::mutator_lock_); 71 72 // Update the instrumentation stack by removing all methods that will be unwound 73 // by the exception being thrown. 74 // Return the return pc of the last frame that's unwound. 75 uintptr_t UpdateInstrumentationStack() REQUIRES_SHARED(Locks::mutator_lock_); 76 77 // Set up environment before delivering an exception to optimized code. 78 void SetCatchEnvironmentForOptimizedHandler(StackVisitor* stack_visitor) 79 REQUIRES_SHARED(Locks::mutator_lock_); 80 81 // Long jump either to a catch handler or to the upcall. 82 NO_RETURN void DoLongJump(bool smash_caller_saves = true) 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_method_; 102 } 103 SetHandlerMethod(ArtMethod * handler_quick_method)104 void SetHandlerMethod(ArtMethod* handler_quick_method) { 105 handler_method_ = handler_quick_method; 106 } 107 GetHandlerDexPc()108 uint32_t GetHandlerDexPc() const { 109 return handler_dex_pc_; 110 } 111 SetHandlerDexPc(uint32_t dex_pc)112 void SetHandlerDexPc(uint32_t dex_pc) { 113 handler_dex_pc_ = dex_pc; 114 } 115 GetClearException()116 bool GetClearException() const { 117 return clear_exception_; 118 } 119 SetClearException(bool clear_exception)120 void SetClearException(bool clear_exception) { 121 clear_exception_ = clear_exception; 122 } 123 SetHandlerFrameDepth(size_t frame_depth)124 void SetHandlerFrameDepth(size_t frame_depth) { 125 handler_frame_depth_ = frame_depth; 126 } 127 IsFullFragmentDone()128 bool IsFullFragmentDone() const { 129 return full_fragment_done_; 130 } 131 SetFullFragmentDone(bool full_fragment_done)132 void SetFullFragmentDone(bool full_fragment_done) { 133 full_fragment_done_ = full_fragment_done; 134 } 135 136 // Walk the stack frames of the given thread, printing out non-runtime methods with their types 137 // of frames. Helps to verify that partial-fragment deopt really works as expected. 138 static void DumpFramesWithType(Thread* self, bool details = false) 139 REQUIRES_SHARED(Locks::mutator_lock_); 140 141 private: 142 Thread* const self_; 143 Context* const context_; 144 // Should we deoptimize the stack? 145 const bool is_deoptimization_; 146 // Is method tracing active? 147 const bool method_tracing_active_; 148 // Quick frame with found handler or last frame if no handler found. 149 ArtMethod** handler_quick_frame_; 150 // PC to branch to for the handler. 151 uintptr_t handler_quick_frame_pc_; 152 // Quick code of the handler. 153 const OatQuickMethodHeader* handler_method_header_; 154 // The value for argument 0. 155 uintptr_t handler_quick_arg0_; 156 // The handler method to report to the debugger. 157 ArtMethod* handler_method_; 158 // The handler's dex PC, zero implies an uncaught exception. 159 uint32_t handler_dex_pc_; 160 // Should the exception be cleared as the catch block has no move-exception? 161 bool clear_exception_; 162 // Frame depth of the catch handler or the upcall. 163 size_t handler_frame_depth_; 164 // Does the handler successfully walk the full fragment (not stopped 165 // by some code that's not deoptimizeable)? Even single-frame deoptimization 166 // can set this to true if the fragment contains only one quick frame. 167 bool full_fragment_done_; 168 169 void PrepareForLongJumpToInvokeStubOrInterpreterBridge() 170 REQUIRES_SHARED(Locks::mutator_lock_); 171 172 DISALLOW_COPY_AND_ASSIGN(QuickExceptionHandler); 173 }; 174 175 } // namespace art 176 #endif // ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_ 177