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