| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2011 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
 | 17 | #include "stack.h" | 
 | 18 |  | 
| Andreas Gampe | 46ee31b | 2016-12-14 10:11:49 -0800 | [diff] [blame] | 19 | #include "android-base/stringprintf.h" | 
 | 20 |  | 
| Ian Rogers | e63db27 | 2014-07-15 15:36:11 -0700 | [diff] [blame] | 21 | #include "arch/context.h" | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 22 | #include "art_method-inl.h" | 
| Andreas Gampe | 8228cdf | 2017-05-30 15:03:54 -0700 | [diff] [blame] | 23 | #include "base/callee_save_type.h" | 
| Andreas Gampe | 542451c | 2016-07-26 09:02:02 -0700 | [diff] [blame] | 24 | #include "base/enums.h" | 
| Dave Allison | f943914 | 2014-03-27 15:10:22 -0700 | [diff] [blame] | 25 | #include "base/hex_dump.h" | 
| David Sehr | 9e734c7 | 2018-01-04 17:56:19 -0800 | [diff] [blame] | 26 | #include "dex/dex_file_types.h" | 
| Nicolas Geoffray | d23eeef | 2015-05-18 22:31:29 +0100 | [diff] [blame] | 27 | #include "entrypoints/entrypoint_utils-inl.h" | 
| Vladimir Marko | d3083dd | 2018-05-17 08:43:47 +0100 | [diff] [blame] | 28 | #include "entrypoints/quick/callee_save_frame.h" | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 29 | #include "entrypoints/runtime_asm_entrypoints.h" | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 30 | #include "gc/space/image_space.h" | 
 | 31 | #include "gc/space/space-inl.h" | 
| Vladimir Marko | 6ec2a1b | 2018-05-22 15:33:48 +0100 | [diff] [blame] | 32 | #include "interpreter/shadow_frame-inl.h" | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 33 | #include "jit/jit.h" | 
 | 34 | #include "jit/jit_code_cache.h" | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 35 | #include "linear_alloc.h" | 
| Andreas Gampe | 513061a | 2017-06-01 09:17:34 -0700 | [diff] [blame] | 36 | #include "managed_stack.h" | 
| Ian Rogers | 4f6ad8a | 2013-03-18 15:27:28 -0700 | [diff] [blame] | 37 | #include "mirror/class-inl.h" | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 38 | #include "mirror/object-inl.h" | 
 | 39 | #include "mirror/object_array-inl.h" | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 40 | #include "oat_quick_method_header.h" | 
| Vladimir Marko | 439d126 | 2019-04-12 14:45:07 +0100 | [diff] [blame] | 41 | #include "obj_ptr-inl.h" | 
| Vladimir Marko | 7624d25 | 2014-05-02 14:40:15 +0100 | [diff] [blame] | 42 | #include "quick/quick_method_frame_info.h" | 
| Mathieu Chartier | 590fee9 | 2013-09-13 13:46:47 -0700 | [diff] [blame] | 43 | #include "runtime.h" | 
| Dave Allison | f943914 | 2014-03-27 15:10:22 -0700 | [diff] [blame] | 44 | #include "thread.h" | 
| Elliott Hughes | bfe487b | 2011-10-26 15:48:55 -0700 | [diff] [blame] | 45 | #include "thread_list.h" | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 46 |  | 
| Elliott Hughes | 11d1b0c | 2012-01-23 16:57:47 -0800 | [diff] [blame] | 47 | namespace art { | 
 | 48 |  | 
| Andreas Gampe | 46ee31b | 2016-12-14 10:11:49 -0800 | [diff] [blame] | 49 | using android::base::StringPrintf; | 
 | 50 |  | 
| Mathieu Chartier | 8405bfd | 2016-02-05 12:00:49 -0800 | [diff] [blame] | 51 | static constexpr bool kDebugStackWalk = false; | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 52 |  | 
| Hiroshi Yamauchi | 02f365f | 2017-02-03 15:06:00 -0800 | [diff] [blame] | 53 | StackVisitor::StackVisitor(Thread* thread, | 
 | 54 |                            Context* context, | 
 | 55 |                            StackWalkKind walk_kind, | 
 | 56 |                            bool check_suspended) | 
 | 57 |     : StackVisitor(thread, context, walk_kind, 0, check_suspended) {} | 
| Ian Rogers | 7a22fa6 | 2013-01-23 12:16:16 -0800 | [diff] [blame] | 58 |  | 
| Nicolas Geoffray | 8e5bd18 | 2015-05-06 11:34:34 +0100 | [diff] [blame] | 59 | StackVisitor::StackVisitor(Thread* thread, | 
 | 60 |                            Context* context, | 
 | 61 |                            StackWalkKind walk_kind, | 
| Hiroshi Yamauchi | 02f365f | 2017-02-03 15:06:00 -0800 | [diff] [blame] | 62 |                            size_t num_frames, | 
 | 63 |                            bool check_suspended) | 
| Nicolas Geoffray | 8e5bd18 | 2015-05-06 11:34:34 +0100 | [diff] [blame] | 64 |     : thread_(thread), | 
 | 65 |       walk_kind_(walk_kind), | 
 | 66 |       cur_shadow_frame_(nullptr), | 
 | 67 |       cur_quick_frame_(nullptr), | 
 | 68 |       cur_quick_frame_pc_(0), | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 69 |       cur_oat_quick_method_header_(nullptr), | 
| Nicolas Geoffray | 8e5bd18 | 2015-05-06 11:34:34 +0100 | [diff] [blame] | 70 |       num_frames_(num_frames), | 
 | 71 |       cur_depth_(0), | 
| Hiroshi Yamauchi | 02f365f | 2017-02-03 15:06:00 -0800 | [diff] [blame] | 72 |       context_(context), | 
 | 73 |       check_suspended_(check_suspended) { | 
 | 74 |   if (check_suspended_) { | 
 | 75 |     DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread; | 
 | 76 |   } | 
| Ian Rogers | 5cf9819 | 2014-05-29 21:31:50 -0700 | [diff] [blame] | 77 | } | 
 | 78 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 79 | ArtMethod* StackVisitor::GetMethod() const { | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 80 |   if (cur_shadow_frame_ != nullptr) { | 
 | 81 |     return cur_shadow_frame_->GetMethod(); | 
 | 82 |   } else if (cur_quick_frame_ != nullptr) { | 
 | 83 |     if (IsInInlinedFrame()) { | 
| David Srbecky | 61b28a1 | 2016-02-25 21:55:03 +0000 | [diff] [blame] | 84 |       const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); | 
| David Srbecky | 8cd5454 | 2018-07-15 23:58:44 +0100 | [diff] [blame] | 85 |       CodeInfo code_info(method_header); | 
| Mathieu Chartier | 45bf250 | 2016-03-31 11:07:09 -0700 | [diff] [blame] | 86 |       DCHECK(walk_kind_ != StackWalkKind::kSkipInlinedFrames); | 
| David Srbecky | 8cd5454 | 2018-07-15 23:58:44 +0100 | [diff] [blame] | 87 |       return GetResolvedMethod(*GetCurrentQuickFrame(), code_info, current_inline_frames_); | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 88 |     } else { | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 89 |       return *cur_quick_frame_; | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 90 |     } | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 91 |   } | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 92 |   return nullptr; | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 93 | } | 
 | 94 |  | 
| Dave Allison | b373e09 | 2014-02-20 16:06:36 -0800 | [diff] [blame] | 95 | uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 96 |   if (cur_shadow_frame_ != nullptr) { | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 97 |     return cur_shadow_frame_->GetDexPC(); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 98 |   } else if (cur_quick_frame_ != nullptr) { | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 99 |     if (IsInInlinedFrame()) { | 
| David Srbecky | 93bd361 | 2018-07-02 19:30:18 +0100 | [diff] [blame] | 100 |       return current_inline_frames_.back().GetDexPc(); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 101 |     } else if (cur_oat_quick_method_header_ == nullptr) { | 
| Andreas Gampe | e2abbc6 | 2017-09-15 11:59:26 -0700 | [diff] [blame] | 102 |       return dex::kDexNoIndex; | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 103 |     } else { | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 104 |       return cur_oat_quick_method_header_->ToDexPc( | 
 | 105 |           GetMethod(), cur_quick_frame_pc_, abort_on_failure); | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 106 |     } | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 107 |   } else { | 
 | 108 |     return 0; | 
 | 109 |   } | 
 | 110 | } | 
 | 111 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 112 | extern "C" mirror::Object* artQuickGetProxyThisObject(ArtMethod** sp) | 
| Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 113 |     REQUIRES_SHARED(Locks::mutator_lock_); | 
| Sebastien Hertz | a836bc9 | 2014-11-25 16:30:53 +0100 | [diff] [blame] | 114 |  | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 115 | mirror::Object* StackVisitor::GetThisObject() const { | 
| Andreas Gampe | 542451c | 2016-07-26 09:02:02 -0700 | [diff] [blame] | 116 |   DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize); | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 117 |   ArtMethod* m = GetMethod(); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 118 |   if (m->IsStatic()) { | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 119 |     return nullptr; | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 120 |   } else if (m->IsNative()) { | 
| Nicolas Geoffray | 3946844 | 2014-09-02 15:17:15 +0100 | [diff] [blame] | 121 |     if (cur_quick_frame_ != nullptr) { | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 122 |       HandleScope* hs = reinterpret_cast<HandleScope*>( | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 123 |           reinterpret_cast<char*>(cur_quick_frame_) + sizeof(ArtMethod*)); | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 124 |       return hs->GetReference(0); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 125 |     } else { | 
 | 126 |       return cur_shadow_frame_->GetVRegReference(0); | 
 | 127 |     } | 
| Nicolas Geoffray | 3a09092 | 2015-11-24 09:17:30 +0000 | [diff] [blame] | 128 |   } else if (m->IsProxyMethod()) { | 
| Sebastien Hertz | a836bc9 | 2014-11-25 16:30:53 +0100 | [diff] [blame] | 129 |     if (cur_quick_frame_ != nullptr) { | 
 | 130 |       return artQuickGetProxyThisObject(cur_quick_frame_); | 
 | 131 |     } else { | 
 | 132 |       return cur_shadow_frame_->GetVRegReference(0); | 
 | 133 |     } | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 134 |   } else { | 
| David Sehr | 0225f8e | 2018-01-31 08:52:24 +0000 | [diff] [blame] | 135 |     CodeItemDataAccessor accessor(m->DexInstructionData()); | 
| Mathieu Chartier | 808c7a5 | 2017-12-15 11:19:33 -0800 | [diff] [blame] | 136 |     if (!accessor.HasCodeItem()) { | 
| Ian Rogers | e0dcd46 | 2014-03-08 15:21:04 -0800 | [diff] [blame] | 137 |       UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: " | 
| David Sehr | 709b070 | 2016-10-13 09:12:37 -0700 | [diff] [blame] | 138 |           << ArtMethod::PrettyMethod(m); | 
| Ian Rogers | e0dcd46 | 2014-03-08 15:21:04 -0800 | [diff] [blame] | 139 |       return nullptr; | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 140 |     } else { | 
| Mathieu Chartier | 808c7a5 | 2017-12-15 11:19:33 -0800 | [diff] [blame] | 141 |       uint16_t reg = accessor.RegistersSize() - accessor.InsSize(); | 
| Nicolas Geoffray | 15b9d52 | 2015-03-12 15:05:13 +0000 | [diff] [blame] | 142 |       uint32_t value = 0; | 
| Nicolas Geoffray | 4cbfadc | 2018-10-10 16:09:43 +0100 | [diff] [blame] | 143 |       if (!GetVReg(m, reg, kReferenceVReg, &value)) { | 
 | 144 |         return nullptr; | 
 | 145 |       } | 
| Nicolas Geoffray | 15b9d52 | 2015-03-12 15:05:13 +0000 | [diff] [blame] | 146 |       return reinterpret_cast<mirror::Object*>(value); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 147 |     } | 
 | 148 |   } | 
 | 149 | } | 
 | 150 |  | 
| Ian Rogers | 0c7abda | 2012-09-19 13:33:42 -0700 | [diff] [blame] | 151 | size_t StackVisitor::GetNativePcOffset() const { | 
 | 152 |   DCHECK(!IsShadowFrame()); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 153 |   return GetCurrentOatQuickMethodHeader()->NativeQuickPcOffset(cur_quick_frame_pc_); | 
| Ian Rogers | 0c7abda | 2012-09-19 13:33:42 -0700 | [diff] [blame] | 154 | } | 
 | 155 |  | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 156 | bool StackVisitor::GetVRegFromDebuggerShadowFrame(uint16_t vreg, | 
 | 157 |                                                   VRegKind kind, | 
 | 158 |                                                   uint32_t* val) const { | 
 | 159 |   size_t frame_id = const_cast<StackVisitor*>(this)->GetFrameId(); | 
 | 160 |   ShadowFrame* shadow_frame = thread_->FindDebuggerShadowFrame(frame_id); | 
 | 161 |   if (shadow_frame != nullptr) { | 
 | 162 |     bool* updated_vreg_flags = thread_->GetUpdatedVRegFlags(frame_id); | 
 | 163 |     DCHECK(updated_vreg_flags != nullptr); | 
 | 164 |     if (updated_vreg_flags[vreg]) { | 
 | 165 |       // Value is set by the debugger. | 
 | 166 |       if (kind == kReferenceVReg) { | 
 | 167 |         *val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>( | 
 | 168 |             shadow_frame->GetVRegReference(vreg))); | 
 | 169 |       } else { | 
 | 170 |         *val = shadow_frame->GetVReg(vreg); | 
 | 171 |       } | 
 | 172 |       return true; | 
 | 173 |     } | 
 | 174 |   } | 
 | 175 |   // No value is set by the debugger. | 
 | 176 |   return false; | 
 | 177 | } | 
 | 178 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 179 | bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const { | 
| Sebastien Hertz | c901dd7 | 2014-07-16 11:56:07 +0200 | [diff] [blame] | 180 |   if (cur_quick_frame_ != nullptr) { | 
 | 181 |     DCHECK(context_ != nullptr);  // You can't reliably read registers without a context. | 
| Ian Rogers | 2bcb4a4 | 2012-11-08 10:39:18 -0800 | [diff] [blame] | 182 |     DCHECK(m == GetMethod()); | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 183 |     // Check if there is value set by the debugger. | 
 | 184 |     if (GetVRegFromDebuggerShadowFrame(vreg, kind, val)) { | 
 | 185 |       return true; | 
 | 186 |     } | 
| Vladimir Marko | 9d07e3d | 2016-03-31 12:02:28 +0100 | [diff] [blame] | 187 |     DCHECK(cur_oat_quick_method_header_->IsOptimized()); | 
 | 188 |     return GetVRegFromOptimizedCode(m, vreg, kind, val); | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 189 |   } else { | 
| Sebastien Hertz | 96ba8dc | 2015-01-22 18:57:14 +0100 | [diff] [blame] | 190 |     DCHECK(cur_shadow_frame_ != nullptr); | 
| Sebastien Hertz | 0968744 | 2015-11-17 10:35:39 +0100 | [diff] [blame] | 191 |     if (kind == kReferenceVReg) { | 
 | 192 |       *val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>( | 
 | 193 |           cur_shadow_frame_->GetVRegReference(vreg))); | 
 | 194 |     } else { | 
 | 195 |       *val = cur_shadow_frame_->GetVReg(vreg); | 
 | 196 |     } | 
| Sebastien Hertz | 0bcb290 | 2014-06-17 15:52:45 +0200 | [diff] [blame] | 197 |     return true; | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 198 |   } | 
 | 199 | } | 
 | 200 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 201 | bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind, | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 202 |                                             uint32_t* val) const { | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 203 |   DCHECK_EQ(m, GetMethod()); | 
| Mathieu Chartier | 808c7a5 | 2017-12-15 11:19:33 -0800 | [diff] [blame] | 204 |   // Can't be null or how would we compile its instructions? | 
 | 205 |   DCHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod(); | 
| David Sehr | 0225f8e | 2018-01-31 08:52:24 +0000 | [diff] [blame] | 206 |   CodeItemDataAccessor accessor(m->DexInstructionData()); | 
| Mathieu Chartier | 808c7a5 | 2017-12-15 11:19:33 -0800 | [diff] [blame] | 207 |   uint16_t number_of_dex_registers = accessor.RegistersSize(); | 
 | 208 |   DCHECK_LT(vreg, number_of_dex_registers); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 209 |   const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); | 
| David Srbecky | 052f8ca | 2018-04-26 15:42:54 +0100 | [diff] [blame] | 210 |   CodeInfo code_info(method_header); | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 211 |  | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 212 |   uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc_); | 
| David Srbecky | 052f8ca | 2018-04-26 15:42:54 +0100 | [diff] [blame] | 213 |   StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); | 
| Nicolas Geoffray | e12997f | 2015-05-22 14:01:33 +0100 | [diff] [blame] | 214 |   DCHECK(stack_map.IsValid()); | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 215 |  | 
 | 216 |   DexRegisterMap dex_register_map = IsInInlinedFrame() | 
| David Srbecky | 93bd361 | 2018-07-02 19:30:18 +0100 | [diff] [blame] | 217 |       ? code_info.GetInlineDexRegisterMapOf(stack_map, current_inline_frames_.back()) | 
| David Srbecky | fd89b07 | 2018-06-03 12:00:22 +0100 | [diff] [blame] | 218 |       : code_info.GetDexRegisterMapOf(stack_map); | 
 | 219 |   if (dex_register_map.empty()) { | 
| Nicolas Geoffray | 012fc4e | 2016-01-08 15:58:19 +0000 | [diff] [blame] | 220 |     return false; | 
 | 221 |   } | 
| David Srbecky | fd89b07 | 2018-06-03 12:00:22 +0100 | [diff] [blame] | 222 |   DCHECK_EQ(dex_register_map.size(), number_of_dex_registers); | 
| David Srbecky | e140212 | 2018-06-13 18:20:45 +0100 | [diff] [blame] | 223 |   DexRegisterLocation::Kind location_kind = dex_register_map[vreg].GetKind(); | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 224 |   switch (location_kind) { | 
| Roland Levillain | a2d8ec6 | 2015-03-12 15:25:29 +0000 | [diff] [blame] | 225 |     case DexRegisterLocation::Kind::kInStack: { | 
| David Srbecky | e140212 | 2018-06-13 18:20:45 +0100 | [diff] [blame] | 226 |       const int32_t offset = dex_register_map[vreg].GetStackOffsetInBytes(); | 
| Nicolas Geoffray | 4cbfadc | 2018-10-10 16:09:43 +0100 | [diff] [blame] | 227 |       BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); | 
 | 228 |       if (kind == kReferenceVReg && !stack_mask.LoadBit(offset / kFrameSlotSize)) { | 
 | 229 |         return false; | 
 | 230 |       } | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 231 |       const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset; | 
 | 232 |       *val = *reinterpret_cast<const uint32_t*>(addr); | 
 | 233 |       return true; | 
 | 234 |     } | 
| Nicolas Geoffray | 4cbfadc | 2018-10-10 16:09:43 +0100 | [diff] [blame] | 235 |     case DexRegisterLocation::Kind::kInRegister: { | 
 | 236 |       uint32_t register_mask = code_info.GetRegisterMaskOf(stack_map); | 
 | 237 |       uint32_t reg = dex_register_map[vreg].GetMachineRegister(); | 
 | 238 |       if (kind == kReferenceVReg && !(register_mask & (1 << reg))) { | 
 | 239 |         return false; | 
 | 240 |       } | 
 | 241 |       return GetRegisterIfAccessible(reg, kind, val); | 
 | 242 |     } | 
| David Brazdil | d9cb68e | 2015-08-25 13:52:43 +0100 | [diff] [blame] | 243 |     case DexRegisterLocation::Kind::kInRegisterHigh: | 
 | 244 |     case DexRegisterLocation::Kind::kInFpuRegister: | 
 | 245 |     case DexRegisterLocation::Kind::kInFpuRegisterHigh: { | 
| Nicolas Geoffray | 4cbfadc | 2018-10-10 16:09:43 +0100 | [diff] [blame] | 246 |       if (kind == kReferenceVReg) { | 
 | 247 |         return false; | 
 | 248 |       } | 
| David Srbecky | e140212 | 2018-06-13 18:20:45 +0100 | [diff] [blame] | 249 |       uint32_t reg = dex_register_map[vreg].GetMachineRegister(); | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 250 |       return GetRegisterIfAccessible(reg, kind, val); | 
 | 251 |     } | 
| Nicolas Geoffray | 4cbfadc | 2018-10-10 16:09:43 +0100 | [diff] [blame] | 252 |     case DexRegisterLocation::Kind::kConstant: { | 
 | 253 |       uint32_t result = dex_register_map[vreg].GetConstant(); | 
 | 254 |       if (kind == kReferenceVReg && result != 0) { | 
 | 255 |         return false; | 
 | 256 |       } | 
 | 257 |       *val = result; | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 258 |       return true; | 
| Nicolas Geoffray | 4cbfadc | 2018-10-10 16:09:43 +0100 | [diff] [blame] | 259 |     } | 
| Roland Levillain | a2d8ec6 | 2015-03-12 15:25:29 +0000 | [diff] [blame] | 260 |     case DexRegisterLocation::Kind::kNone: | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 261 |       return false; | 
| Roland Levillain | a2d8ec6 | 2015-03-12 15:25:29 +0000 | [diff] [blame] | 262 |     default: | 
| David Srbecky | e140212 | 2018-06-13 18:20:45 +0100 | [diff] [blame] | 263 |       LOG(FATAL) << "Unexpected location kind " << dex_register_map[vreg].GetKind(); | 
| Roland Levillain | a2d8ec6 | 2015-03-12 15:25:29 +0000 | [diff] [blame] | 264 |       UNREACHABLE(); | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 265 |   } | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 266 | } | 
 | 267 |  | 
 | 268 | bool StackVisitor::GetRegisterIfAccessible(uint32_t reg, VRegKind kind, uint32_t* val) const { | 
 | 269 |   const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); | 
| David Brazdil | 77a48ae | 2015-09-15 12:34:04 +0000 | [diff] [blame] | 270 |  | 
| Vladimir Marko | 239d6ea | 2016-09-05 10:44:04 +0100 | [diff] [blame] | 271 |   if (kRuntimeISA == InstructionSet::kX86 && is_float) { | 
 | 272 |     // X86 float registers are 64-bit and each XMM register is provided as two separate | 
 | 273 |     // 32-bit registers by the context. | 
 | 274 |     reg = (kind == kDoubleHiVReg) ? (2 * reg + 1) : (2 * reg); | 
 | 275 |   } | 
| David Brazdil | 77a48ae | 2015-09-15 12:34:04 +0000 | [diff] [blame] | 276 |  | 
| Goran Jakovljevic | 986660c | 2015-12-10 11:44:50 +0100 | [diff] [blame] | 277 |   // MIPS32 float registers are used as 64-bit (for MIPS32r2 it is pair | 
 | 278 |   // F(2n)-F(2n+1), and for MIPS32r6 it is 64-bit register F(2n)). When | 
 | 279 |   // accessing upper 32-bits from double, reg + 1 should be used. | 
 | 280 |   if ((kRuntimeISA == InstructionSet::kMips) && (kind == kDoubleHiVReg)) { | 
 | 281 |     DCHECK_ALIGNED(reg, 2); | 
 | 282 |     reg++; | 
 | 283 |   } | 
 | 284 |  | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 285 |   if (!IsAccessibleRegister(reg, is_float)) { | 
 | 286 |     return false; | 
 | 287 |   } | 
 | 288 |   uintptr_t ptr_val = GetRegister(reg, is_float); | 
 | 289 |   const bool target64 = Is64BitInstructionSet(kRuntimeISA); | 
 | 290 |   if (target64) { | 
 | 291 |     const bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg); | 
 | 292 |     const bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg); | 
 | 293 |     int64_t value_long = static_cast<int64_t>(ptr_val); | 
 | 294 |     if (wide_lo) { | 
 | 295 |       ptr_val = static_cast<uintptr_t>(Low32Bits(value_long)); | 
 | 296 |     } else if (wide_hi) { | 
 | 297 |       ptr_val = static_cast<uintptr_t>(High32Bits(value_long)); | 
 | 298 |     } | 
 | 299 |   } | 
 | 300 |   *val = ptr_val; | 
 | 301 |   return true; | 
 | 302 | } | 
 | 303 |  | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 304 | bool StackVisitor::GetVRegPairFromDebuggerShadowFrame(uint16_t vreg, | 
 | 305 |                                                       VRegKind kind_lo, | 
 | 306 |                                                       VRegKind kind_hi, | 
 | 307 |                                                       uint64_t* val) const { | 
 | 308 |   uint32_t low_32bits; | 
 | 309 |   uint32_t high_32bits; | 
 | 310 |   bool success = GetVRegFromDebuggerShadowFrame(vreg, kind_lo, &low_32bits); | 
 | 311 |   success &= GetVRegFromDebuggerShadowFrame(vreg + 1, kind_hi, &high_32bits); | 
 | 312 |   if (success) { | 
 | 313 |     *val = (static_cast<uint64_t>(high_32bits) << 32) | static_cast<uint64_t>(low_32bits); | 
 | 314 |   } | 
 | 315 |   return success; | 
 | 316 | } | 
 | 317 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 318 | bool StackVisitor::GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, | 
| Sebastien Hertz | c901dd7 | 2014-07-16 11:56:07 +0200 | [diff] [blame] | 319 |                                VRegKind kind_hi, uint64_t* val) const { | 
 | 320 |   if (kind_lo == kLongLoVReg) { | 
 | 321 |     DCHECK_EQ(kind_hi, kLongHiVReg); | 
 | 322 |   } else if (kind_lo == kDoubleLoVReg) { | 
 | 323 |     DCHECK_EQ(kind_hi, kDoubleHiVReg); | 
 | 324 |   } else { | 
 | 325 |     LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi; | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 326 |     UNREACHABLE(); | 
| Sebastien Hertz | c901dd7 | 2014-07-16 11:56:07 +0200 | [diff] [blame] | 327 |   } | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 328 |   // Check if there is value set by the debugger. | 
 | 329 |   if (GetVRegPairFromDebuggerShadowFrame(vreg, kind_lo, kind_hi, val)) { | 
 | 330 |     return true; | 
 | 331 |   } | 
| Sebastien Hertz | c901dd7 | 2014-07-16 11:56:07 +0200 | [diff] [blame] | 332 |   if (cur_quick_frame_ != nullptr) { | 
 | 333 |     DCHECK(context_ != nullptr);  // You can't reliably read registers without a context. | 
 | 334 |     DCHECK(m == GetMethod()); | 
| Vladimir Marko | 9d07e3d | 2016-03-31 12:02:28 +0100 | [diff] [blame] | 335 |     DCHECK(cur_oat_quick_method_header_->IsOptimized()); | 
 | 336 |     return GetVRegPairFromOptimizedCode(m, vreg, kind_lo, kind_hi, val); | 
| Sebastien Hertz | c901dd7 | 2014-07-16 11:56:07 +0200 | [diff] [blame] | 337 |   } else { | 
| Sebastien Hertz | 96ba8dc | 2015-01-22 18:57:14 +0100 | [diff] [blame] | 338 |     DCHECK(cur_shadow_frame_ != nullptr); | 
| Sebastien Hertz | c901dd7 | 2014-07-16 11:56:07 +0200 | [diff] [blame] | 339 |     *val = cur_shadow_frame_->GetVRegLong(vreg); | 
 | 340 |     return true; | 
 | 341 |   } | 
 | 342 | } | 
 | 343 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 344 | bool StackVisitor::GetVRegPairFromOptimizedCode(ArtMethod* m, uint16_t vreg, | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 345 |                                                 VRegKind kind_lo, VRegKind kind_hi, | 
 | 346 |                                                 uint64_t* val) const { | 
 | 347 |   uint32_t low_32bits; | 
 | 348 |   uint32_t high_32bits; | 
| Igor Murashkin | b1d8c31 | 2015-08-04 11:18:43 -0700 | [diff] [blame] | 349 |   bool success = GetVRegFromOptimizedCode(m, vreg, kind_lo, &low_32bits); | 
 | 350 |   success &= GetVRegFromOptimizedCode(m, vreg + 1, kind_hi, &high_32bits); | 
| Sebastien Hertz | 7cde48c | 2015-01-20 16:06:43 +0100 | [diff] [blame] | 351 |   if (success) { | 
 | 352 |     *val = (static_cast<uint64_t>(high_32bits) << 32) | static_cast<uint64_t>(low_32bits); | 
 | 353 |   } | 
 | 354 |   return success; | 
 | 355 | } | 
 | 356 |  | 
 | 357 | bool StackVisitor::GetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, | 
 | 358 |                                                VRegKind kind_lo, uint64_t* val) const { | 
 | 359 |   const bool is_float = (kind_lo == kDoubleLoVReg); | 
 | 360 |   if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) { | 
 | 361 |     return false; | 
 | 362 |   } | 
 | 363 |   uintptr_t ptr_val_lo = GetRegister(reg_lo, is_float); | 
 | 364 |   uintptr_t ptr_val_hi = GetRegister(reg_hi, is_float); | 
 | 365 |   bool target64 = Is64BitInstructionSet(kRuntimeISA); | 
 | 366 |   if (target64) { | 
 | 367 |     int64_t value_long_lo = static_cast<int64_t>(ptr_val_lo); | 
 | 368 |     int64_t value_long_hi = static_cast<int64_t>(ptr_val_hi); | 
 | 369 |     ptr_val_lo = static_cast<uintptr_t>(Low32Bits(value_long_lo)); | 
 | 370 |     ptr_val_hi = static_cast<uintptr_t>(High32Bits(value_long_hi)); | 
 | 371 |   } | 
 | 372 |   *val = (static_cast<uint64_t>(ptr_val_hi) << 32) | static_cast<uint32_t>(ptr_val_lo); | 
 | 373 |   return true; | 
 | 374 | } | 
 | 375 |  | 
| Vladimir Marko | 439d126 | 2019-04-12 14:45:07 +0100 | [diff] [blame] | 376 | ShadowFrame* StackVisitor::PrepareSetVReg(ArtMethod* m, uint16_t vreg, bool wide) { | 
| David Sehr | 0225f8e | 2018-01-31 08:52:24 +0000 | [diff] [blame] | 377 |   CodeItemDataAccessor accessor(m->DexInstructionData()); | 
| Mathieu Chartier | 808c7a5 | 2017-12-15 11:19:33 -0800 | [diff] [blame] | 378 |   if (!accessor.HasCodeItem()) { | 
| Vladimir Marko | 439d126 | 2019-04-12 14:45:07 +0100 | [diff] [blame] | 379 |     return nullptr; | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 380 |   } | 
 | 381 |   ShadowFrame* shadow_frame = GetCurrentShadowFrame(); | 
 | 382 |   if (shadow_frame == nullptr) { | 
 | 383 |     // This is a compiled frame: we must prepare and update a shadow frame that will | 
 | 384 |     // be executed by the interpreter after deoptimization of the stack. | 
 | 385 |     const size_t frame_id = GetFrameId(); | 
| Mathieu Chartier | 808c7a5 | 2017-12-15 11:19:33 -0800 | [diff] [blame] | 386 |     const uint16_t num_regs = accessor.RegistersSize(); | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 387 |     shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc()); | 
 | 388 |     CHECK(shadow_frame != nullptr); | 
| Vladimir Marko | 439d126 | 2019-04-12 14:45:07 +0100 | [diff] [blame] | 389 |     // Remember the vreg(s) has been set for debugging and must not be overwritten by the | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 390 |     // original value during deoptimization of the stack. | 
 | 391 |     thread_->GetUpdatedVRegFlags(frame_id)[vreg] = true; | 
| Vladimir Marko | 439d126 | 2019-04-12 14:45:07 +0100 | [diff] [blame] | 392 |     if (wide) { | 
 | 393 |       thread_->GetUpdatedVRegFlags(frame_id)[vreg + 1] = true; | 
 | 394 |     } | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 395 |   } | 
| Vladimir Marko | 439d126 | 2019-04-12 14:45:07 +0100 | [diff] [blame] | 396 |   return shadow_frame; | 
 | 397 | } | 
 | 398 |  | 
 | 399 | bool StackVisitor::SetVReg(ArtMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind) { | 
 | 400 |   DCHECK(kind == kIntVReg || kind == kFloatVReg); | 
 | 401 |   ShadowFrame* shadow_frame = PrepareSetVReg(m, vreg, /* wide= */ false); | 
 | 402 |   if (shadow_frame == nullptr) { | 
 | 403 |     return false; | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 404 |   } | 
| Vladimir Marko | 439d126 | 2019-04-12 14:45:07 +0100 | [diff] [blame] | 405 |   shadow_frame->SetVReg(vreg, new_value); | 
 | 406 |   return true; | 
 | 407 | } | 
 | 408 |  | 
 | 409 | bool StackVisitor::SetVRegReference(ArtMethod* m, uint16_t vreg, ObjPtr<mirror::Object> new_value) { | 
 | 410 |   ShadowFrame* shadow_frame = PrepareSetVReg(m, vreg, /* wide= */ false); | 
 | 411 |   if (shadow_frame == nullptr) { | 
 | 412 |     return false; | 
 | 413 |   } | 
 | 414 |   shadow_frame->SetVRegReference(vreg, new_value); | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 415 |   return true; | 
 | 416 | } | 
 | 417 |  | 
| Mingyao Yang | 636b925 | 2015-07-31 16:40:24 -0700 | [diff] [blame] | 418 | bool StackVisitor::SetVRegPair(ArtMethod* m, | 
 | 419 |                                uint16_t vreg, | 
 | 420 |                                uint64_t new_value, | 
 | 421 |                                VRegKind kind_lo, | 
 | 422 |                                VRegKind kind_hi) { | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 423 |   if (kind_lo == kLongLoVReg) { | 
 | 424 |     DCHECK_EQ(kind_hi, kLongHiVReg); | 
 | 425 |   } else if (kind_lo == kDoubleLoVReg) { | 
 | 426 |     DCHECK_EQ(kind_hi, kDoubleHiVReg); | 
 | 427 |   } else { | 
 | 428 |     LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi; | 
 | 429 |     UNREACHABLE(); | 
 | 430 |   } | 
| Vladimir Marko | 439d126 | 2019-04-12 14:45:07 +0100 | [diff] [blame] | 431 |   ShadowFrame* shadow_frame = PrepareSetVReg(m, vreg, /* wide= */ true); | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 432 |   if (shadow_frame == nullptr) { | 
| Vladimir Marko | 439d126 | 2019-04-12 14:45:07 +0100 | [diff] [blame] | 433 |     return false; | 
| Mingyao Yang | 99170c6 | 2015-07-06 11:10:37 -0700 | [diff] [blame] | 434 |   } | 
 | 435 |   shadow_frame->SetVRegLong(vreg, new_value); | 
 | 436 |   return true; | 
 | 437 | } | 
 | 438 |  | 
| Sebastien Hertz | 96ba8dc | 2015-01-22 18:57:14 +0100 | [diff] [blame] | 439 | bool StackVisitor::IsAccessibleGPR(uint32_t reg) const { | 
 | 440 |   DCHECK(context_ != nullptr); | 
 | 441 |   return context_->IsAccessibleGPR(reg); | 
 | 442 | } | 
 | 443 |  | 
| Mathieu Chartier | 815873e | 2014-02-13 18:02:13 -0800 | [diff] [blame] | 444 | uintptr_t* StackVisitor::GetGPRAddress(uint32_t reg) const { | 
| Sebastien Hertz | 96ba8dc | 2015-01-22 18:57:14 +0100 | [diff] [blame] | 445 |   DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine"; | 
 | 446 |   DCHECK(context_ != nullptr); | 
| Mathieu Chartier | 815873e | 2014-02-13 18:02:13 -0800 | [diff] [blame] | 447 |   return context_->GetGPRAddress(reg); | 
 | 448 | } | 
 | 449 |  | 
| Sebastien Hertz | 96ba8dc | 2015-01-22 18:57:14 +0100 | [diff] [blame] | 450 | uintptr_t StackVisitor::GetGPR(uint32_t reg) const { | 
 | 451 |   DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine"; | 
 | 452 |   DCHECK(context_ != nullptr); | 
 | 453 |   return context_->GetGPR(reg); | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 454 | } | 
 | 455 |  | 
| Sebastien Hertz | 96ba8dc | 2015-01-22 18:57:14 +0100 | [diff] [blame] | 456 | bool StackVisitor::IsAccessibleFPR(uint32_t reg) const { | 
 | 457 |   DCHECK(context_ != nullptr); | 
 | 458 |   return context_->IsAccessibleFPR(reg); | 
| Sebastien Hertz | 0bcb290 | 2014-06-17 15:52:45 +0200 | [diff] [blame] | 459 | } | 
 | 460 |  | 
| Sebastien Hertz | 96ba8dc | 2015-01-22 18:57:14 +0100 | [diff] [blame] | 461 | uintptr_t StackVisitor::GetFPR(uint32_t reg) const { | 
 | 462 |   DCHECK(cur_quick_frame_ != nullptr) << "This is a quick frame routine"; | 
 | 463 |   DCHECK(context_ != nullptr); | 
 | 464 |   return context_->GetFPR(reg); | 
 | 465 | } | 
 | 466 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 467 | uintptr_t StackVisitor::GetReturnPc() const { | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 468 |   uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame()); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 469 |   DCHECK(sp != nullptr); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 470 |   uint8_t* pc_addr = sp + GetCurrentQuickFrameInfo().GetReturnPcOffset(); | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 471 |   return *reinterpret_cast<uintptr_t*>(pc_addr); | 
 | 472 | } | 
 | 473 |  | 
 | 474 | void StackVisitor::SetReturnPc(uintptr_t new_ret_pc) { | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 475 |   uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame()); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 476 |   CHECK(sp != nullptr); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 477 |   uint8_t* pc_addr = sp + GetCurrentQuickFrameInfo().GetReturnPcOffset(); | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 478 |   *reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc; | 
 | 479 | } | 
 | 480 |  | 
| Nicolas Geoffray | 8e5bd18 | 2015-05-06 11:34:34 +0100 | [diff] [blame] | 481 | size_t StackVisitor::ComputeNumFrames(Thread* thread, StackWalkKind walk_kind) { | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 482 |   struct NumFramesVisitor : public StackVisitor { | 
| Nicolas Geoffray | 8e5bd18 | 2015-05-06 11:34:34 +0100 | [diff] [blame] | 483 |     NumFramesVisitor(Thread* thread_in, StackWalkKind walk_kind_in) | 
 | 484 |         : StackVisitor(thread_in, nullptr, walk_kind_in), frames(0) {} | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 485 |  | 
| Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 486 |     bool VisitFrame() override { | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 487 |       frames++; | 
 | 488 |       return true; | 
 | 489 |     } | 
| Elliott Hughes | 08fc03a | 2012-06-26 17:34:00 -0700 | [diff] [blame] | 490 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 491 |     size_t frames; | 
 | 492 |   }; | 
| Nicolas Geoffray | 8e5bd18 | 2015-05-06 11:34:34 +0100 | [diff] [blame] | 493 |   NumFramesVisitor visitor(thread, walk_kind); | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 494 |   visitor.WalkStack(true); | 
 | 495 |   return visitor.frames; | 
 | 496 | } | 
 | 497 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 498 | bool StackVisitor::GetNextMethodAndDexPc(ArtMethod** next_method, uint32_t* next_dex_pc) { | 
| Ian Rogers | 5cf9819 | 2014-05-29 21:31:50 -0700 | [diff] [blame] | 499 |   struct HasMoreFramesVisitor : public StackVisitor { | 
| Nicolas Geoffray | 8e5bd18 | 2015-05-06 11:34:34 +0100 | [diff] [blame] | 500 |     HasMoreFramesVisitor(Thread* thread, | 
 | 501 |                          StackWalkKind walk_kind, | 
 | 502 |                          size_t num_frames, | 
 | 503 |                          size_t frame_height) | 
 | 504 |         : StackVisitor(thread, nullptr, walk_kind, num_frames), | 
 | 505 |           frame_height_(frame_height), | 
 | 506 |           found_frame_(false), | 
 | 507 |           has_more_frames_(false), | 
 | 508 |           next_method_(nullptr), | 
 | 509 |           next_dex_pc_(0) { | 
| Ian Rogers | 5cf9819 | 2014-05-29 21:31:50 -0700 | [diff] [blame] | 510 |     } | 
 | 511 |  | 
| Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 512 |     bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) { | 
| Ian Rogers | 5cf9819 | 2014-05-29 21:31:50 -0700 | [diff] [blame] | 513 |       if (found_frame_) { | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 514 |         ArtMethod* method = GetMethod(); | 
| Ian Rogers | 5cf9819 | 2014-05-29 21:31:50 -0700 | [diff] [blame] | 515 |         if (method != nullptr && !method->IsRuntimeMethod()) { | 
 | 516 |           has_more_frames_ = true; | 
 | 517 |           next_method_ = method; | 
 | 518 |           next_dex_pc_ = GetDexPc(); | 
 | 519 |           return false;  // End stack walk once next method is found. | 
 | 520 |         } | 
 | 521 |       } else if (GetFrameHeight() == frame_height_) { | 
 | 522 |         found_frame_ = true; | 
 | 523 |       } | 
 | 524 |       return true; | 
 | 525 |     } | 
 | 526 |  | 
 | 527 |     size_t frame_height_; | 
 | 528 |     bool found_frame_; | 
 | 529 |     bool has_more_frames_; | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 530 |     ArtMethod* next_method_; | 
| Ian Rogers | 5cf9819 | 2014-05-29 21:31:50 -0700 | [diff] [blame] | 531 |     uint32_t next_dex_pc_; | 
 | 532 |   }; | 
| Nicolas Geoffray | 8e5bd18 | 2015-05-06 11:34:34 +0100 | [diff] [blame] | 533 |   HasMoreFramesVisitor visitor(thread_, walk_kind_, GetNumFrames(), GetFrameHeight()); | 
| Ian Rogers | 5cf9819 | 2014-05-29 21:31:50 -0700 | [diff] [blame] | 534 |   visitor.WalkStack(true); | 
 | 535 |   *next_method = visitor.next_method_; | 
 | 536 |   *next_dex_pc = visitor.next_dex_pc_; | 
 | 537 |   return visitor.has_more_frames_; | 
 | 538 | } | 
 | 539 |  | 
| Ian Rogers | 7a22fa6 | 2013-01-23 12:16:16 -0800 | [diff] [blame] | 540 | void StackVisitor::DescribeStack(Thread* thread) { | 
| Ian Rogers | 306057f | 2012-11-26 12:45:53 -0800 | [diff] [blame] | 541 |   struct DescribeStackVisitor : public StackVisitor { | 
| Andreas Gampe | 277ccbd | 2014-11-03 21:36:10 -0800 | [diff] [blame] | 542 |     explicit DescribeStackVisitor(Thread* thread_in) | 
| Nicolas Geoffray | 8e5bd18 | 2015-05-06 11:34:34 +0100 | [diff] [blame] | 543 |         : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {} | 
| Ian Rogers | 306057f | 2012-11-26 12:45:53 -0800 | [diff] [blame] | 544 |  | 
| Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 545 |     bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) { | 
| Ian Rogers | 306057f | 2012-11-26 12:45:53 -0800 | [diff] [blame] | 546 |       LOG(INFO) << "Frame Id=" << GetFrameId() << " " << DescribeLocation(); | 
 | 547 |       return true; | 
 | 548 |     } | 
 | 549 |   }; | 
| Ian Rogers | 7a22fa6 | 2013-01-23 12:16:16 -0800 | [diff] [blame] | 550 |   DescribeStackVisitor visitor(thread); | 
| Ian Rogers | 306057f | 2012-11-26 12:45:53 -0800 | [diff] [blame] | 551 |   visitor.WalkStack(true); | 
 | 552 | } | 
 | 553 |  | 
| Ian Rogers | 40e3bac | 2012-11-20 00:09:14 -0800 | [diff] [blame] | 554 | std::string StackVisitor::DescribeLocation() const { | 
 | 555 |   std::string result("Visiting method '"); | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 556 |   ArtMethod* m = GetMethod(); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 557 |   if (m == nullptr) { | 
| Ian Rogers | 306057f | 2012-11-26 12:45:53 -0800 | [diff] [blame] | 558 |     return "upcall"; | 
 | 559 |   } | 
| David Sehr | 709b070 | 2016-10-13 09:12:37 -0700 | [diff] [blame] | 560 |   result += m->PrettyMethod(); | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 561 |   result += StringPrintf("' at dex PC 0x%04x", GetDexPc()); | 
| Ian Rogers | 40e3bac | 2012-11-20 00:09:14 -0800 | [diff] [blame] | 562 |   if (!IsShadowFrame()) { | 
 | 563 |     result += StringPrintf(" (native PC %p)", reinterpret_cast<void*>(GetCurrentQuickFramePc())); | 
 | 564 |   } | 
 | 565 |   return result; | 
 | 566 | } | 
 | 567 |  | 
| Alex Light | dba6148 | 2016-12-21 08:20:29 -0800 | [diff] [blame] | 568 | void StackVisitor::SetMethod(ArtMethod* method) { | 
 | 569 |   DCHECK(GetMethod() != nullptr); | 
 | 570 |   if (cur_shadow_frame_ != nullptr) { | 
 | 571 |     cur_shadow_frame_->SetMethod(method); | 
 | 572 |   } else { | 
 | 573 |     DCHECK(cur_quick_frame_ != nullptr); | 
| Nicolas Geoffray | 226805d | 2018-12-14 10:59:02 +0000 | [diff] [blame] | 574 |     CHECK(!IsInInlinedFrame()) << "We do not support setting inlined method's ArtMethod: " | 
 | 575 |                                << GetMethod()->PrettyMethod() << " is inlined into " | 
 | 576 |                                << GetOuterMethod()->PrettyMethod(); | 
| Alex Light | 1ebe4fe | 2017-01-30 14:57:11 -0800 | [diff] [blame] | 577 |     *cur_quick_frame_ = method; | 
| Alex Light | dba6148 | 2016-12-21 08:20:29 -0800 | [diff] [blame] | 578 |   } | 
 | 579 | } | 
 | 580 |  | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 581 | static void AssertPcIsWithinQuickCode(ArtMethod* method, uintptr_t pc) | 
| Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 582 |     REQUIRES_SHARED(Locks::mutator_lock_) { | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 583 |   if (method->IsNative() || method->IsRuntimeMethod() || method->IsProxyMethod()) { | 
 | 584 |     return; | 
 | 585 |   } | 
 | 586 |  | 
 | 587 |   if (pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) { | 
 | 588 |     return; | 
 | 589 |   } | 
 | 590 |  | 
| Mingyao Yang | 88ca8ba | 2017-05-23 14:21:07 -0700 | [diff] [blame] | 591 |   Runtime* runtime = Runtime::Current(); | 
 | 592 |   if (runtime->UseJitCompilation() && | 
 | 593 |       runtime->GetJit()->GetCodeCache()->ContainsPc(reinterpret_cast<const void*>(pc))) { | 
 | 594 |     return; | 
 | 595 |   } | 
 | 596 |  | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 597 |   const void* code = method->GetEntryPointFromQuickCompiledCode(); | 
| Alex Light | db01a09 | 2017-04-03 15:39:55 -0700 | [diff] [blame] | 598 |   if (code == GetQuickInstrumentationEntryPoint() || code == GetInvokeObsoleteMethodStub()) { | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 599 |     return; | 
 | 600 |   } | 
 | 601 |  | 
 | 602 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 603 |   if (class_linker->IsQuickToInterpreterBridge(code) || | 
 | 604 |       class_linker->IsQuickResolutionStub(code)) { | 
 | 605 |     return; | 
 | 606 |   } | 
 | 607 |  | 
| Calin Juravle | ffc8707 | 2016-04-20 14:22:09 +0100 | [diff] [blame] | 608 |   if (runtime->UseJitCompilation() && runtime->GetJit()->GetCodeCache()->ContainsPc(code)) { | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 609 |     return; | 
 | 610 |   } | 
 | 611 |  | 
| Mingyao Yang | 063fc77 | 2016-08-02 11:02:54 -0700 | [diff] [blame] | 612 |   uint32_t code_size = OatQuickMethodHeader::FromEntryPoint(code)->GetCodeSize(); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 613 |   uintptr_t code_start = reinterpret_cast<uintptr_t>(code); | 
 | 614 |   CHECK(code_start <= pc && pc <= (code_start + code_size)) | 
| David Sehr | 709b070 | 2016-10-13 09:12:37 -0700 | [diff] [blame] | 615 |       << method->PrettyMethod() | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 616 |       << " pc=" << std::hex << pc | 
| Roland Levillain | 0d5a281 | 2015-11-13 10:07:31 +0000 | [diff] [blame] | 617 |       << " code_start=" << code_start | 
 | 618 |       << " code_size=" << code_size; | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 619 | } | 
 | 620 |  | 
| Ian Rogers | 00f7d0e | 2012-07-19 15:28:27 -0700 | [diff] [blame] | 621 | void StackVisitor::SanityCheckFrame() const { | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 622 |   if (kIsDebugBuild) { | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 623 |     ArtMethod* method = GetMethod(); | 
| Vladimir Marko | d93e374 | 2018-07-18 10:58:13 +0100 | [diff] [blame] | 624 |     ObjPtr<mirror::Class> declaring_class = method->GetDeclaringClass(); | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 625 |     // Runtime methods have null declaring class. | 
 | 626 |     if (!method->IsRuntimeMethod()) { | 
 | 627 |       CHECK(declaring_class != nullptr); | 
 | 628 |       CHECK_EQ(declaring_class->GetClass(), declaring_class->GetClass()->GetClass()) | 
 | 629 |           << declaring_class; | 
 | 630 |     } else { | 
 | 631 |       CHECK(declaring_class == nullptr); | 
 | 632 |     } | 
| Mathieu Chartier | 951ec2c | 2015-09-22 08:50:05 -0700 | [diff] [blame] | 633 |     Runtime* const runtime = Runtime::Current(); | 
 | 634 |     LinearAlloc* const linear_alloc = runtime->GetLinearAlloc(); | 
 | 635 |     if (!linear_alloc->Contains(method)) { | 
 | 636 |       // Check class linker linear allocs. | 
| Nicolas Geoffray | 48b40cc | 2017-08-07 16:52:40 +0100 | [diff] [blame] | 637 |       // We get the canonical method as copied methods may have their declaring | 
 | 638 |       // class from another class loader. | 
 | 639 |       ArtMethod* canonical = method->GetCanonicalMethod(); | 
| Vladimir Marko | d93e374 | 2018-07-18 10:58:13 +0100 | [diff] [blame] | 640 |       ObjPtr<mirror::Class> klass = canonical->GetDeclaringClass(); | 
| Mathieu Chartier | 951ec2c | 2015-09-22 08:50:05 -0700 | [diff] [blame] | 641 |       LinearAlloc* const class_linear_alloc = (klass != nullptr) | 
| Mathieu Chartier | 5b83050 | 2016-03-02 10:30:23 -0800 | [diff] [blame] | 642 |           ? runtime->GetClassLinker()->GetAllocatorForClassLoader(klass->GetClassLoader()) | 
| Mathieu Chartier | 951ec2c | 2015-09-22 08:50:05 -0700 | [diff] [blame] | 643 |           : linear_alloc; | 
| Nicolas Geoffray | 48b40cc | 2017-08-07 16:52:40 +0100 | [diff] [blame] | 644 |       if (!class_linear_alloc->Contains(canonical)) { | 
| Mathieu Chartier | 951ec2c | 2015-09-22 08:50:05 -0700 | [diff] [blame] | 645 |         // Check image space. | 
 | 646 |         bool in_image = false; | 
 | 647 |         for (auto& space : runtime->GetHeap()->GetContinuousSpaces()) { | 
 | 648 |           if (space->IsImageSpace()) { | 
 | 649 |             auto* image_space = space->AsImageSpace(); | 
 | 650 |             const auto& header = image_space->GetImageHeader(); | 
| Mathieu Chartier | e42888f | 2016-04-14 10:49:19 -0700 | [diff] [blame] | 651 |             const ImageSection& methods = header.GetMethodsSection(); | 
 | 652 |             const ImageSection& runtime_methods = header.GetRuntimeMethodsSection(); | 
| Nicolas Geoffray | 48b40cc | 2017-08-07 16:52:40 +0100 | [diff] [blame] | 653 |             const size_t offset =  reinterpret_cast<const uint8_t*>(canonical) - image_space->Begin(); | 
| Mathieu Chartier | e42888f | 2016-04-14 10:49:19 -0700 | [diff] [blame] | 654 |             if (methods.Contains(offset) || runtime_methods.Contains(offset)) { | 
| Mathieu Chartier | 951ec2c | 2015-09-22 08:50:05 -0700 | [diff] [blame] | 655 |               in_image = true; | 
 | 656 |               break; | 
 | 657 |             } | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 658 |           } | 
 | 659 |         } | 
| Nicolas Geoffray | 48b40cc | 2017-08-07 16:52:40 +0100 | [diff] [blame] | 660 |         CHECK(in_image) << canonical->PrettyMethod() << " not in linear alloc or image"; | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 661 |       } | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 662 |     } | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 663 |     if (cur_quick_frame_ != nullptr) { | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 664 |       AssertPcIsWithinQuickCode(method, cur_quick_frame_pc_); | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 665 |       // Frame sanity. | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 666 |       size_t frame_size = GetCurrentQuickFrameInfo().FrameSizeInBytes(); | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 667 |       CHECK_NE(frame_size, 0u); | 
| Andreas Gampe | 5b417b9 | 2014-03-10 14:18:35 -0700 | [diff] [blame] | 668 |       // A rough guess at an upper size we expect to see for a frame. | 
 | 669 |       // 256 registers | 
| Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 670 |       // 2 words HandleScope overhead | 
| Andreas Gampe | 5b417b9 | 2014-03-10 14:18:35 -0700 | [diff] [blame] | 671 |       // 3+3 register spills | 
 | 672 |       // TODO: this seems architecture specific for the case of JNI frames. | 
| Brian Carlstrom | ed08bd4 | 2014-03-19 18:34:17 -0700 | [diff] [blame] | 673 |       // TODO: 083-compiler-regressions ManyFloatArgs shows this estimate is wrong. | 
 | 674 |       // const size_t kMaxExpectedFrameSize = (256 + 2 + 3 + 3) * sizeof(word); | 
 | 675 |       const size_t kMaxExpectedFrameSize = 2 * KB; | 
| David Sehr | 709b070 | 2016-10-13 09:12:37 -0700 | [diff] [blame] | 676 |       CHECK_LE(frame_size, kMaxExpectedFrameSize) << method->PrettyMethod(); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 677 |       size_t return_pc_offset = GetCurrentQuickFrameInfo().GetReturnPcOffset(); | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 678 |       CHECK_LT(return_pc_offset, frame_size); | 
 | 679 |     } | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 680 |   } | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 681 | } | 
 | 682 |  | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 683 | // Counts the number of references in the parameter list of the corresponding method. | 
 | 684 | // Note: Thus does _not_ include "this" for non-static methods. | 
 | 685 | static uint32_t GetNumberOfReferenceArgsWithoutReceiver(ArtMethod* method) | 
| Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 686 |     REQUIRES_SHARED(Locks::mutator_lock_) { | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 687 |   uint32_t shorty_len; | 
 | 688 |   const char* shorty = method->GetShorty(&shorty_len); | 
 | 689 |   uint32_t refs = 0; | 
 | 690 |   for (uint32_t i = 1; i < shorty_len ; ++i) { | 
 | 691 |     if (shorty[i] == 'L') { | 
 | 692 |       refs++; | 
 | 693 |     } | 
 | 694 |   } | 
 | 695 |   return refs; | 
 | 696 | } | 
 | 697 |  | 
 | 698 | QuickMethodFrameInfo StackVisitor::GetCurrentQuickFrameInfo() const { | 
 | 699 |   if (cur_oat_quick_method_header_ != nullptr) { | 
 | 700 |     return cur_oat_quick_method_header_->GetFrameInfo(); | 
 | 701 |   } | 
 | 702 |  | 
 | 703 |   ArtMethod* method = GetMethod(); | 
 | 704 |   Runtime* runtime = Runtime::Current(); | 
 | 705 |  | 
 | 706 |   if (method->IsAbstract()) { | 
| Vladimir Marko | d3083dd | 2018-05-17 08:43:47 +0100 | [diff] [blame] | 707 |     return RuntimeCalleeSaveFrame::GetMethodFrameInfo(CalleeSaveType::kSaveRefsAndArgs); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 708 |   } | 
 | 709 |  | 
 | 710 |   // This goes before IsProxyMethod since runtime methods have a null declaring class. | 
 | 711 |   if (method->IsRuntimeMethod()) { | 
 | 712 |     return runtime->GetRuntimeMethodFrameInfo(method); | 
 | 713 |   } | 
 | 714 |  | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 715 |   if (method->IsProxyMethod()) { | 
| Nicolas Geoffray | 22cf3d3 | 2015-11-02 11:57:11 +0000 | [diff] [blame] | 716 |     // There is only one direct method of a proxy class: the constructor. A direct method is | 
 | 717 |     // cloned from the original java.lang.reflect.Proxy and is executed as usual quick | 
 | 718 |     // compiled method without any stubs. Therefore the method must have a OatQuickMethodHeader. | 
 | 719 |     DCHECK(!method->IsDirect() && !method->IsConstructor()) | 
 | 720 |         << "Constructors of proxy classes must have a OatQuickMethodHeader"; | 
| Vladimir Marko | d3083dd | 2018-05-17 08:43:47 +0100 | [diff] [blame] | 721 |     return RuntimeCalleeSaveFrame::GetMethodFrameInfo(CalleeSaveType::kSaveRefsAndArgs); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 722 |   } | 
 | 723 |  | 
| Vladimir Marko | 2196c65 | 2017-11-30 16:16:07 +0000 | [diff] [blame] | 724 |   // The only remaining case is if the method is native and uses the generic JNI stub, | 
 | 725 |   // called either directly or through some (resolution, instrumentation) trampoline. | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 726 |   DCHECK(method->IsNative()); | 
| Vladimir Marko | 2196c65 | 2017-11-30 16:16:07 +0000 | [diff] [blame] | 727 |   if (kIsDebugBuild) { | 
 | 728 |     ClassLinker* class_linker = runtime->GetClassLinker(); | 
 | 729 |     const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(method, | 
 | 730 |                                                                              kRuntimePointerSize); | 
 | 731 |     CHECK(class_linker->IsQuickGenericJniStub(entry_point) || | 
 | 732 |           // The current entrypoint (after filtering out trampolines) may have changed | 
 | 733 |           // from GenericJNI to JIT-compiled stub since we have entered this frame. | 
 | 734 |           (runtime->GetJit() != nullptr && | 
 | 735 |            runtime->GetJit()->GetCodeCache()->ContainsPc(entry_point))) << method->PrettyMethod(); | 
 | 736 |   } | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 737 |   // Generic JNI frame. | 
 | 738 |   uint32_t handle_refs = GetNumberOfReferenceArgsWithoutReceiver(method) + 1; | 
 | 739 |   size_t scope_size = HandleScope::SizeOf(handle_refs); | 
| Vladimir Marko | d3083dd | 2018-05-17 08:43:47 +0100 | [diff] [blame] | 740 |   constexpr QuickMethodFrameInfo callee_info = | 
 | 741 |       RuntimeCalleeSaveFrame::GetMethodFrameInfo(CalleeSaveType::kSaveRefsAndArgs); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 742 |  | 
 | 743 |   // Callee saves + handle scope + method ref + alignment | 
 | 744 |   // Note: -sizeof(void*) since callee-save frame stores a whole method pointer. | 
 | 745 |   size_t frame_size = RoundUp( | 
 | 746 |       callee_info.FrameSizeInBytes() - sizeof(void*) + sizeof(ArtMethod*) + scope_size, | 
 | 747 |       kStackAlignment); | 
 | 748 |   return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask()); | 
 | 749 | } | 
 | 750 |  | 
| Andreas Gampe | 585da95 | 2016-12-02 14:52:29 -0800 | [diff] [blame] | 751 | template <StackVisitor::CountTransitions kCount> | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 752 | void StackVisitor::WalkStack(bool include_transitions) { | 
| Hiroshi Yamauchi | 02f365f | 2017-02-03 15:06:00 -0800 | [diff] [blame] | 753 |   if (check_suspended_) { | 
 | 754 |     DCHECK(thread_ == Thread::Current() || thread_->IsSuspended()); | 
 | 755 |   } | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 756 |   CHECK_EQ(cur_depth_, 0U); | 
 | 757 |   bool exit_stubs_installed = Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled(); | 
| Alex Light | b81a984 | 2016-12-15 00:59:05 +0000 | [diff] [blame] | 758 |   uint32_t instrumentation_stack_depth = 0; | 
| Sebastien Hertz | b2feaaf | 2015-10-12 13:40:10 +0000 | [diff] [blame] | 759 |   size_t inlined_frames_count = 0; | 
| Dave Allison | f943914 | 2014-03-27 15:10:22 -0700 | [diff] [blame] | 760 |  | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 761 |   for (const ManagedStack* current_fragment = thread_->GetManagedStack(); | 
 | 762 |        current_fragment != nullptr; current_fragment = current_fragment->GetLink()) { | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 763 |     cur_shadow_frame_ = current_fragment->GetTopShadowFrame(); | 
 | 764 |     cur_quick_frame_ = current_fragment->GetTopQuickFrame(); | 
| Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 765 |     cur_quick_frame_pc_ = 0; | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 766 |     cur_oat_quick_method_header_ = nullptr; | 
| Dave Allison | f943914 | 2014-03-27 15:10:22 -0700 | [diff] [blame] | 767 |  | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 768 |     if (cur_quick_frame_ != nullptr) {  // Handle quick stack frames. | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 769 |       // Can't be both a shadow and a quick fragment. | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 770 |       DCHECK(current_fragment->GetTopShadowFrame() == nullptr); | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 771 |       ArtMethod* method = *cur_quick_frame_; | 
| Vladimir Marko | 2196c65 | 2017-11-30 16:16:07 +0000 | [diff] [blame] | 772 |       DCHECK(method != nullptr); | 
 | 773 |       bool header_retrieved = false; | 
 | 774 |       if (method->IsNative()) { | 
 | 775 |         // We do not have a PC for the first frame, so we cannot simply use | 
 | 776 |         // ArtMethod::GetOatQuickMethodHeader() as we're unable to distinguish there | 
 | 777 |         // between GenericJNI frame and JIT-compiled JNI stub; the entrypoint may have | 
 | 778 |         // changed since the frame was entered. The top quick frame tag indicates | 
 | 779 |         // GenericJNI here, otherwise it's either AOT-compiled or JNI-compiled JNI stub. | 
 | 780 |         if (UNLIKELY(current_fragment->GetTopQuickFrameTag())) { | 
 | 781 |           // The generic JNI does not have any method header. | 
 | 782 |           cur_oat_quick_method_header_ = nullptr; | 
 | 783 |         } else { | 
 | 784 |           const void* existing_entry_point = method->GetEntryPointFromQuickCompiledCode(); | 
 | 785 |           CHECK(existing_entry_point != nullptr); | 
 | 786 |           Runtime* runtime = Runtime::Current(); | 
 | 787 |           ClassLinker* class_linker = runtime->GetClassLinker(); | 
 | 788 |           // Check whether we can quickly get the header from the current entrypoint. | 
 | 789 |           if (!class_linker->IsQuickGenericJniStub(existing_entry_point) && | 
 | 790 |               !class_linker->IsQuickResolutionStub(existing_entry_point) && | 
 | 791 |               existing_entry_point != GetQuickInstrumentationEntryPoint()) { | 
 | 792 |             cur_oat_quick_method_header_ = | 
 | 793 |                 OatQuickMethodHeader::FromEntryPoint(existing_entry_point); | 
 | 794 |           } else { | 
 | 795 |             const void* code = method->GetOatMethodQuickCode(class_linker->GetImagePointerSize()); | 
 | 796 |             if (code != nullptr) { | 
 | 797 |               cur_oat_quick_method_header_ = OatQuickMethodHeader::FromEntryPoint(code); | 
 | 798 |             } else { | 
 | 799 |               // This must be a JITted JNI stub frame. | 
 | 800 |               CHECK(runtime->GetJit() != nullptr); | 
 | 801 |               code = runtime->GetJit()->GetCodeCache()->GetJniStubCode(method); | 
 | 802 |               CHECK(code != nullptr) << method->PrettyMethod(); | 
 | 803 |               cur_oat_quick_method_header_ = OatQuickMethodHeader::FromCodePointer(code); | 
 | 804 |             } | 
 | 805 |           } | 
 | 806 |         } | 
 | 807 |         header_retrieved = true; | 
 | 808 |       } | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 809 |       while (method != nullptr) { | 
| Vladimir Marko | 2196c65 | 2017-11-30 16:16:07 +0000 | [diff] [blame] | 810 |         if (!header_retrieved) { | 
 | 811 |           cur_oat_quick_method_header_ = method->GetOatQuickMethodHeader(cur_quick_frame_pc_); | 
 | 812 |         } | 
 | 813 |         header_retrieved = false;  // Force header retrieval in next iteration. | 
| Dave Allison | 5cd3375 | 2014-04-15 15:57:58 -0700 | [diff] [blame] | 814 |         SanityCheckFrame(); | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 815 |  | 
| Nicolas Geoffray | c6df1e3 | 2016-07-04 10:15:47 +0100 | [diff] [blame] | 816 |         if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames) | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 817 |             && (cur_oat_quick_method_header_ != nullptr) | 
| David Srbecky | afc97bc | 2018-07-05 08:14:35 +0000 | [diff] [blame] | 818 |             && cur_oat_quick_method_header_->IsOptimized() | 
 | 819 |             // JNI methods cannot have any inlined frames. | 
 | 820 |             && !method->IsNative()) { | 
 | 821 |           DCHECK_NE(cur_quick_frame_pc_, 0u); | 
| David Srbecky | 2259f1c | 2019-01-16 23:18:30 +0000 | [diff] [blame] | 822 |           current_code_info_ = CodeInfo(cur_oat_quick_method_header_, | 
 | 823 |                                         CodeInfo::DecodeFlags::InlineInfoOnly); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 824 |           uint32_t native_pc_offset = | 
 | 825 |               cur_oat_quick_method_header_->NativeQuickPcOffset(cur_quick_frame_pc_); | 
| David Srbecky | 2259f1c | 2019-01-16 23:18:30 +0000 | [diff] [blame] | 826 |           StackMap stack_map = current_code_info_.GetStackMapForNativePcOffset(native_pc_offset); | 
| David Srbecky | 052f8ca | 2018-04-26 15:42:54 +0100 | [diff] [blame] | 827 |           if (stack_map.IsValid() && stack_map.HasInlineInfo()) { | 
| David Srbecky | 93bd361 | 2018-07-02 19:30:18 +0100 | [diff] [blame] | 828 |             DCHECK_EQ(current_inline_frames_.size(), 0u); | 
| David Srbecky | 2259f1c | 2019-01-16 23:18:30 +0000 | [diff] [blame] | 829 |             for (current_inline_frames_ = current_code_info_.GetInlineInfosOf(stack_map); | 
| David Srbecky | 93bd361 | 2018-07-02 19:30:18 +0100 | [diff] [blame] | 830 |                  !current_inline_frames_.empty(); | 
 | 831 |                  current_inline_frames_.pop_back()) { | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 832 |               bool should_continue = VisitFrame(); | 
 | 833 |               if (UNLIKELY(!should_continue)) { | 
 | 834 |                 return; | 
 | 835 |               } | 
| Nicolas Geoffray | d23eeef | 2015-05-18 22:31:29 +0100 | [diff] [blame] | 836 |               cur_depth_++; | 
| Sebastien Hertz | b2feaaf | 2015-10-12 13:40:10 +0000 | [diff] [blame] | 837 |               inlined_frames_count++; | 
| Nicolas Geoffray | 57f6161 | 2015-05-15 13:20:41 +0100 | [diff] [blame] | 838 |             } | 
 | 839 |           } | 
 | 840 |         } | 
 | 841 |  | 
| Dave Allison | 5cd3375 | 2014-04-15 15:57:58 -0700 | [diff] [blame] | 842 |         bool should_continue = VisitFrame(); | 
 | 843 |         if (UNLIKELY(!should_continue)) { | 
 | 844 |           return; | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 845 |         } | 
| Dave Allison | 5cd3375 | 2014-04-15 15:57:58 -0700 | [diff] [blame] | 846 |  | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 847 |         QuickMethodFrameInfo frame_info = GetCurrentQuickFrameInfo(); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 848 |         if (context_ != nullptr) { | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 849 |           context_->FillCalleeSaves(reinterpret_cast<uint8_t*>(cur_quick_frame_), frame_info); | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 850 |         } | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 851 |         // Compute PC for next stack frame from return PC. | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 852 |         size_t frame_size = frame_info.FrameSizeInBytes(); | 
 | 853 |         size_t return_pc_offset = frame_size - sizeof(void*); | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 854 |         uint8_t* return_pc_addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + return_pc_offset; | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 855 |         uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr); | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 856 |  | 
| Alex Light | b32c6a9 | 2018-06-07 16:48:04 -0700 | [diff] [blame] | 857 |         if (UNLIKELY(exit_stubs_installed || | 
 | 858 |                      reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == return_pc)) { | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 859 |           // While profiling, the return pc is restored from the side stack, except when walking | 
 | 860 |           // the stack for an exception where the side stack will be unwound in VisitFrame. | 
| Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 861 |           if (reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == return_pc) { | 
| Andreas Gampe | 585da95 | 2016-12-02 14:52:29 -0800 | [diff] [blame] | 862 |             CHECK_LT(instrumentation_stack_depth, thread_->GetInstrumentationStack()->size()); | 
| Sebastien Hertz | 74e256b | 2013-10-04 10:40:37 +0200 | [diff] [blame] | 863 |             const instrumentation::InstrumentationStackFrame& instrumentation_frame = | 
| Vladimir Marko | 35d5b8a | 2018-07-03 09:18:32 +0100 | [diff] [blame] | 864 |                 (*thread_->GetInstrumentationStack())[instrumentation_stack_depth]; | 
| jeffhao | 725a957 | 2012-11-13 18:20:12 -0800 | [diff] [blame] | 865 |             instrumentation_stack_depth++; | 
| Vladimir Marko | fd36f1f | 2016-08-03 18:49:58 +0100 | [diff] [blame] | 866 |             if (GetMethod() == | 
| Andreas Gampe | 8228cdf | 2017-05-30 15:03:54 -0700 | [diff] [blame] | 867 |                 Runtime::Current()->GetCalleeSaveMethod(CalleeSaveType::kSaveAllCalleeSaves)) { | 
| Jeff Hao | fb2802d | 2013-07-24 13:53:05 -0700 | [diff] [blame] | 868 |               // Skip runtime save all callee frames which are used to deliver exceptions. | 
 | 869 |             } else if (instrumentation_frame.interpreter_entry_) { | 
| Vladimir Marko | fd36f1f | 2016-08-03 18:49:58 +0100 | [diff] [blame] | 870 |               ArtMethod* callee = | 
| Andreas Gampe | 8228cdf | 2017-05-30 15:03:54 -0700 | [diff] [blame] | 871 |                   Runtime::Current()->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs); | 
| David Sehr | 709b070 | 2016-10-13 09:12:37 -0700 | [diff] [blame] | 872 |               CHECK_EQ(GetMethod(), callee) << "Expected: " << ArtMethod::PrettyMethod(callee) | 
 | 873 |                                             << " Found: " << ArtMethod::PrettyMethod(GetMethod()); | 
| Sebastien Hertz | b2feaaf | 2015-10-12 13:40:10 +0000 | [diff] [blame] | 874 |             } else { | 
| Alex Light | eee0bd4 | 2017-02-14 15:31:45 +0000 | [diff] [blame] | 875 |               // Instrumentation generally doesn't distinguish between a method's obsolete and | 
 | 876 |               // non-obsolete version. | 
 | 877 |               CHECK_EQ(instrumentation_frame.method_->GetNonObsoleteMethod(), | 
 | 878 |                        GetMethod()->GetNonObsoleteMethod()) | 
 | 879 |                   << "Expected: " | 
 | 880 |                   << ArtMethod::PrettyMethod(instrumentation_frame.method_->GetNonObsoleteMethod()) | 
 | 881 |                   << " Found: " << ArtMethod::PrettyMethod(GetMethod()->GetNonObsoleteMethod()); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 882 |             } | 
 | 883 |             if (num_frames_ != 0) { | 
 | 884 |               // Check agreement of frame Ids only if num_frames_ is computed to avoid infinite | 
 | 885 |               // recursion. | 
| Sebastien Hertz | b2feaaf | 2015-10-12 13:40:10 +0000 | [diff] [blame] | 886 |               size_t frame_id = instrumentation::Instrumentation::ComputeFrameId( | 
 | 887 |                   thread_, | 
 | 888 |                   cur_depth_, | 
 | 889 |                   inlined_frames_count); | 
 | 890 |               CHECK_EQ(instrumentation_frame.frame_id_, frame_id); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 891 |             } | 
| jeffhao | 725a957 | 2012-11-13 18:20:12 -0800 | [diff] [blame] | 892 |             return_pc = instrumentation_frame.return_pc_; | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 893 |           } | 
 | 894 |         } | 
| Nicolas Geoffray | 6bc4374 | 2015-10-12 18:11:10 +0100 | [diff] [blame] | 895 |  | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 896 |         cur_quick_frame_pc_ = return_pc; | 
| Ian Rogers | 1373595 | 2014-10-08 12:43:28 -0700 | [diff] [blame] | 897 |         uint8_t* next_frame = reinterpret_cast<uint8_t*>(cur_quick_frame_) + frame_size; | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 898 |         cur_quick_frame_ = reinterpret_cast<ArtMethod**>(next_frame); | 
 | 899 |  | 
 | 900 |         if (kDebugStackWalk) { | 
| David Sehr | 709b070 | 2016-10-13 09:12:37 -0700 | [diff] [blame] | 901 |           LOG(INFO) << ArtMethod::PrettyMethod(method) << "@" << method << " size=" << frame_size | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 902 |               << std::boolalpha | 
 | 903 |               << " optimized=" << (cur_oat_quick_method_header_ != nullptr && | 
 | 904 |                                    cur_oat_quick_method_header_->IsOptimized()) | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 905 |               << " native=" << method->IsNative() | 
| Nicolas Geoffray | 524e7ea | 2015-10-16 17:13:34 +0100 | [diff] [blame] | 906 |               << std::noboolalpha | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 907 |               << " entrypoints=" << method->GetEntryPointFromQuickCompiledCode() | 
| Alex Light | eee0bd4 | 2017-02-14 15:31:45 +0000 | [diff] [blame] | 908 |               << "," << (method->IsNative() ? method->GetEntryPointFromJni() : nullptr) | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 909 |               << " next=" << *cur_quick_frame_; | 
 | 910 |         } | 
 | 911 |  | 
| Andreas Gampe | f040be6 | 2017-04-14 21:49:33 -0700 | [diff] [blame] | 912 |         if (kCount == CountTransitions::kYes || !method->IsRuntimeMethod()) { | 
 | 913 |           cur_depth_++; | 
 | 914 |         } | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 915 |         method = *cur_quick_frame_; | 
| jeffhao | 6641ea1 | 2013-01-02 18:13:42 -0800 | [diff] [blame] | 916 |       } | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 917 |     } else if (cur_shadow_frame_ != nullptr) { | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 918 |       do { | 
 | 919 |         SanityCheckFrame(); | 
 | 920 |         bool should_continue = VisitFrame(); | 
 | 921 |         if (UNLIKELY(!should_continue)) { | 
 | 922 |           return; | 
 | 923 |         } | 
 | 924 |         cur_depth_++; | 
 | 925 |         cur_shadow_frame_ = cur_shadow_frame_->GetLink(); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 926 |       } while (cur_shadow_frame_ != nullptr); | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 927 |     } | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 928 |     if (include_transitions) { | 
 | 929 |       bool should_continue = VisitFrame(); | 
 | 930 |       if (!should_continue) { | 
 | 931 |         return; | 
 | 932 |       } | 
 | 933 |     } | 
| Andreas Gampe | 585da95 | 2016-12-02 14:52:29 -0800 | [diff] [blame] | 934 |     if (kCount == CountTransitions::kYes) { | 
 | 935 |       cur_depth_++; | 
 | 936 |     } | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 937 |   } | 
 | 938 |   if (num_frames_ != 0) { | 
 | 939 |     CHECK_EQ(cur_depth_, num_frames_); | 
| Ian Rogers | 0399dde | 2012-06-06 17:09:28 -0700 | [diff] [blame] | 940 |   } | 
 | 941 | } | 
 | 942 |  | 
| Andreas Gampe | 585da95 | 2016-12-02 14:52:29 -0800 | [diff] [blame] | 943 | template void StackVisitor::WalkStack<StackVisitor::CountTransitions::kYes>(bool); | 
 | 944 | template void StackVisitor::WalkStack<StackVisitor::CountTransitions::kNo>(bool); | 
 | 945 |  | 
| Elliott Hughes | 68e7652 | 2011-10-05 13:22:16 -0700 | [diff] [blame] | 946 | }  // namespace art |