1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
#define ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
#include <android-base/logging.h>
#include "base/macros.h"
#include "base/mutex.h"
#include "deoptimization_kind.h"
#include "stack_reference.h"
namespace art {
namespace mirror {
class Throwable;
} // namespace mirror
class ArtMethod;
class Context;
class OatQuickMethodHeader;
class Thread;
class ShadowFrame;
class StackVisitor;
// Manages exception delivery for Quick backend.
class QuickExceptionHandler {
public:
QuickExceptionHandler(Thread* self, bool is_deoptimization)
REQUIRES_SHARED(Locks::mutator_lock_);
NO_RETURN ~QuickExceptionHandler() {
LOG(FATAL) << "UNREACHABLE"; // Expected to take long jump.
UNREACHABLE();
}
// Find the catch handler for the given exception and call all required Instrumentation methods.
// Note this might result in the exception being caught being different from 'exception'.
void FindCatch(ObjPtr<mirror::Throwable> exception) REQUIRES_SHARED(Locks::mutator_lock_);
// Deoptimize the stack to the upcall/some code that's not deoptimizeable. For
// every compiled frame, we create a "copy" shadow frame that will be executed
// with the interpreter.
void DeoptimizeStack() REQUIRES_SHARED(Locks::mutator_lock_);
// Deoptimize a single frame. It's directly triggered from compiled code. It
// has the following properties:
// - It deoptimizes a single frame, which can include multiple inlined frames.
// - It doesn't have return result or pending exception at the deoptimization point.
// - It always deoptimizes, even if IsDeoptimizeable() returns false for the
// code, since HDeoptimize always saves the full environment. So it overrides
// the result of IsDeoptimizeable().
// - It can be either full-fragment, or partial-fragment deoptimization, depending
// on whether that single frame covers full or partial fragment.
void DeoptimizeSingleFrame(DeoptimizationKind kind) REQUIRES_SHARED(Locks::mutator_lock_);
void DeoptimizePartialFragmentFixup(uintptr_t return_pc)
REQUIRES_SHARED(Locks::mutator_lock_);
// Update the instrumentation stack by removing all methods that will be unwound
// by the exception being thrown.
// Return the return pc of the last frame that's unwound.
uintptr_t UpdateInstrumentationStack() REQUIRES_SHARED(Locks::mutator_lock_);
// Set up environment before delivering an exception to optimized code.
void SetCatchEnvironmentForOptimizedHandler(StackVisitor* stack_visitor)
REQUIRES_SHARED(Locks::mutator_lock_);
// Long jump either to a catch handler or to the upcall.
NO_RETURN void DoLongJump(bool smash_caller_saves = true) REQUIRES_SHARED(Locks::mutator_lock_);
void SetHandlerQuickFrame(ArtMethod** handler_quick_frame) {
handler_quick_frame_ = handler_quick_frame;
}
void SetHandlerQuickFramePc(uintptr_t handler_quick_frame_pc) {
handler_quick_frame_pc_ = handler_quick_frame_pc;
}
void SetHandlerMethodHeader(const OatQuickMethodHeader* handler_method_header) {
handler_method_header_ = handler_method_header;
}
void SetHandlerQuickArg0(uintptr_t handler_quick_arg0) {
handler_quick_arg0_ = handler_quick_arg0;
}
ArtMethod* GetHandlerMethod() const {
return *handler_quick_frame_;
}
uint32_t GetHandlerDexPc() const {
return handler_dex_pc_;
}
void SetHandlerDexPc(uint32_t dex_pc) {
handler_dex_pc_ = dex_pc;
}
bool GetClearException() const {
return clear_exception_;
}
void SetClearException(bool clear_exception) {
clear_exception_ = clear_exception;
}
void SetHandlerFrameDepth(size_t frame_depth) {
handler_frame_depth_ = frame_depth;
}
bool IsFullFragmentDone() const {
return full_fragment_done_;
}
void SetFullFragmentDone(bool full_fragment_done) {
full_fragment_done_ = full_fragment_done;
}
// Walk the stack frames of the given thread, printing out non-runtime methods with their types
// of frames. Helps to verify that partial-fragment deopt really works as expected.
static void DumpFramesWithType(Thread* self, bool details = false)
REQUIRES_SHARED(Locks::mutator_lock_);
private:
Thread* const self_;
Context* const context_;
// Should we deoptimize the stack?
const bool is_deoptimization_;
// Is method tracing active?
const bool method_tracing_active_;
// Quick frame with found handler or last frame if no handler found.
ArtMethod** handler_quick_frame_;
// PC to branch to for the handler.
uintptr_t handler_quick_frame_pc_;
// Quick code of the handler.
const OatQuickMethodHeader* handler_method_header_;
// The value for argument 0.
uintptr_t handler_quick_arg0_;
// The handler's dex PC, zero implies an uncaught exception.
uint32_t handler_dex_pc_;
// Should the exception be cleared as the catch block has no move-exception?
bool clear_exception_;
// Frame depth of the catch handler or the upcall.
size_t handler_frame_depth_;
// Does the handler successfully walk the full fragment (not stopped
// by some code that's not deoptimizeable)? Even single-frame deoptimization
// can set this to true if the fragment contains only one quick frame.
bool full_fragment_done_;
void PrepareForLongJumpToInvokeStubOrInterpreterBridge()
REQUIRES_SHARED(Locks::mutator_lock_);
DISALLOW_COPY_AND_ASSIGN(QuickExceptionHandler);
};
} // namespace art
#endif // ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
|