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_quick_frame_; 103 } 104 GetHandlerDexPc()105 uint32_t GetHandlerDexPc() const { 106 return handler_dex_pc_; 107 } 108 SetHandlerDexPc(uint32_t dex_pc)109 void SetHandlerDexPc(uint32_t dex_pc) { 110 handler_dex_pc_ = dex_pc; 111 } 112 GetClearException()113 bool GetClearException() const { 114 return clear_exception_; 115 } 116 SetClearException(bool clear_exception)117 void SetClearException(bool clear_exception) { 118 clear_exception_ = clear_exception; 119 } 120 SetHandlerFrameDepth(size_t frame_depth)121 void SetHandlerFrameDepth(size_t frame_depth) { 122 handler_frame_depth_ = frame_depth; 123 } 124 IsFullFragmentDone()125 bool IsFullFragmentDone() const { 126 return full_fragment_done_; 127 } 128 SetFullFragmentDone(bool full_fragment_done)129 void SetFullFragmentDone(bool full_fragment_done) { 130 full_fragment_done_ = full_fragment_done; 131 } 132 133 // Walk the stack frames of the given thread, printing out non-runtime methods with their types 134 // of frames. Helps to verify that partial-fragment deopt really works as expected. 135 static void DumpFramesWithType(Thread* self, bool details = false) 136 REQUIRES_SHARED(Locks::mutator_lock_); 137 138 private: 139 Thread* const self_; 140 Context* const context_; 141 // Should we deoptimize the stack? 142 const bool is_deoptimization_; 143 // Is method tracing active? 144 const bool method_tracing_active_; 145 // Quick frame with found handler or last frame if no handler found. 146 ArtMethod** handler_quick_frame_; 147 // PC to branch to for the handler. 148 uintptr_t handler_quick_frame_pc_; 149 // Quick code of the handler. 150 const OatQuickMethodHeader* handler_method_header_; 151 // The value for argument 0. 152 uintptr_t handler_quick_arg0_; 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