xref: /aosp_15_r20/art/runtime/quick_exception_handler.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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