1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "quick_exception_handler.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <ios>
20*795d594fSAndroid Build Coastguard Worker #include <queue>
21*795d594fSAndroid Build Coastguard Worker #include <sstream>
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker #include "arch/context.h"
24*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/logging.h" // For VLOG_IS_ON.
28*795d594fSAndroid Build Coastguard Worker #include "base/pointer_size.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/systrace.h"
30*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_types.h"
31*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction.h"
32*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction-inl.h"
33*795d594fSAndroid Build Coastguard Worker #include "entrypoints/entrypoint_utils.h"
34*795d594fSAndroid Build Coastguard Worker #include "entrypoints/quick/quick_entrypoints_enum.h"
35*795d594fSAndroid Build Coastguard Worker #include "entrypoints/runtime_asm_entrypoints.h"
36*795d594fSAndroid Build Coastguard Worker #include "handle_scope-inl.h"
37*795d594fSAndroid Build Coastguard Worker #include "interpreter/shadow_frame-inl.h"
38*795d594fSAndroid Build Coastguard Worker #include "jit/jit.h"
39*795d594fSAndroid Build Coastguard Worker #include "jit/jit_code_cache.h"
40*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
41*795d594fSAndroid Build Coastguard Worker #include "mirror/class_loader.h"
42*795d594fSAndroid Build Coastguard Worker #include "mirror/throwable.h"
43*795d594fSAndroid Build Coastguard Worker #include "nterp_helpers.h"
44*795d594fSAndroid Build Coastguard Worker #include "oat/oat_quick_method_header.h"
45*795d594fSAndroid Build Coastguard Worker #include "oat/stack_map.h"
46*795d594fSAndroid Build Coastguard Worker #include "stack.h"
47*795d594fSAndroid Build Coastguard Worker
48*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker static constexpr bool kDebugExceptionDelivery = false;
51*795d594fSAndroid Build Coastguard Worker static constexpr size_t kInvalidFrameDepth = 0xffffffff;
52*795d594fSAndroid Build Coastguard Worker
QuickExceptionHandler(Thread * self,bool is_deoptimization)53*795d594fSAndroid Build Coastguard Worker QuickExceptionHandler::QuickExceptionHandler(Thread* self, bool is_deoptimization)
54*795d594fSAndroid Build Coastguard Worker : self_(self),
55*795d594fSAndroid Build Coastguard Worker context_(Context::Create()),
56*795d594fSAndroid Build Coastguard Worker is_deoptimization_(is_deoptimization),
57*795d594fSAndroid Build Coastguard Worker handler_quick_frame_(nullptr),
58*795d594fSAndroid Build Coastguard Worker handler_quick_frame_pc_(0),
59*795d594fSAndroid Build Coastguard Worker handler_method_header_(nullptr),
60*795d594fSAndroid Build Coastguard Worker handler_quick_arg0_(0),
61*795d594fSAndroid Build Coastguard Worker clear_exception_(false),
62*795d594fSAndroid Build Coastguard Worker handler_frame_depth_(kInvalidFrameDepth),
63*795d594fSAndroid Build Coastguard Worker full_fragment_done_(false) {}
64*795d594fSAndroid Build Coastguard Worker
65*795d594fSAndroid Build Coastguard Worker // Finds catch handler.
66*795d594fSAndroid Build Coastguard Worker class CatchBlockStackVisitor final : public StackVisitor {
67*795d594fSAndroid Build Coastguard Worker public:
CatchBlockStackVisitor(Thread * self,Context * context,Handle<mirror::Throwable> * exception,QuickExceptionHandler * exception_handler,uint32_t skip_frames,bool skip_top_unwind_callback)68*795d594fSAndroid Build Coastguard Worker CatchBlockStackVisitor(Thread* self,
69*795d594fSAndroid Build Coastguard Worker Context* context,
70*795d594fSAndroid Build Coastguard Worker Handle<mirror::Throwable>* exception,
71*795d594fSAndroid Build Coastguard Worker QuickExceptionHandler* exception_handler,
72*795d594fSAndroid Build Coastguard Worker uint32_t skip_frames,
73*795d594fSAndroid Build Coastguard Worker bool skip_top_unwind_callback)
74*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_)
75*795d594fSAndroid Build Coastguard Worker : StackVisitor(self, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
76*795d594fSAndroid Build Coastguard Worker exception_(exception),
77*795d594fSAndroid Build Coastguard Worker exception_handler_(exception_handler),
78*795d594fSAndroid Build Coastguard Worker skip_frames_(skip_frames),
79*795d594fSAndroid Build Coastguard Worker skip_unwind_callback_(skip_top_unwind_callback) {
80*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(skip_unwind_callback_, skip_frames_ == 0);
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker
VisitFrame()83*795d594fSAndroid Build Coastguard Worker bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
84*795d594fSAndroid Build Coastguard Worker ArtMethod* method = GetMethod();
85*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerFrameDepth(GetFrameDepth());
86*795d594fSAndroid Build Coastguard Worker if (method == nullptr) {
87*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(skip_frames_, 0u)
88*795d594fSAndroid Build Coastguard Worker << "We tried to skip an upcall! We should have returned to the upcall to finish delivery";
89*795d594fSAndroid Build Coastguard Worker // This is the upcall, we remember the frame and last pc so that we may long jump to them.
90*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
91*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
92*795d594fSAndroid Build Coastguard Worker return false; // End stack walk.
93*795d594fSAndroid Build Coastguard Worker }
94*795d594fSAndroid Build Coastguard Worker if (skip_frames_ != 0) {
95*795d594fSAndroid Build Coastguard Worker skip_frames_--;
96*795d594fSAndroid Build Coastguard Worker return true;
97*795d594fSAndroid Build Coastguard Worker }
98*795d594fSAndroid Build Coastguard Worker if (method->IsRuntimeMethod()) {
99*795d594fSAndroid Build Coastguard Worker // Ignore callee save method.
100*795d594fSAndroid Build Coastguard Worker DCHECK(method->IsCalleeSaveMethod());
101*795d594fSAndroid Build Coastguard Worker return true;
102*795d594fSAndroid Build Coastguard Worker }
103*795d594fSAndroid Build Coastguard Worker bool continue_stack_walk = HandleTryItems(method);
104*795d594fSAndroid Build Coastguard Worker // Collect methods for which MethodUnwind callback needs to be invoked. MethodUnwind callback
105*795d594fSAndroid Build Coastguard Worker // can potentially throw, so we want to call these after we find the catch block.
106*795d594fSAndroid Build Coastguard Worker // We stop the stack walk when we find the catch block. If we are ending the stack walk we don't
107*795d594fSAndroid Build Coastguard Worker // have to unwind this method so don't record it.
108*795d594fSAndroid Build Coastguard Worker if (continue_stack_walk && !skip_unwind_callback_) {
109*795d594fSAndroid Build Coastguard Worker // Skip unwind callback is only used when method exit callback has thrown an exception. In
110*795d594fSAndroid Build Coastguard Worker // that case, we should have runtime method (artMethodExitHook) on top of stack and the
111*795d594fSAndroid Build Coastguard Worker // second should be the method for which method exit was called.
112*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(skip_unwind_callback_, GetFrameDepth() == 2);
113*795d594fSAndroid Build Coastguard Worker unwound_methods_.push(method);
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker skip_unwind_callback_ = false;
116*795d594fSAndroid Build Coastguard Worker return continue_stack_walk;
117*795d594fSAndroid Build Coastguard Worker }
118*795d594fSAndroid Build Coastguard Worker
GetUnwoundMethods()119*795d594fSAndroid Build Coastguard Worker std::queue<ArtMethod*>& GetUnwoundMethods() {
120*795d594fSAndroid Build Coastguard Worker return unwound_methods_;
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker
123*795d594fSAndroid Build Coastguard Worker private:
HandleTryItems(ArtMethod * method)124*795d594fSAndroid Build Coastguard Worker bool HandleTryItems(ArtMethod* method)
125*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
126*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = dex::kDexNoIndex;
127*795d594fSAndroid Build Coastguard Worker if (!method->IsNative()) {
128*795d594fSAndroid Build Coastguard Worker dex_pc = GetDexPc();
129*795d594fSAndroid Build Coastguard Worker }
130*795d594fSAndroid Build Coastguard Worker if (dex_pc != dex::kDexNoIndex) {
131*795d594fSAndroid Build Coastguard Worker bool clear_exception = false;
132*795d594fSAndroid Build Coastguard Worker StackHandleScope<1> hs(GetThread());
133*795d594fSAndroid Build Coastguard Worker Handle<mirror::Class> to_find(hs.NewHandle((*exception_)->GetClass()));
134*795d594fSAndroid Build Coastguard Worker uint32_t found_dex_pc = method->FindCatchBlock(to_find, dex_pc, &clear_exception);
135*795d594fSAndroid Build Coastguard Worker exception_handler_->SetClearException(clear_exception);
136*795d594fSAndroid Build Coastguard Worker if (found_dex_pc != dex::kDexNoIndex) {
137*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerDexPcList(ComputeDexPcList(found_dex_pc));
138*795d594fSAndroid Build Coastguard Worker uint32_t stack_map_row = -1;
139*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerQuickFramePc(
140*795d594fSAndroid Build Coastguard Worker GetCurrentOatQuickMethodHeader()->ToNativeQuickPcForCatchHandlers(
141*795d594fSAndroid Build Coastguard Worker method, exception_handler_->GetHandlerDexPcList(), &stack_map_row));
142*795d594fSAndroid Build Coastguard Worker exception_handler_->SetCatchStackMapRow(stack_map_row);
143*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
144*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerMethodHeader(GetCurrentOatQuickMethodHeader());
145*795d594fSAndroid Build Coastguard Worker return false; // End stack walk.
146*795d594fSAndroid Build Coastguard Worker } else if (UNLIKELY(GetThread()->HasDebuggerShadowFrames())) {
147*795d594fSAndroid Build Coastguard Worker // We are going to unwind this frame. Did we prepare a shadow frame for debugging?
148*795d594fSAndroid Build Coastguard Worker size_t frame_id = GetFrameId();
149*795d594fSAndroid Build Coastguard Worker ShadowFrame* frame = GetThread()->FindDebuggerShadowFrame(frame_id);
150*795d594fSAndroid Build Coastguard Worker if (frame != nullptr) {
151*795d594fSAndroid Build Coastguard Worker // We will not execute this shadow frame so we can safely deallocate it.
152*795d594fSAndroid Build Coastguard Worker GetThread()->RemoveDebuggerShadowFrameMapping(frame_id);
153*795d594fSAndroid Build Coastguard Worker ShadowFrame::DeleteDeoptimizedFrame(frame);
154*795d594fSAndroid Build Coastguard Worker }
155*795d594fSAndroid Build Coastguard Worker }
156*795d594fSAndroid Build Coastguard Worker }
157*795d594fSAndroid Build Coastguard Worker return true; // Continue stack walk.
158*795d594fSAndroid Build Coastguard Worker }
159*795d594fSAndroid Build Coastguard Worker
160*795d594fSAndroid Build Coastguard Worker // The exception we're looking for the catch block of.
161*795d594fSAndroid Build Coastguard Worker Handle<mirror::Throwable>* exception_;
162*795d594fSAndroid Build Coastguard Worker // The quick exception handler we're visiting for.
163*795d594fSAndroid Build Coastguard Worker QuickExceptionHandler* const exception_handler_;
164*795d594fSAndroid Build Coastguard Worker // The number of frames to skip searching for catches in.
165*795d594fSAndroid Build Coastguard Worker uint32_t skip_frames_;
166*795d594fSAndroid Build Coastguard Worker // The list of methods we would skip to reach the catch block. We record these to call
167*795d594fSAndroid Build Coastguard Worker // MethodUnwind callbacks.
168*795d594fSAndroid Build Coastguard Worker std::queue<ArtMethod*> unwound_methods_;
169*795d594fSAndroid Build Coastguard Worker // Specifies if the unwind callback should be ignored for method at the top of the stack.
170*795d594fSAndroid Build Coastguard Worker bool skip_unwind_callback_;
171*795d594fSAndroid Build Coastguard Worker
172*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor);
173*795d594fSAndroid Build Coastguard Worker };
174*795d594fSAndroid Build Coastguard Worker
175*795d594fSAndroid Build Coastguard Worker // Finds the appropriate exception catch after calling all method exit instrumentation functions.
176*795d594fSAndroid Build Coastguard Worker // Note that this might change the exception being thrown. If is_method_exit_exception is true
177*795d594fSAndroid Build Coastguard Worker // skip the method unwind call for the method on top of the stack as the exception was thrown by
178*795d594fSAndroid Build Coastguard Worker // method exit callback.
FindCatch(ObjPtr<mirror::Throwable> exception,bool is_method_exit_exception)179*795d594fSAndroid Build Coastguard Worker void QuickExceptionHandler::FindCatch(ObjPtr<mirror::Throwable> exception,
180*795d594fSAndroid Build Coastguard Worker bool is_method_exit_exception) {
181*795d594fSAndroid Build Coastguard Worker DCHECK(!is_deoptimization_);
182*795d594fSAndroid Build Coastguard Worker instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation();
183*795d594fSAndroid Build Coastguard Worker // The number of total frames we have so far popped.
184*795d594fSAndroid Build Coastguard Worker uint32_t already_popped = 0;
185*795d594fSAndroid Build Coastguard Worker bool popped_to_top = true;
186*795d594fSAndroid Build Coastguard Worker StackHandleScope<1> hs(self_);
187*795d594fSAndroid Build Coastguard Worker MutableHandle<mirror::Throwable> exception_ref(hs.NewHandle(exception));
188*795d594fSAndroid Build Coastguard Worker bool skip_top_unwind_callback = is_method_exit_exception;
189*795d594fSAndroid Build Coastguard Worker // Sending the instrumentation events (done by the InstrumentationStackPopper) can cause new
190*795d594fSAndroid Build Coastguard Worker // exceptions to be thrown which will override the current exception. Therefore we need to perform
191*795d594fSAndroid Build Coastguard Worker // the search for a catch in a loop until we have successfully popped all the way to a catch or
192*795d594fSAndroid Build Coastguard Worker // the top of the stack.
193*795d594fSAndroid Build Coastguard Worker do {
194*795d594fSAndroid Build Coastguard Worker if (kDebugExceptionDelivery) {
195*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::String> msg = exception_ref->GetDetailMessage();
196*795d594fSAndroid Build Coastguard Worker std::string str_msg(msg != nullptr ? msg->ToModifiedUtf8() : "");
197*795d594fSAndroid Build Coastguard Worker self_->DumpStack(LOG_STREAM(INFO) << "Delivering exception: " << exception_ref->PrettyTypeOf()
198*795d594fSAndroid Build Coastguard Worker << ": " << str_msg << "\n");
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker
201*795d594fSAndroid Build Coastguard Worker // Walk the stack to find catch handler.
202*795d594fSAndroid Build Coastguard Worker CatchBlockStackVisitor visitor(self_,
203*795d594fSAndroid Build Coastguard Worker context_.get(),
204*795d594fSAndroid Build Coastguard Worker &exception_ref,
205*795d594fSAndroid Build Coastguard Worker this,
206*795d594fSAndroid Build Coastguard Worker /*skip_frames=*/already_popped,
207*795d594fSAndroid Build Coastguard Worker skip_top_unwind_callback);
208*795d594fSAndroid Build Coastguard Worker visitor.WalkStack(true);
209*795d594fSAndroid Build Coastguard Worker skip_top_unwind_callback = false;
210*795d594fSAndroid Build Coastguard Worker
211*795d594fSAndroid Build Coastguard Worker uint32_t new_pop_count = handler_frame_depth_;
212*795d594fSAndroid Build Coastguard Worker DCHECK_GE(new_pop_count, already_popped);
213*795d594fSAndroid Build Coastguard Worker already_popped = new_pop_count;
214*795d594fSAndroid Build Coastguard Worker
215*795d594fSAndroid Build Coastguard Worker if (kDebugExceptionDelivery) {
216*795d594fSAndroid Build Coastguard Worker if (*handler_quick_frame_ == nullptr) {
217*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Handler is upcall";
218*795d594fSAndroid Build Coastguard Worker }
219*795d594fSAndroid Build Coastguard Worker if (GetHandlerMethod() != nullptr) {
220*795d594fSAndroid Build Coastguard Worker const DexFile* dex_file = GetHandlerMethod()->GetDexFile();
221*795d594fSAndroid Build Coastguard Worker DCHECK(handler_dex_pc_list_.has_value());
222*795d594fSAndroid Build Coastguard Worker DCHECK_GE(handler_dex_pc_list_->size(), 1u);
223*795d594fSAndroid Build Coastguard Worker int line_number = annotations::GetLineNumFromPC(
224*795d594fSAndroid Build Coastguard Worker dex_file, GetHandlerMethod(), handler_dex_pc_list_->front());
225*795d594fSAndroid Build Coastguard Worker
226*795d594fSAndroid Build Coastguard Worker // We may have an inlined method. If so, we can add some extra logging.
227*795d594fSAndroid Build Coastguard Worker std::stringstream ss;
228*795d594fSAndroid Build Coastguard Worker ArtMethod* maybe_inlined_method = visitor.GetMethod();
229*795d594fSAndroid Build Coastguard Worker if (maybe_inlined_method != GetHandlerMethod()) {
230*795d594fSAndroid Build Coastguard Worker const DexFile* inlined_dex_file = maybe_inlined_method->GetDexFile();
231*795d594fSAndroid Build Coastguard Worker DCHECK_GE(handler_dex_pc_list_->size(), 2u);
232*795d594fSAndroid Build Coastguard Worker int inlined_line_number = annotations::GetLineNumFromPC(
233*795d594fSAndroid Build Coastguard Worker inlined_dex_file, maybe_inlined_method, handler_dex_pc_list_->back());
234*795d594fSAndroid Build Coastguard Worker ss << " which ends up calling inlined method " << maybe_inlined_method->PrettyMethod()
235*795d594fSAndroid Build Coastguard Worker << " (line: " << inlined_line_number << ")";
236*795d594fSAndroid Build Coastguard Worker }
237*795d594fSAndroid Build Coastguard Worker
238*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Handler: " << GetHandlerMethod()->PrettyMethod() << " (line: "
239*795d594fSAndroid Build Coastguard Worker << line_number << ")" << ss.str();
240*795d594fSAndroid Build Coastguard Worker }
241*795d594fSAndroid Build Coastguard Worker }
242*795d594fSAndroid Build Coastguard Worker // Exception was cleared as part of delivery.
243*795d594fSAndroid Build Coastguard Worker DCHECK(!self_->IsExceptionPending());
244*795d594fSAndroid Build Coastguard Worker // If the handler is in optimized code, we need to set the catch environment.
245*795d594fSAndroid Build Coastguard Worker if (*handler_quick_frame_ != nullptr &&
246*795d594fSAndroid Build Coastguard Worker handler_method_header_ != nullptr &&
247*795d594fSAndroid Build Coastguard Worker handler_method_header_->IsOptimized()) {
248*795d594fSAndroid Build Coastguard Worker SetCatchEnvironmentForOptimizedHandler(&visitor);
249*795d594fSAndroid Build Coastguard Worker }
250*795d594fSAndroid Build Coastguard Worker popped_to_top = instr->ProcessMethodUnwindCallbacks(self_,
251*795d594fSAndroid Build Coastguard Worker visitor.GetUnwoundMethods(),
252*795d594fSAndroid Build Coastguard Worker exception_ref);
253*795d594fSAndroid Build Coastguard Worker } while (!popped_to_top);
254*795d594fSAndroid Build Coastguard Worker
255*795d594fSAndroid Build Coastguard Worker if (!clear_exception_) {
256*795d594fSAndroid Build Coastguard Worker // Put exception back in root set with clear throw location.
257*795d594fSAndroid Build Coastguard Worker self_->SetException(exception_ref.Get());
258*795d594fSAndroid Build Coastguard Worker }
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker
ToVRegKind(DexRegisterLocation::Kind kind)261*795d594fSAndroid Build Coastguard Worker static VRegKind ToVRegKind(DexRegisterLocation::Kind kind) {
262*795d594fSAndroid Build Coastguard Worker // Slightly hacky since we cannot map DexRegisterLocationKind and VRegKind
263*795d594fSAndroid Build Coastguard Worker // one to one. However, StackVisitor::GetVRegFromOptimizedCode only needs to
264*795d594fSAndroid Build Coastguard Worker // distinguish between core/FPU registers and low/high bits on 64-bit.
265*795d594fSAndroid Build Coastguard Worker switch (kind) {
266*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kConstant:
267*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInStack:
268*795d594fSAndroid Build Coastguard Worker // VRegKind is ignored.
269*795d594fSAndroid Build Coastguard Worker return VRegKind::kUndefined;
270*795d594fSAndroid Build Coastguard Worker
271*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInRegister:
272*795d594fSAndroid Build Coastguard Worker // Selects core register. For 64-bit registers, selects low 32 bits.
273*795d594fSAndroid Build Coastguard Worker return VRegKind::kLongLoVReg;
274*795d594fSAndroid Build Coastguard Worker
275*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInRegisterHigh:
276*795d594fSAndroid Build Coastguard Worker // Selects core register. For 64-bit registers, selects high 32 bits.
277*795d594fSAndroid Build Coastguard Worker return VRegKind::kLongHiVReg;
278*795d594fSAndroid Build Coastguard Worker
279*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInFpuRegister:
280*795d594fSAndroid Build Coastguard Worker // Selects FPU register. For 64-bit registers, selects low 32 bits.
281*795d594fSAndroid Build Coastguard Worker return VRegKind::kDoubleLoVReg;
282*795d594fSAndroid Build Coastguard Worker
283*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInFpuRegisterHigh:
284*795d594fSAndroid Build Coastguard Worker // Selects FPU register. For 64-bit registers, selects high 32 bits.
285*795d594fSAndroid Build Coastguard Worker return VRegKind::kDoubleHiVReg;
286*795d594fSAndroid Build Coastguard Worker
287*795d594fSAndroid Build Coastguard Worker default:
288*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected vreg location " << kind;
289*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
290*795d594fSAndroid Build Coastguard Worker }
291*795d594fSAndroid Build Coastguard Worker }
292*795d594fSAndroid Build Coastguard Worker
SetCatchEnvironmentForOptimizedHandler(StackVisitor * stack_visitor)293*795d594fSAndroid Build Coastguard Worker void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* stack_visitor) {
294*795d594fSAndroid Build Coastguard Worker DCHECK(!is_deoptimization_);
295*795d594fSAndroid Build Coastguard Worker DCHECK(*handler_quick_frame_ != nullptr) << "Method should not be called on upcall exceptions";
296*795d594fSAndroid Build Coastguard Worker DCHECK(GetHandlerMethod() != nullptr && handler_method_header_->IsOptimized());
297*795d594fSAndroid Build Coastguard Worker
298*795d594fSAndroid Build Coastguard Worker if (kDebugExceptionDelivery) {
299*795d594fSAndroid Build Coastguard Worker self_->DumpStack(LOG_STREAM(INFO) << "Setting catch phis: ");
300*795d594fSAndroid Build Coastguard Worker }
301*795d594fSAndroid Build Coastguard Worker
302*795d594fSAndroid Build Coastguard Worker CodeInfo code_info(handler_method_header_);
303*795d594fSAndroid Build Coastguard Worker
304*795d594fSAndroid Build Coastguard Worker // Find stack map of the catch block.
305*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint32_t> dex_pc_list = GetHandlerDexPcList();
306*795d594fSAndroid Build Coastguard Worker DCHECK_GE(dex_pc_list.size(), 1u);
307*795d594fSAndroid Build Coastguard Worker StackMap catch_stack_map = code_info.GetStackMapAt(GetCatchStackMapRow());
308*795d594fSAndroid Build Coastguard Worker DCHECK(catch_stack_map.IsValid());
309*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(catch_stack_map.Row(), code_info.GetCatchStackMapForDexPc(dex_pc_list).Row());
310*795d594fSAndroid Build Coastguard Worker const uint32_t catch_depth = dex_pc_list.size() - 1;
311*795d594fSAndroid Build Coastguard Worker const size_t number_of_registers = stack_visitor->GetNumberOfRegisters(&code_info, catch_depth);
312*795d594fSAndroid Build Coastguard Worker DexRegisterMap catch_vreg_map =
313*795d594fSAndroid Build Coastguard Worker code_info.GetDexRegisterMapOf(catch_stack_map, /* first= */ 0, number_of_registers);
314*795d594fSAndroid Build Coastguard Worker
315*795d594fSAndroid Build Coastguard Worker if (!catch_vreg_map.HasAnyLiveDexRegisters()) {
316*795d594fSAndroid Build Coastguard Worker return;
317*795d594fSAndroid Build Coastguard Worker }
318*795d594fSAndroid Build Coastguard Worker
319*795d594fSAndroid Build Coastguard Worker // Find stack map of the throwing instruction.
320*795d594fSAndroid Build Coastguard Worker StackMap throw_stack_map =
321*795d594fSAndroid Build Coastguard Worker code_info.GetStackMapForNativePcOffset(stack_visitor->GetNativePcOffset());
322*795d594fSAndroid Build Coastguard Worker DCHECK(throw_stack_map.IsValid());
323*795d594fSAndroid Build Coastguard Worker const uint32_t throw_depth = stack_visitor->InlineDepth();
324*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(throw_depth, catch_depth);
325*795d594fSAndroid Build Coastguard Worker DexRegisterMap throw_vreg_map =
326*795d594fSAndroid Build Coastguard Worker code_info.GetDexRegisterMapOf(throw_stack_map, /* first= */ 0, number_of_registers);
327*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(throw_vreg_map.size(), catch_vreg_map.size());
328*795d594fSAndroid Build Coastguard Worker
329*795d594fSAndroid Build Coastguard Worker // First vreg that it is part of the catch's environment.
330*795d594fSAndroid Build Coastguard Worker const size_t catch_vreg_start = catch_depth == 0
331*795d594fSAndroid Build Coastguard Worker ? 0
332*795d594fSAndroid Build Coastguard Worker : stack_visitor->GetNumberOfRegisters(&code_info, catch_depth - 1);
333*795d594fSAndroid Build Coastguard Worker
334*795d594fSAndroid Build Coastguard Worker // We don't need to copy anything in the parent's environment.
335*795d594fSAndroid Build Coastguard Worker for (size_t vreg = 0; vreg < catch_vreg_start; ++vreg) {
336*795d594fSAndroid Build Coastguard Worker DexRegisterLocation::Kind catch_location_kind = catch_vreg_map[vreg].GetKind();
337*795d594fSAndroid Build Coastguard Worker DCHECK(catch_location_kind == DexRegisterLocation::Kind::kNone ||
338*795d594fSAndroid Build Coastguard Worker catch_location_kind == DexRegisterLocation::Kind::kConstant ||
339*795d594fSAndroid Build Coastguard Worker catch_location_kind == DexRegisterLocation::Kind::kInStack)
340*795d594fSAndroid Build Coastguard Worker << "Unexpected catch_location_kind: " << catch_location_kind;
341*795d594fSAndroid Build Coastguard Worker }
342*795d594fSAndroid Build Coastguard Worker
343*795d594fSAndroid Build Coastguard Worker // Copy values between the throw and the catch.
344*795d594fSAndroid Build Coastguard Worker for (size_t vreg = catch_vreg_start; vreg < catch_vreg_map.size(); ++vreg) {
345*795d594fSAndroid Build Coastguard Worker DexRegisterLocation::Kind catch_location_kind = catch_vreg_map[vreg].GetKind();
346*795d594fSAndroid Build Coastguard Worker if (catch_location_kind == DexRegisterLocation::Kind::kNone) {
347*795d594fSAndroid Build Coastguard Worker continue;
348*795d594fSAndroid Build Coastguard Worker }
349*795d594fSAndroid Build Coastguard Worker
350*795d594fSAndroid Build Coastguard Worker // Consistency checks.
351*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(catch_location_kind, DexRegisterLocation::Kind::kInStack);
352*795d594fSAndroid Build Coastguard Worker uint32_t vreg_value;
353*795d594fSAndroid Build Coastguard Worker VRegKind vreg_kind = ToVRegKind(throw_vreg_map[vreg].GetKind());
354*795d594fSAndroid Build Coastguard Worker DCHECK_NE(vreg_kind, kReferenceVReg)
355*795d594fSAndroid Build Coastguard Worker << "The fast path in GetVReg doesn't expect a kReferenceVReg.";
356*795d594fSAndroid Build Coastguard Worker
357*795d594fSAndroid Build Coastguard Worker // Get vreg value from its current location.
358*795d594fSAndroid Build Coastguard Worker bool get_vreg_success = stack_visitor->GetVReg(stack_visitor->GetMethod(),
359*795d594fSAndroid Build Coastguard Worker vreg,
360*795d594fSAndroid Build Coastguard Worker vreg_kind,
361*795d594fSAndroid Build Coastguard Worker &vreg_value,
362*795d594fSAndroid Build Coastguard Worker throw_vreg_map[vreg],
363*795d594fSAndroid Build Coastguard Worker /* need_full_register_list= */ true);
364*795d594fSAndroid Build Coastguard Worker CHECK(get_vreg_success) << "VReg " << vreg << " was optimized out ("
365*795d594fSAndroid Build Coastguard Worker << "method=" << ArtMethod::PrettyMethod(stack_visitor->GetMethod())
366*795d594fSAndroid Build Coastguard Worker << ", dex_pc=" << stack_visitor->GetDexPc() << ", "
367*795d594fSAndroid Build Coastguard Worker << "native_pc_offset=" << stack_visitor->GetNativePcOffset() << ")";
368*795d594fSAndroid Build Coastguard Worker
369*795d594fSAndroid Build Coastguard Worker // Copy value to the catch phi's stack slot.
370*795d594fSAndroid Build Coastguard Worker int32_t slot_offset = catch_vreg_map[vreg].GetStackOffsetInBytes();
371*795d594fSAndroid Build Coastguard Worker ArtMethod** frame_top = stack_visitor->GetCurrentQuickFrame();
372*795d594fSAndroid Build Coastguard Worker uint8_t* slot_address = reinterpret_cast<uint8_t*>(frame_top) + slot_offset;
373*795d594fSAndroid Build Coastguard Worker uint32_t* slot_ptr = reinterpret_cast<uint32_t*>(slot_address);
374*795d594fSAndroid Build Coastguard Worker *slot_ptr = vreg_value;
375*795d594fSAndroid Build Coastguard Worker }
376*795d594fSAndroid Build Coastguard Worker }
377*795d594fSAndroid Build Coastguard Worker
378*795d594fSAndroid Build Coastguard Worker // Prepares deoptimization.
379*795d594fSAndroid Build Coastguard Worker class DeoptimizeStackVisitor final : public StackVisitor {
380*795d594fSAndroid Build Coastguard Worker public:
DeoptimizeStackVisitor(Thread * self,Context * context,QuickExceptionHandler * exception_handler,bool single_frame,bool skip_method_exit_callbacks)381*795d594fSAndroid Build Coastguard Worker DeoptimizeStackVisitor(Thread* self,
382*795d594fSAndroid Build Coastguard Worker Context* context,
383*795d594fSAndroid Build Coastguard Worker QuickExceptionHandler* exception_handler,
384*795d594fSAndroid Build Coastguard Worker bool single_frame,
385*795d594fSAndroid Build Coastguard Worker bool skip_method_exit_callbacks) REQUIRES_SHARED(Locks::mutator_lock_)
386*795d594fSAndroid Build Coastguard Worker : StackVisitor(self, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
387*795d594fSAndroid Build Coastguard Worker exception_handler_(exception_handler),
388*795d594fSAndroid Build Coastguard Worker prev_shadow_frame_(nullptr),
389*795d594fSAndroid Build Coastguard Worker bottom_shadow_frame_(nullptr),
390*795d594fSAndroid Build Coastguard Worker stacked_shadow_frame_pushed_(false),
391*795d594fSAndroid Build Coastguard Worker single_frame_deopt_(single_frame),
392*795d594fSAndroid Build Coastguard Worker single_frame_done_(false),
393*795d594fSAndroid Build Coastguard Worker single_frame_deopt_method_(nullptr),
394*795d594fSAndroid Build Coastguard Worker single_frame_deopt_quick_method_header_(nullptr),
395*795d594fSAndroid Build Coastguard Worker callee_method_(nullptr),
396*795d594fSAndroid Build Coastguard Worker skip_method_exit_callbacks_(skip_method_exit_callbacks) {}
397*795d594fSAndroid Build Coastguard Worker
GetSingleFrameDeoptMethod() const398*795d594fSAndroid Build Coastguard Worker ArtMethod* GetSingleFrameDeoptMethod() const {
399*795d594fSAndroid Build Coastguard Worker return single_frame_deopt_method_;
400*795d594fSAndroid Build Coastguard Worker }
401*795d594fSAndroid Build Coastguard Worker
GetSingleFrameDeoptQuickMethodHeader() const402*795d594fSAndroid Build Coastguard Worker const OatQuickMethodHeader* GetSingleFrameDeoptQuickMethodHeader() const {
403*795d594fSAndroid Build Coastguard Worker return single_frame_deopt_quick_method_header_;
404*795d594fSAndroid Build Coastguard Worker }
405*795d594fSAndroid Build Coastguard Worker
GetBottomShadowFrame() const406*795d594fSAndroid Build Coastguard Worker ShadowFrame* GetBottomShadowFrame() const {
407*795d594fSAndroid Build Coastguard Worker return bottom_shadow_frame_;
408*795d594fSAndroid Build Coastguard Worker }
409*795d594fSAndroid Build Coastguard Worker
GetDexPcs() const410*795d594fSAndroid Build Coastguard Worker const std::vector<uint32_t>& GetDexPcs() const {
411*795d594fSAndroid Build Coastguard Worker return dex_pcs_;
412*795d594fSAndroid Build Coastguard Worker }
413*795d594fSAndroid Build Coastguard Worker
FinishStackWalk()414*795d594fSAndroid Build Coastguard Worker void FinishStackWalk() REQUIRES_SHARED(Locks::mutator_lock_) {
415*795d594fSAndroid Build Coastguard Worker // This is the upcall, or the next full frame in single-frame deopt, or the
416*795d594fSAndroid Build Coastguard Worker // code isn't deoptimizeable. We remember the frame and last pc so that we
417*795d594fSAndroid Build Coastguard Worker // may long jump to them.
418*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
419*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
420*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerMethodHeader(GetCurrentOatQuickMethodHeader());
421*795d594fSAndroid Build Coastguard Worker if (!stacked_shadow_frame_pushed_) {
422*795d594fSAndroid Build Coastguard Worker // In case there is no deoptimized shadow frame for this upcall, we still
423*795d594fSAndroid Build Coastguard Worker // need to push a nullptr to the stack since there is always a matching pop after
424*795d594fSAndroid Build Coastguard Worker // the long jump.
425*795d594fSAndroid Build Coastguard Worker GetThread()->PushStackedShadowFrame(nullptr,
426*795d594fSAndroid Build Coastguard Worker StackedShadowFrameType::kDeoptimizationShadowFrame);
427*795d594fSAndroid Build Coastguard Worker stacked_shadow_frame_pushed_ = true;
428*795d594fSAndroid Build Coastguard Worker }
429*795d594fSAndroid Build Coastguard Worker if (GetMethod() == nullptr) {
430*795d594fSAndroid Build Coastguard Worker exception_handler_->SetFullFragmentDone(true);
431*795d594fSAndroid Build Coastguard Worker } else {
432*795d594fSAndroid Build Coastguard Worker CHECK(callee_method_ != nullptr) << GetMethod()->PrettyMethod(false);
433*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerQuickArg0(reinterpret_cast<uintptr_t>(callee_method_));
434*795d594fSAndroid Build Coastguard Worker }
435*795d594fSAndroid Build Coastguard Worker }
436*795d594fSAndroid Build Coastguard Worker
VisitFrame()437*795d594fSAndroid Build Coastguard Worker bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
438*795d594fSAndroid Build Coastguard Worker exception_handler_->SetHandlerFrameDepth(GetFrameDepth());
439*795d594fSAndroid Build Coastguard Worker ArtMethod* method = GetMethod();
440*795d594fSAndroid Build Coastguard Worker VLOG(deopt) << "Deoptimizing stack: depth: " << GetFrameDepth()
441*795d594fSAndroid Build Coastguard Worker << " at method " << ArtMethod::PrettyMethod(method);
442*795d594fSAndroid Build Coastguard Worker
443*795d594fSAndroid Build Coastguard Worker if (method == nullptr || single_frame_done_) {
444*795d594fSAndroid Build Coastguard Worker FinishStackWalk();
445*795d594fSAndroid Build Coastguard Worker return false; // End stack walk.
446*795d594fSAndroid Build Coastguard Worker }
447*795d594fSAndroid Build Coastguard Worker
448*795d594fSAndroid Build Coastguard Worker // Update if method exit event needs to be reported. We should report exit event only if we
449*795d594fSAndroid Build Coastguard Worker // have reported an entry event. So tell interpreter if/ an entry event was reported.
450*795d594fSAndroid Build Coastguard Worker bool supports_exit_events = Runtime::Current()->GetInstrumentation()->MethodSupportsExitEvents(
451*795d594fSAndroid Build Coastguard Worker method, GetCurrentOatQuickMethodHeader());
452*795d594fSAndroid Build Coastguard Worker
453*795d594fSAndroid Build Coastguard Worker if (method->IsRuntimeMethod()) {
454*795d594fSAndroid Build Coastguard Worker // Ignore callee save method.
455*795d594fSAndroid Build Coastguard Worker DCHECK(method->IsCalleeSaveMethod());
456*795d594fSAndroid Build Coastguard Worker return true;
457*795d594fSAndroid Build Coastguard Worker } else if (method->IsNative()) {
458*795d594fSAndroid Build Coastguard Worker // If we return from JNI with a pending exception and want to deoptimize, we need to skip
459*795d594fSAndroid Build Coastguard Worker // the native method. The top method is a runtime method, the native method comes next.
460*795d594fSAndroid Build Coastguard Worker // We also deoptimize due to method instrumentation reasons from method exit callbacks.
461*795d594fSAndroid Build Coastguard Worker // In these cases native method is at the top of stack.
462*795d594fSAndroid Build Coastguard Worker CHECK((GetFrameDepth() == 1U) || (GetFrameDepth() == 0U));
463*795d594fSAndroid Build Coastguard Worker // We see a native frame when:
464*795d594fSAndroid Build Coastguard Worker // 1. returning from JNI with a pending exception
465*795d594fSAndroid Build Coastguard Worker // 2. deopting from method exit callbacks (with or without a pending exception).
466*795d594fSAndroid Build Coastguard Worker // skip_method_exit_callbacks_ is set in this case
467*795d594fSAndroid Build Coastguard Worker // 3. handling async exception on suspend points for fast native methods.
468*795d594fSAndroid Build Coastguard Worker // We only need to call method unwind event in the first case.
469*795d594fSAndroid Build Coastguard Worker if (supports_exit_events &&
470*795d594fSAndroid Build Coastguard Worker !skip_method_exit_callbacks_ &&
471*795d594fSAndroid Build Coastguard Worker GetThread()->IsExceptionPending()) {
472*795d594fSAndroid Build Coastguard Worker // An exception has occurred in a native method and we are deoptimizing past the native
473*795d594fSAndroid Build Coastguard Worker // method. So report method unwind event here.
474*795d594fSAndroid Build Coastguard Worker Runtime::Current()->GetInstrumentation()->MethodUnwindEvent(
475*795d594fSAndroid Build Coastguard Worker GetThread(), method, dex::kDexNoIndex);
476*795d594fSAndroid Build Coastguard Worker }
477*795d594fSAndroid Build Coastguard Worker callee_method_ = method;
478*795d594fSAndroid Build Coastguard Worker return true;
479*795d594fSAndroid Build Coastguard Worker } else if (!single_frame_deopt_ &&
480*795d594fSAndroid Build Coastguard Worker !Runtime::Current()->IsAsyncDeoptimizeable(GetOuterMethod(),
481*795d594fSAndroid Build Coastguard Worker GetCurrentQuickFramePc())) {
482*795d594fSAndroid Build Coastguard Worker // We hit some code that's not deoptimizeable. However, Single-frame deoptimization triggered
483*795d594fSAndroid Build Coastguard Worker // from compiled code is always allowed since HDeoptimize always saves the full environment.
484*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Got request to deoptimize un-deoptimizable method "
485*795d594fSAndroid Build Coastguard Worker << method->PrettyMethod();
486*795d594fSAndroid Build Coastguard Worker FinishStackWalk();
487*795d594fSAndroid Build Coastguard Worker return false; // End stack walk.
488*795d594fSAndroid Build Coastguard Worker } else {
489*795d594fSAndroid Build Coastguard Worker // Check if a shadow frame already exists for debugger's set-local-value purpose.
490*795d594fSAndroid Build Coastguard Worker const size_t frame_id = GetFrameId();
491*795d594fSAndroid Build Coastguard Worker ShadowFrame* new_frame = GetThread()->FindDebuggerShadowFrame(frame_id);
492*795d594fSAndroid Build Coastguard Worker const bool* updated_vregs;
493*795d594fSAndroid Build Coastguard Worker CodeItemDataAccessor accessor(method->DexInstructionData());
494*795d594fSAndroid Build Coastguard Worker const size_t num_regs = accessor.RegistersSize();
495*795d594fSAndroid Build Coastguard Worker if (new_frame == nullptr) {
496*795d594fSAndroid Build Coastguard Worker new_frame = ShadowFrame::CreateDeoptimizedFrame(num_regs, method, GetDexPc());
497*795d594fSAndroid Build Coastguard Worker updated_vregs = nullptr;
498*795d594fSAndroid Build Coastguard Worker } else {
499*795d594fSAndroid Build Coastguard Worker updated_vregs = GetThread()->GetUpdatedVRegFlags(frame_id);
500*795d594fSAndroid Build Coastguard Worker DCHECK(updated_vregs != nullptr);
501*795d594fSAndroid Build Coastguard Worker }
502*795d594fSAndroid Build Coastguard Worker if (GetCurrentOatQuickMethodHeader()->IsNterpMethodHeader()) {
503*795d594fSAndroid Build Coastguard Worker HandleNterpDeoptimization(method, new_frame, updated_vregs);
504*795d594fSAndroid Build Coastguard Worker } else {
505*795d594fSAndroid Build Coastguard Worker HandleOptimizingDeoptimization(method, new_frame, updated_vregs);
506*795d594fSAndroid Build Coastguard Worker }
507*795d594fSAndroid Build Coastguard Worker new_frame->SetSkipMethodExitEvents(!supports_exit_events);
508*795d594fSAndroid Build Coastguard Worker // If we are deoptimizing after method exit callback we shouldn't call the method exit
509*795d594fSAndroid Build Coastguard Worker // callbacks again for the top frame. We may have to deopt after the callback if the callback
510*795d594fSAndroid Build Coastguard Worker // either throws or performs other actions that require a deopt.
511*795d594fSAndroid Build Coastguard Worker // We only need to skip for the top frame and the rest of the frames should still run the
512*795d594fSAndroid Build Coastguard Worker // callbacks. So only do this check for the top frame.
513*795d594fSAndroid Build Coastguard Worker if (GetFrameDepth() == 0U && skip_method_exit_callbacks_) {
514*795d594fSAndroid Build Coastguard Worker new_frame->SetSkipMethodExitEvents(true);
515*795d594fSAndroid Build Coastguard Worker // This exception was raised by method exit callbacks and we shouldn't report it to
516*795d594fSAndroid Build Coastguard Worker // listeners for these exceptions.
517*795d594fSAndroid Build Coastguard Worker if (GetThread()->IsExceptionPending()) {
518*795d594fSAndroid Build Coastguard Worker new_frame->SetSkipNextExceptionEvent(true);
519*795d594fSAndroid Build Coastguard Worker }
520*795d594fSAndroid Build Coastguard Worker }
521*795d594fSAndroid Build Coastguard Worker if (updated_vregs != nullptr) {
522*795d594fSAndroid Build Coastguard Worker // Calling Thread::RemoveDebuggerShadowFrameMapping will also delete the updated_vregs
523*795d594fSAndroid Build Coastguard Worker // array so this must come after we processed the frame.
524*795d594fSAndroid Build Coastguard Worker GetThread()->RemoveDebuggerShadowFrameMapping(frame_id);
525*795d594fSAndroid Build Coastguard Worker DCHECK(GetThread()->FindDebuggerShadowFrame(frame_id) == nullptr);
526*795d594fSAndroid Build Coastguard Worker }
527*795d594fSAndroid Build Coastguard Worker if (prev_shadow_frame_ != nullptr) {
528*795d594fSAndroid Build Coastguard Worker prev_shadow_frame_->SetLink(new_frame);
529*795d594fSAndroid Build Coastguard Worker } else {
530*795d594fSAndroid Build Coastguard Worker // Will be popped after the long jump after DeoptimizeStack(),
531*795d594fSAndroid Build Coastguard Worker // right before interpreter::EnterInterpreterFromDeoptimize().
532*795d594fSAndroid Build Coastguard Worker stacked_shadow_frame_pushed_ = true;
533*795d594fSAndroid Build Coastguard Worker bottom_shadow_frame_ = new_frame;
534*795d594fSAndroid Build Coastguard Worker GetThread()->PushStackedShadowFrame(
535*795d594fSAndroid Build Coastguard Worker new_frame, StackedShadowFrameType::kDeoptimizationShadowFrame);
536*795d594fSAndroid Build Coastguard Worker }
537*795d594fSAndroid Build Coastguard Worker prev_shadow_frame_ = new_frame;
538*795d594fSAndroid Build Coastguard Worker
539*795d594fSAndroid Build Coastguard Worker if (single_frame_deopt_) {
540*795d594fSAndroid Build Coastguard Worker dex_pcs_.push_back(GetDexPc());
541*795d594fSAndroid Build Coastguard Worker if (!IsInInlinedFrame()) {
542*795d594fSAndroid Build Coastguard Worker // Single-frame deopt ends at the first non-inlined frame and needs to store that method.
543*795d594fSAndroid Build Coastguard Worker single_frame_done_ = true;
544*795d594fSAndroid Build Coastguard Worker single_frame_deopt_method_ = method;
545*795d594fSAndroid Build Coastguard Worker single_frame_deopt_quick_method_header_ = GetCurrentOatQuickMethodHeader();
546*795d594fSAndroid Build Coastguard Worker }
547*795d594fSAndroid Build Coastguard Worker }
548*795d594fSAndroid Build Coastguard Worker callee_method_ = method;
549*795d594fSAndroid Build Coastguard Worker return true;
550*795d594fSAndroid Build Coastguard Worker }
551*795d594fSAndroid Build Coastguard Worker }
552*795d594fSAndroid Build Coastguard Worker
553*795d594fSAndroid Build Coastguard Worker private:
HandleNterpDeoptimization(ArtMethod * m,ShadowFrame * new_frame,const bool * updated_vregs)554*795d594fSAndroid Build Coastguard Worker void HandleNterpDeoptimization(ArtMethod* m,
555*795d594fSAndroid Build Coastguard Worker ShadowFrame* new_frame,
556*795d594fSAndroid Build Coastguard Worker const bool* updated_vregs)
557*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
558*795d594fSAndroid Build Coastguard Worker ArtMethod** cur_quick_frame = GetCurrentQuickFrame();
559*795d594fSAndroid Build Coastguard Worker StackReference<mirror::Object>* vreg_ref_base =
560*795d594fSAndroid Build Coastguard Worker reinterpret_cast<StackReference<mirror::Object>*>(NterpGetReferenceArray(cur_quick_frame));
561*795d594fSAndroid Build Coastguard Worker int32_t* vreg_int_base =
562*795d594fSAndroid Build Coastguard Worker reinterpret_cast<int32_t*>(NterpGetRegistersArray(cur_quick_frame));
563*795d594fSAndroid Build Coastguard Worker CodeItemDataAccessor accessor(m->DexInstructionData());
564*795d594fSAndroid Build Coastguard Worker const uint16_t num_regs = accessor.RegistersSize();
565*795d594fSAndroid Build Coastguard Worker // An nterp frame has two arrays: a dex register array and a reference array
566*795d594fSAndroid Build Coastguard Worker // that shadows the dex register array but only containing references
567*795d594fSAndroid Build Coastguard Worker // (non-reference dex registers have nulls). See nterp_helpers.cc.
568*795d594fSAndroid Build Coastguard Worker for (size_t reg = 0; reg < num_regs; ++reg) {
569*795d594fSAndroid Build Coastguard Worker if (updated_vregs != nullptr && updated_vregs[reg]) {
570*795d594fSAndroid Build Coastguard Worker // Keep the value set by debugger.
571*795d594fSAndroid Build Coastguard Worker continue;
572*795d594fSAndroid Build Coastguard Worker }
573*795d594fSAndroid Build Coastguard Worker StackReference<mirror::Object>* ref_addr = vreg_ref_base + reg;
574*795d594fSAndroid Build Coastguard Worker mirror::Object* ref = ref_addr->AsMirrorPtr();
575*795d594fSAndroid Build Coastguard Worker if (ref != nullptr) {
576*795d594fSAndroid Build Coastguard Worker new_frame->SetVRegReference(reg, ref);
577*795d594fSAndroid Build Coastguard Worker } else {
578*795d594fSAndroid Build Coastguard Worker new_frame->SetVReg(reg, vreg_int_base[reg]);
579*795d594fSAndroid Build Coastguard Worker }
580*795d594fSAndroid Build Coastguard Worker }
581*795d594fSAndroid Build Coastguard Worker }
582*795d594fSAndroid Build Coastguard Worker
HandleOptimizingDeoptimization(ArtMethod * m,ShadowFrame * new_frame,const bool * updated_vregs)583*795d594fSAndroid Build Coastguard Worker void HandleOptimizingDeoptimization(ArtMethod* m,
584*795d594fSAndroid Build Coastguard Worker ShadowFrame* new_frame,
585*795d594fSAndroid Build Coastguard Worker const bool* updated_vregs)
586*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(Locks::mutator_lock_) {
587*795d594fSAndroid Build Coastguard Worker const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
588*795d594fSAndroid Build Coastguard Worker CodeInfo code_info(method_header);
589*795d594fSAndroid Build Coastguard Worker uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc());
590*795d594fSAndroid Build Coastguard Worker StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
591*795d594fSAndroid Build Coastguard Worker CodeItemDataAccessor accessor(m->DexInstructionData());
592*795d594fSAndroid Build Coastguard Worker const size_t number_of_vregs = accessor.RegistersSize();
593*795d594fSAndroid Build Coastguard Worker uint32_t register_mask = code_info.GetRegisterMaskOf(stack_map);
594*795d594fSAndroid Build Coastguard Worker BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map);
595*795d594fSAndroid Build Coastguard Worker DexRegisterMap vreg_map = IsInInlinedFrame()
596*795d594fSAndroid Build Coastguard Worker ? code_info.GetInlineDexRegisterMapOf(stack_map, GetCurrentInlinedFrame())
597*795d594fSAndroid Build Coastguard Worker : code_info.GetDexRegisterMapOf(stack_map);
598*795d594fSAndroid Build Coastguard Worker
599*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild || UNLIKELY(Runtime::Current()->IsJavaDebuggable())) {
600*795d594fSAndroid Build Coastguard Worker CHECK_EQ(vreg_map.size(), number_of_vregs) << *Thread::Current()
601*795d594fSAndroid Build Coastguard Worker << "Deopting: " << m->PrettyMethod()
602*795d594fSAndroid Build Coastguard Worker << " inlined? "
603*795d594fSAndroid Build Coastguard Worker << std::boolalpha << IsInInlinedFrame();
604*795d594fSAndroid Build Coastguard Worker }
605*795d594fSAndroid Build Coastguard Worker if (vreg_map.empty()) {
606*795d594fSAndroid Build Coastguard Worker return;
607*795d594fSAndroid Build Coastguard Worker }
608*795d594fSAndroid Build Coastguard Worker
609*795d594fSAndroid Build Coastguard Worker for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) {
610*795d594fSAndroid Build Coastguard Worker if (updated_vregs != nullptr && updated_vregs[vreg]) {
611*795d594fSAndroid Build Coastguard Worker // Keep the value set by debugger.
612*795d594fSAndroid Build Coastguard Worker continue;
613*795d594fSAndroid Build Coastguard Worker }
614*795d594fSAndroid Build Coastguard Worker
615*795d594fSAndroid Build Coastguard Worker DexRegisterLocation::Kind location = vreg_map[vreg].GetKind();
616*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kDeadValue = 0xEBADDE09;
617*795d594fSAndroid Build Coastguard Worker uint32_t value = kDeadValue;
618*795d594fSAndroid Build Coastguard Worker bool is_reference = false;
619*795d594fSAndroid Build Coastguard Worker
620*795d594fSAndroid Build Coastguard Worker switch (location) {
621*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInStack: {
622*795d594fSAndroid Build Coastguard Worker const int32_t offset = vreg_map[vreg].GetStackOffsetInBytes();
623*795d594fSAndroid Build Coastguard Worker const uint8_t* addr = reinterpret_cast<const uint8_t*>(GetCurrentQuickFrame()) + offset;
624*795d594fSAndroid Build Coastguard Worker value = *reinterpret_cast<const uint32_t*>(addr);
625*795d594fSAndroid Build Coastguard Worker uint32_t bit = (offset >> 2);
626*795d594fSAndroid Build Coastguard Worker if (bit < stack_mask.size_in_bits() && stack_mask.LoadBit(bit)) {
627*795d594fSAndroid Build Coastguard Worker is_reference = true;
628*795d594fSAndroid Build Coastguard Worker }
629*795d594fSAndroid Build Coastguard Worker break;
630*795d594fSAndroid Build Coastguard Worker }
631*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInRegister:
632*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInRegisterHigh:
633*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInFpuRegister:
634*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kInFpuRegisterHigh: {
635*795d594fSAndroid Build Coastguard Worker uint32_t reg = vreg_map[vreg].GetMachineRegister();
636*795d594fSAndroid Build Coastguard Worker bool result = GetRegisterIfAccessible(reg, location, &value);
637*795d594fSAndroid Build Coastguard Worker CHECK(result);
638*795d594fSAndroid Build Coastguard Worker if (location == DexRegisterLocation::Kind::kInRegister) {
639*795d594fSAndroid Build Coastguard Worker if (((1u << reg) & register_mask) != 0) {
640*795d594fSAndroid Build Coastguard Worker is_reference = true;
641*795d594fSAndroid Build Coastguard Worker }
642*795d594fSAndroid Build Coastguard Worker }
643*795d594fSAndroid Build Coastguard Worker break;
644*795d594fSAndroid Build Coastguard Worker }
645*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kConstant: {
646*795d594fSAndroid Build Coastguard Worker value = vreg_map[vreg].GetConstant();
647*795d594fSAndroid Build Coastguard Worker if (value == 0) {
648*795d594fSAndroid Build Coastguard Worker // Make it a reference for extra safety.
649*795d594fSAndroid Build Coastguard Worker is_reference = true;
650*795d594fSAndroid Build Coastguard Worker }
651*795d594fSAndroid Build Coastguard Worker break;
652*795d594fSAndroid Build Coastguard Worker }
653*795d594fSAndroid Build Coastguard Worker case DexRegisterLocation::Kind::kNone: {
654*795d594fSAndroid Build Coastguard Worker break;
655*795d594fSAndroid Build Coastguard Worker }
656*795d594fSAndroid Build Coastguard Worker default: {
657*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected location kind " << vreg_map[vreg].GetKind();
658*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
659*795d594fSAndroid Build Coastguard Worker }
660*795d594fSAndroid Build Coastguard Worker }
661*795d594fSAndroid Build Coastguard Worker if (is_reference) {
662*795d594fSAndroid Build Coastguard Worker new_frame->SetVRegReference(vreg, reinterpret_cast<mirror::Object*>(value));
663*795d594fSAndroid Build Coastguard Worker } else {
664*795d594fSAndroid Build Coastguard Worker new_frame->SetVReg(vreg, value);
665*795d594fSAndroid Build Coastguard Worker }
666*795d594fSAndroid Build Coastguard Worker }
667*795d594fSAndroid Build Coastguard Worker }
668*795d594fSAndroid Build Coastguard Worker
GetVRegKind(uint16_t reg,const std::vector<int32_t> & kinds)669*795d594fSAndroid Build Coastguard Worker static VRegKind GetVRegKind(uint16_t reg, const std::vector<int32_t>& kinds) {
670*795d594fSAndroid Build Coastguard Worker return static_cast<VRegKind>(kinds[reg * 2]);
671*795d594fSAndroid Build Coastguard Worker }
672*795d594fSAndroid Build Coastguard Worker
673*795d594fSAndroid Build Coastguard Worker QuickExceptionHandler* const exception_handler_;
674*795d594fSAndroid Build Coastguard Worker ShadowFrame* prev_shadow_frame_;
675*795d594fSAndroid Build Coastguard Worker ShadowFrame* bottom_shadow_frame_;
676*795d594fSAndroid Build Coastguard Worker bool stacked_shadow_frame_pushed_;
677*795d594fSAndroid Build Coastguard Worker const bool single_frame_deopt_;
678*795d594fSAndroid Build Coastguard Worker bool single_frame_done_;
679*795d594fSAndroid Build Coastguard Worker ArtMethod* single_frame_deopt_method_;
680*795d594fSAndroid Build Coastguard Worker const OatQuickMethodHeader* single_frame_deopt_quick_method_header_;
681*795d594fSAndroid Build Coastguard Worker ArtMethod* callee_method_;
682*795d594fSAndroid Build Coastguard Worker // This specifies if method exit callbacks should be skipped for the top frame. We may request
683*795d594fSAndroid Build Coastguard Worker // a deopt after running method exit callbacks if the callback throws or requests events that
684*795d594fSAndroid Build Coastguard Worker // need a deopt.
685*795d594fSAndroid Build Coastguard Worker bool skip_method_exit_callbacks_;
686*795d594fSAndroid Build Coastguard Worker std::vector<uint32_t> dex_pcs_;
687*795d594fSAndroid Build Coastguard Worker
688*795d594fSAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(DeoptimizeStackVisitor);
689*795d594fSAndroid Build Coastguard Worker };
690*795d594fSAndroid Build Coastguard Worker
PrepareForLongJumpToInvokeStubOrInterpreterBridge()691*795d594fSAndroid Build Coastguard Worker void QuickExceptionHandler::PrepareForLongJumpToInvokeStubOrInterpreterBridge() {
692*795d594fSAndroid Build Coastguard Worker if (full_fragment_done_) {
693*795d594fSAndroid Build Coastguard Worker // Restore deoptimization exception. When returning from the invoke stub,
694*795d594fSAndroid Build Coastguard Worker // ArtMethod::Invoke() will see the special exception to know deoptimization
695*795d594fSAndroid Build Coastguard Worker // is needed.
696*795d594fSAndroid Build Coastguard Worker self_->SetException(Thread::GetDeoptimizationException());
697*795d594fSAndroid Build Coastguard Worker } else {
698*795d594fSAndroid Build Coastguard Worker // PC needs to be of the quick-to-interpreter bridge.
699*795d594fSAndroid Build Coastguard Worker int32_t offset;
700*795d594fSAndroid Build Coastguard Worker offset = GetThreadOffset<kRuntimePointerSize>(kQuickQuickToInterpreterBridge).Int32Value();
701*795d594fSAndroid Build Coastguard Worker handler_quick_frame_pc_ = *reinterpret_cast<uintptr_t*>(
702*795d594fSAndroid Build Coastguard Worker reinterpret_cast<uint8_t*>(self_) + offset);
703*795d594fSAndroid Build Coastguard Worker }
704*795d594fSAndroid Build Coastguard Worker }
705*795d594fSAndroid Build Coastguard Worker
DeoptimizeStack(bool skip_method_exit_callbacks)706*795d594fSAndroid Build Coastguard Worker void QuickExceptionHandler::DeoptimizeStack(bool skip_method_exit_callbacks) {
707*795d594fSAndroid Build Coastguard Worker DCHECK(is_deoptimization_);
708*795d594fSAndroid Build Coastguard Worker if (kDebugExceptionDelivery) {
709*795d594fSAndroid Build Coastguard Worker self_->DumpStack(LOG_STREAM(INFO) << "Deoptimizing: ");
710*795d594fSAndroid Build Coastguard Worker }
711*795d594fSAndroid Build Coastguard Worker
712*795d594fSAndroid Build Coastguard Worker DeoptimizeStackVisitor visitor(self_, context_.get(), this, false, skip_method_exit_callbacks);
713*795d594fSAndroid Build Coastguard Worker visitor.WalkStack(true);
714*795d594fSAndroid Build Coastguard Worker PrepareForLongJumpToInvokeStubOrInterpreterBridge();
715*795d594fSAndroid Build Coastguard Worker }
716*795d594fSAndroid Build Coastguard Worker
DeoptimizeSingleFrame(DeoptimizationKind kind)717*795d594fSAndroid Build Coastguard Worker void QuickExceptionHandler::DeoptimizeSingleFrame(DeoptimizationKind kind) {
718*795d594fSAndroid Build Coastguard Worker DCHECK(is_deoptimization_);
719*795d594fSAndroid Build Coastguard Worker
720*795d594fSAndroid Build Coastguard Worker // This deopt is requested while still executing the method. We haven't run method exit callbacks
721*795d594fSAndroid Build Coastguard Worker // yet, so don't skip them.
722*795d594fSAndroid Build Coastguard Worker DeoptimizeStackVisitor visitor(
723*795d594fSAndroid Build Coastguard Worker self_, context_.get(), this, true, /* skip_method_exit_callbacks= */ false);
724*795d594fSAndroid Build Coastguard Worker visitor.WalkStack(true);
725*795d594fSAndroid Build Coastguard Worker
726*795d594fSAndroid Build Coastguard Worker // Compiled code made an explicit deoptimization.
727*795d594fSAndroid Build Coastguard Worker ArtMethod* deopt_method = visitor.GetSingleFrameDeoptMethod();
728*795d594fSAndroid Build Coastguard Worker SCOPED_TRACE << "Deoptimizing "
729*795d594fSAndroid Build Coastguard Worker << deopt_method->PrettyMethod()
730*795d594fSAndroid Build Coastguard Worker << ": " << GetDeoptimizationKindName(kind);
731*795d594fSAndroid Build Coastguard Worker
732*795d594fSAndroid Build Coastguard Worker DCHECK(deopt_method != nullptr);
733*795d594fSAndroid Build Coastguard Worker if (VLOG_IS_ON(deopt) || kDebugExceptionDelivery) {
734*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "Single-frame deopting: "
735*795d594fSAndroid Build Coastguard Worker << deopt_method->PrettyMethod()
736*795d594fSAndroid Build Coastguard Worker << " due to "
737*795d594fSAndroid Build Coastguard Worker << GetDeoptimizationKindName(kind);
738*795d594fSAndroid Build Coastguard Worker DumpFramesWithType(self_, /* details= */ true);
739*795d594fSAndroid Build Coastguard Worker }
740*795d594fSAndroid Build Coastguard Worker // When deoptimizing for debug support the optimized code is still valid and
741*795d594fSAndroid Build Coastguard Worker // can be reused when debugging support (like breakpoints) are no longer
742*795d594fSAndroid Build Coastguard Worker // needed fot this method.
743*795d594fSAndroid Build Coastguard Worker Runtime* runtime = Runtime::Current();
744*795d594fSAndroid Build Coastguard Worker if (runtime->UseJitCompilation() && (kind != DeoptimizationKind::kDebugging)) {
745*795d594fSAndroid Build Coastguard Worker runtime->GetJit()->GetCodeCache()->InvalidateCompiledCodeFor(
746*795d594fSAndroid Build Coastguard Worker deopt_method, visitor.GetSingleFrameDeoptQuickMethodHeader());
747*795d594fSAndroid Build Coastguard Worker } else {
748*795d594fSAndroid Build Coastguard Worker runtime->GetInstrumentation()->InitializeMethodsCode(
749*795d594fSAndroid Build Coastguard Worker deopt_method, /*aot_code=*/ nullptr);
750*795d594fSAndroid Build Coastguard Worker }
751*795d594fSAndroid Build Coastguard Worker
752*795d594fSAndroid Build Coastguard Worker // If the deoptimization is due to an inline cache, update it with the type
753*795d594fSAndroid Build Coastguard Worker // that made us deoptimize. This avoids pathological cases of never seeing
754*795d594fSAndroid Build Coastguard Worker // that type while executing baseline generated code.
755*795d594fSAndroid Build Coastguard Worker if (kind == DeoptimizationKind::kJitInlineCache || kind == DeoptimizationKind::kJitSameTarget) {
756*795d594fSAndroid Build Coastguard Worker DCHECK(runtime->UseJitCompilation());
757*795d594fSAndroid Build Coastguard Worker ShadowFrame* shadow_frame = visitor.GetBottomShadowFrame();
758*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = shadow_frame->GetDexPC();
759*795d594fSAndroid Build Coastguard Worker CodeItemDataAccessor accessor(shadow_frame->GetMethod()->DexInstructionData());
760*795d594fSAndroid Build Coastguard Worker const uint16_t* const insns = accessor.Insns();
761*795d594fSAndroid Build Coastguard Worker const Instruction* inst = Instruction::At(insns + dex_pc);
762*795d594fSAndroid Build Coastguard Worker switch (inst->Opcode()) {
763*795d594fSAndroid Build Coastguard Worker case Instruction::INVOKE_INTERFACE:
764*795d594fSAndroid Build Coastguard Worker case Instruction::INVOKE_VIRTUAL:
765*795d594fSAndroid Build Coastguard Worker case Instruction::INVOKE_INTERFACE_RANGE:
766*795d594fSAndroid Build Coastguard Worker case Instruction::INVOKE_VIRTUAL_RANGE: {
767*795d594fSAndroid Build Coastguard Worker uint32_t encoded_dex_pc = InlineCache::EncodeDexPc(
768*795d594fSAndroid Build Coastguard Worker visitor.GetSingleFrameDeoptMethod(),
769*795d594fSAndroid Build Coastguard Worker visitor.GetDexPcs(),
770*795d594fSAndroid Build Coastguard Worker runtime->GetJit()->GetJitCompiler()->GetInlineMaxCodeUnits());
771*795d594fSAndroid Build Coastguard Worker if (encoded_dex_pc != static_cast<uint32_t>(-1)) {
772*795d594fSAndroid Build Coastguard Worker // The inline cache comes from the top-level method.
773*795d594fSAndroid Build Coastguard Worker runtime->GetJit()->GetCodeCache()->MaybeUpdateInlineCache(
774*795d594fSAndroid Build Coastguard Worker visitor.GetSingleFrameDeoptMethod(),
775*795d594fSAndroid Build Coastguard Worker encoded_dex_pc,
776*795d594fSAndroid Build Coastguard Worker shadow_frame->GetVRegReference(inst->VRegC())->GetClass(),
777*795d594fSAndroid Build Coastguard Worker self_);
778*795d594fSAndroid Build Coastguard Worker } else {
779*795d594fSAndroid Build Coastguard Worker // If the top-level inline cache did not exist, update the one for the
780*795d594fSAndroid Build Coastguard Worker // bottom method, we know it's the one that was used for compilation.
781*795d594fSAndroid Build Coastguard Worker runtime->GetJit()->GetCodeCache()->MaybeUpdateInlineCache(
782*795d594fSAndroid Build Coastguard Worker shadow_frame->GetMethod(),
783*795d594fSAndroid Build Coastguard Worker dex_pc,
784*795d594fSAndroid Build Coastguard Worker shadow_frame->GetVRegReference(inst->VRegC())->GetClass(),
785*795d594fSAndroid Build Coastguard Worker self_);
786*795d594fSAndroid Build Coastguard Worker }
787*795d594fSAndroid Build Coastguard Worker break;
788*795d594fSAndroid Build Coastguard Worker }
789*795d594fSAndroid Build Coastguard Worker default: {
790*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected instruction for inline cache: " << inst->Name();
791*795d594fSAndroid Build Coastguard Worker }
792*795d594fSAndroid Build Coastguard Worker }
793*795d594fSAndroid Build Coastguard Worker }
794*795d594fSAndroid Build Coastguard Worker
795*795d594fSAndroid Build Coastguard Worker PrepareForLongJumpToInvokeStubOrInterpreterBridge();
796*795d594fSAndroid Build Coastguard Worker }
797*795d594fSAndroid Build Coastguard Worker
DeoptimizePartialFragmentFixup()798*795d594fSAndroid Build Coastguard Worker void QuickExceptionHandler::DeoptimizePartialFragmentFixup() {
799*795d594fSAndroid Build Coastguard Worker CHECK(handler_quick_frame_ != nullptr);
800*795d594fSAndroid Build Coastguard Worker // Architecture-dependent work. This is to get the LR right for x86 and x86-64.
801*795d594fSAndroid Build Coastguard Worker if (kRuntimeQuickCodeISA == InstructionSet::kX86 ||
802*795d594fSAndroid Build Coastguard Worker kRuntimeQuickCodeISA == InstructionSet::kX86_64) {
803*795d594fSAndroid Build Coastguard Worker // On x86, the return address is on the stack, so just reuse it. Otherwise we would have to
804*795d594fSAndroid Build Coastguard Worker // change how longjump works.
805*795d594fSAndroid Build Coastguard Worker handler_quick_frame_ = reinterpret_cast<ArtMethod**>(
806*795d594fSAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(handler_quick_frame_) - sizeof(void*));
807*795d594fSAndroid Build Coastguard Worker }
808*795d594fSAndroid Build Coastguard Worker }
809*795d594fSAndroid Build Coastguard Worker
PrepareLongJump(bool smash_caller_saves)810*795d594fSAndroid Build Coastguard Worker std::unique_ptr<Context> QuickExceptionHandler::PrepareLongJump(bool smash_caller_saves) {
811*795d594fSAndroid Build Coastguard Worker // Prepare and return the context.
812*795d594fSAndroid Build Coastguard Worker context_->SetSP(reinterpret_cast<uintptr_t>(handler_quick_frame_));
813*795d594fSAndroid Build Coastguard Worker CHECK_NE(handler_quick_frame_pc_, 0u);
814*795d594fSAndroid Build Coastguard Worker context_->SetPC(handler_quick_frame_pc_);
815*795d594fSAndroid Build Coastguard Worker context_->SetArg0(handler_quick_arg0_);
816*795d594fSAndroid Build Coastguard Worker if (smash_caller_saves) {
817*795d594fSAndroid Build Coastguard Worker context_->SmashCallerSaves();
818*795d594fSAndroid Build Coastguard Worker }
819*795d594fSAndroid Build Coastguard Worker if (!is_deoptimization_ &&
820*795d594fSAndroid Build Coastguard Worker handler_method_header_ != nullptr &&
821*795d594fSAndroid Build Coastguard Worker handler_method_header_->IsNterpMethodHeader()) {
822*795d594fSAndroid Build Coastguard Worker // Interpreter procceses one method at a time i.e. not inlining
823*795d594fSAndroid Build Coastguard Worker DCHECK(handler_dex_pc_list_.has_value());
824*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(handler_dex_pc_list_->size(), 1u) << "We shouldn't have any inlined frames.";
825*795d594fSAndroid Build Coastguard Worker context_->SetNterpDexPC(reinterpret_cast<uintptr_t>(
826*795d594fSAndroid Build Coastguard Worker GetHandlerMethod()->DexInstructions().Insns() + handler_dex_pc_list_->front()));
827*795d594fSAndroid Build Coastguard Worker }
828*795d594fSAndroid Build Coastguard Worker // Clear the dex_pc list so as not to leak memory.
829*795d594fSAndroid Build Coastguard Worker handler_dex_pc_list_.reset();
830*795d594fSAndroid Build Coastguard Worker return std::move(context_);
831*795d594fSAndroid Build Coastguard Worker }
832*795d594fSAndroid Build Coastguard Worker
DumpFramesWithType(Thread * self,bool details)833*795d594fSAndroid Build Coastguard Worker void QuickExceptionHandler::DumpFramesWithType(Thread* self, bool details) {
834*795d594fSAndroid Build Coastguard Worker StackVisitor::WalkStack(
835*795d594fSAndroid Build Coastguard Worker [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
836*795d594fSAndroid Build Coastguard Worker ArtMethod* method = stack_visitor->GetMethod();
837*795d594fSAndroid Build Coastguard Worker if (details) {
838*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "|> pc = " << std::hex << stack_visitor->GetCurrentQuickFramePc();
839*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "|> addr = " << std::hex
840*795d594fSAndroid Build Coastguard Worker << reinterpret_cast<uintptr_t>(stack_visitor->GetCurrentQuickFrame());
841*795d594fSAndroid Build Coastguard Worker if (stack_visitor->GetCurrentQuickFrame() != nullptr && method != nullptr) {
842*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "|> ret = " << std::hex << stack_visitor->GetReturnPc();
843*795d594fSAndroid Build Coastguard Worker }
844*795d594fSAndroid Build Coastguard Worker }
845*795d594fSAndroid Build Coastguard Worker if (method == nullptr) {
846*795d594fSAndroid Build Coastguard Worker // Transition, do go on, we want to unwind over bridges, all the way.
847*795d594fSAndroid Build Coastguard Worker if (details) {
848*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "N <transition>";
849*795d594fSAndroid Build Coastguard Worker }
850*795d594fSAndroid Build Coastguard Worker return true;
851*795d594fSAndroid Build Coastguard Worker } else if (method->IsRuntimeMethod()) {
852*795d594fSAndroid Build Coastguard Worker if (details) {
853*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "R " << method->PrettyMethod(true);
854*795d594fSAndroid Build Coastguard Worker }
855*795d594fSAndroid Build Coastguard Worker return true;
856*795d594fSAndroid Build Coastguard Worker } else {
857*795d594fSAndroid Build Coastguard Worker bool is_shadow = stack_visitor->GetCurrentShadowFrame() != nullptr;
858*795d594fSAndroid Build Coastguard Worker LOG(INFO) << (is_shadow ? "S" : "Q")
859*795d594fSAndroid Build Coastguard Worker << ((!is_shadow && stack_visitor->IsInInlinedFrame()) ? "i" : " ")
860*795d594fSAndroid Build Coastguard Worker << " "
861*795d594fSAndroid Build Coastguard Worker << method->PrettyMethod(true);
862*795d594fSAndroid Build Coastguard Worker return true; // Go on.
863*795d594fSAndroid Build Coastguard Worker }
864*795d594fSAndroid Build Coastguard Worker },
865*795d594fSAndroid Build Coastguard Worker self,
866*795d594fSAndroid Build Coastguard Worker /* context= */ nullptr,
867*795d594fSAndroid Build Coastguard Worker art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
868*795d594fSAndroid Build Coastguard Worker }
869*795d594fSAndroid Build Coastguard Worker
870*795d594fSAndroid Build Coastguard Worker } // namespace art
871