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