Home | History | Annotate | Download | only in runtime
      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 
     19 #include "arch/context.h"
     20 #include "base/hex_dump.h"
     21 #include "mirror/art_method-inl.h"
     22 #include "mirror/class-inl.h"
     23 #include "mirror/object.h"
     24 #include "mirror/object-inl.h"
     25 #include "mirror/object_array-inl.h"
     26 #include "quick/quick_method_frame_info.h"
     27 #include "runtime.h"
     28 #include "thread.h"
     29 #include "thread_list.h"
     30 #include "throw_location.h"
     31 #include "verify_object-inl.h"
     32 #include "vmap_table.h"
     33 
     34 namespace art {
     35 
     36 mirror::Object* ShadowFrame::GetThisObject() const {
     37   mirror::ArtMethod* m = GetMethod();
     38   if (m->IsStatic()) {
     39     return NULL;
     40   } else if (m->IsNative()) {
     41     return GetVRegReference(0);
     42   } else {
     43     const DexFile::CodeItem* code_item = m->GetCodeItem();
     44     CHECK(code_item != NULL) << PrettyMethod(m);
     45     uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
     46     return GetVRegReference(reg);
     47   }
     48 }
     49 
     50 mirror::Object* ShadowFrame::GetThisObject(uint16_t num_ins) const {
     51   mirror::ArtMethod* m = GetMethod();
     52   if (m->IsStatic()) {
     53     return NULL;
     54   } else {
     55     return GetVRegReference(NumberOfVRegs() - num_ins);
     56   }
     57 }
     58 
     59 ThrowLocation ShadowFrame::GetCurrentLocationForThrow() const {
     60   return ThrowLocation(GetThisObject(), GetMethod(), GetDexPC());
     61 }
     62 
     63 size_t ManagedStack::NumJniShadowFrameReferences() const {
     64   size_t count = 0;
     65   for (const ManagedStack* current_fragment = this; current_fragment != NULL;
     66        current_fragment = current_fragment->GetLink()) {
     67     for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != NULL;
     68          current_frame = current_frame->GetLink()) {
     69       if (current_frame->GetMethod()->IsNative()) {
     70         // The JNI ShadowFrame only contains references. (For indirect reference.)
     71         count += current_frame->NumberOfVRegs();
     72       }
     73     }
     74   }
     75   return count;
     76 }
     77 
     78 bool ManagedStack::ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const {
     79   for (const ManagedStack* current_fragment = this; current_fragment != NULL;
     80        current_fragment = current_fragment->GetLink()) {
     81     for (ShadowFrame* current_frame = current_fragment->top_shadow_frame_; current_frame != NULL;
     82          current_frame = current_frame->GetLink()) {
     83       if (current_frame->Contains(shadow_frame_entry)) {
     84         return true;
     85       }
     86     }
     87   }
     88   return false;
     89 }
     90 
     91 StackVisitor::StackVisitor(Thread* thread, Context* context)
     92     : thread_(thread), cur_shadow_frame_(NULL),
     93       cur_quick_frame_(NULL), cur_quick_frame_pc_(0), num_frames_(0), cur_depth_(0),
     94       context_(context) {
     95   DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread;
     96 }
     97 
     98 StackVisitor::StackVisitor(Thread* thread, Context* context, size_t num_frames)
     99     : thread_(thread), cur_shadow_frame_(NULL),
    100       cur_quick_frame_(NULL), cur_quick_frame_pc_(0), num_frames_(num_frames), cur_depth_(0),
    101       context_(context) {
    102   DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread;
    103 }
    104 
    105 uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const {
    106   if (cur_shadow_frame_ != NULL) {
    107     return cur_shadow_frame_->GetDexPC();
    108   } else if (cur_quick_frame_ != NULL) {
    109     return GetMethod()->ToDexPc(cur_quick_frame_pc_, abort_on_failure);
    110   } else {
    111     return 0;
    112   }
    113 }
    114 
    115 mirror::Object* StackVisitor::GetThisObject() const {
    116   mirror::ArtMethod* m = GetMethod();
    117   if (m->IsStatic()) {
    118     return NULL;
    119   } else if (m->IsNative()) {
    120     if (cur_quick_frame_ != NULL) {
    121       HandleScope* hs = reinterpret_cast<HandleScope*>(
    122           reinterpret_cast<char*>(cur_quick_frame_) + m->GetHandleScopeOffsetInBytes());
    123       return hs->GetReference(0);
    124     } else {
    125       return cur_shadow_frame_->GetVRegReference(0);
    126     }
    127   } else {
    128     const DexFile::CodeItem* code_item = m->GetCodeItem();
    129     if (code_item == NULL) {
    130       UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: "
    131           << PrettyMethod(m);
    132       return nullptr;
    133     } else {
    134       uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
    135       return reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kReferenceVReg));
    136     }
    137   }
    138 }
    139 
    140 size_t StackVisitor::GetNativePcOffset() const {
    141   DCHECK(!IsShadowFrame());
    142   return GetMethod()->NativePcOffset(cur_quick_frame_pc_);
    143 }
    144 
    145 bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
    146                            uint32_t* val) const {
    147   if (cur_quick_frame_ != nullptr) {
    148     DCHECK(context_ != nullptr);  // You can't reliably read registers without a context.
    149     DCHECK(m == GetMethod());
    150     const void* code_pointer = m->GetQuickOatCodePointer();
    151     DCHECK(code_pointer != nullptr);
    152     const VmapTable vmap_table(m->GetVmapTable(code_pointer));
    153     QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
    154     uint32_t vmap_offset;
    155     // TODO: IsInContext stops before spotting floating point registers.
    156     if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
    157       bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
    158       uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
    159       uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
    160       uintptr_t ptr_val;
    161       bool success = is_float ? GetFPR(reg, &ptr_val) : GetGPR(reg, &ptr_val);
    162       if (!success) {
    163         return false;
    164       }
    165       bool target64 = Is64BitInstructionSet(kRuntimeISA);
    166       if (target64) {
    167         bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
    168         bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
    169         int64_t value_long = static_cast<int64_t>(ptr_val);
    170         if (wide_lo) {
    171           ptr_val = static_cast<uintptr_t>(value_long & 0xFFFFFFFF);
    172         } else if (wide_hi) {
    173           ptr_val = static_cast<uintptr_t>(value_long >> 32);
    174         }
    175       }
    176       *val = ptr_val;
    177       return true;
    178     } else {
    179       const DexFile::CodeItem* code_item = m->GetCodeItem();
    180       DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
    181                                                         // its instructions?
    182       *val = *GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
    183                           frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
    184       return true;
    185     }
    186   } else {
    187     *val = cur_shadow_frame_->GetVReg(vreg);
    188     return true;
    189   }
    190 }
    191 
    192 bool StackVisitor::GetVRegPair(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind_lo,
    193                                VRegKind kind_hi, uint64_t* val) const {
    194   if (kind_lo == kLongLoVReg) {
    195     DCHECK_EQ(kind_hi, kLongHiVReg);
    196   } else if (kind_lo == kDoubleLoVReg) {
    197     DCHECK_EQ(kind_hi, kDoubleHiVReg);
    198   } else {
    199     LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
    200   }
    201   if (cur_quick_frame_ != nullptr) {
    202     DCHECK(context_ != nullptr);  // You can't reliably read registers without a context.
    203     DCHECK(m == GetMethod());
    204     const void* code_pointer = m->GetQuickOatCodePointer();
    205     DCHECK(code_pointer != nullptr);
    206     const VmapTable vmap_table(m->GetVmapTable(code_pointer));
    207     QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
    208     uint32_t vmap_offset_lo, vmap_offset_hi;
    209     // TODO: IsInContext stops before spotting floating point registers.
    210     if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
    211         vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) {
    212       bool is_float = (kind_lo == kDoubleLoVReg);
    213       uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
    214       uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo);
    215       uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi);
    216       uintptr_t ptr_val_lo, ptr_val_hi;
    217       bool success = is_float ? GetFPR(reg_lo, &ptr_val_lo) : GetGPR(reg_lo, &ptr_val_lo);
    218       success &= is_float ? GetFPR(reg_hi, &ptr_val_hi) : GetGPR(reg_hi, &ptr_val_hi);
    219       if (!success) {
    220         return false;
    221       }
    222       bool target64 = Is64BitInstructionSet(kRuntimeISA);
    223       if (target64) {
    224         int64_t value_long_lo = static_cast<int64_t>(ptr_val_lo);
    225         int64_t value_long_hi = static_cast<int64_t>(ptr_val_hi);
    226         ptr_val_lo = static_cast<uintptr_t>(value_long_lo & 0xFFFFFFFF);
    227         ptr_val_hi = static_cast<uintptr_t>(value_long_hi >> 32);
    228       }
    229       *val = (static_cast<uint64_t>(ptr_val_hi) << 32) | static_cast<uint32_t>(ptr_val_lo);
    230       return true;
    231     } else {
    232       const DexFile::CodeItem* code_item = m->GetCodeItem();
    233       DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
    234                                                         // its instructions?
    235       uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
    236                                    frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
    237       *val = *reinterpret_cast<uint64_t*>(addr);
    238       return true;
    239     }
    240   } else {
    241     *val = cur_shadow_frame_->GetVRegLong(vreg);
    242     return true;
    243   }
    244 }
    245 
    246 bool StackVisitor::SetVReg(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value,
    247                            VRegKind kind) {
    248   if (cur_quick_frame_ != nullptr) {
    249     DCHECK(context_ != nullptr);  // You can't reliably write registers without a context.
    250     DCHECK(m == GetMethod());
    251     const void* code_pointer = m->GetQuickOatCodePointer();
    252     DCHECK(code_pointer != nullptr);
    253     const VmapTable vmap_table(m->GetVmapTable(code_pointer));
    254     QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
    255     uint32_t vmap_offset;
    256     // TODO: IsInContext stops before spotting floating point registers.
    257     if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
    258       bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
    259       uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
    260       const uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
    261       bool target64 = Is64BitInstructionSet(kRuntimeISA);
    262       // Deal with 32 or 64-bit wide registers in a way that builds on all targets.
    263       if (target64) {
    264         bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
    265         bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
    266         if (wide_lo || wide_hi) {
    267           uintptr_t old_reg_val;
    268           bool success = is_float ? GetFPR(reg, &old_reg_val) : GetGPR(reg, &old_reg_val);
    269           if (!success) {
    270             return false;
    271           }
    272           uint64_t new_vreg_portion = static_cast<uint64_t>(new_value);
    273           uint64_t old_reg_val_as_wide = static_cast<uint64_t>(old_reg_val);
    274           uint64_t mask = 0xffffffff;
    275           if (wide_lo) {
    276             mask = mask << 32;
    277           } else {
    278             new_vreg_portion = new_vreg_portion << 32;
    279           }
    280           new_value = static_cast<uintptr_t>((old_reg_val_as_wide & mask) | new_vreg_portion);
    281         }
    282       }
    283       if (is_float) {
    284         return SetFPR(reg, new_value);
    285       } else {
    286         return SetGPR(reg, new_value);
    287       }
    288     } else {
    289       const DexFile::CodeItem* code_item = m->GetCodeItem();
    290       DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
    291                                                         // its instructions?
    292       uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
    293                                    frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
    294       *addr = new_value;
    295       return true;
    296     }
    297   } else {
    298     cur_shadow_frame_->SetVReg(vreg, new_value);
    299     return true;
    300   }
    301 }
    302 
    303 bool StackVisitor::SetVRegPair(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
    304                                VRegKind kind_lo, VRegKind kind_hi) {
    305   if (kind_lo == kLongLoVReg) {
    306     DCHECK_EQ(kind_hi, kLongHiVReg);
    307   } else if (kind_lo == kDoubleLoVReg) {
    308     DCHECK_EQ(kind_hi, kDoubleHiVReg);
    309   } else {
    310     LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
    311   }
    312   if (cur_quick_frame_ != nullptr) {
    313     DCHECK(context_ != nullptr);  // You can't reliably write registers without a context.
    314     DCHECK(m == GetMethod());
    315     const void* code_pointer = m->GetQuickOatCodePointer();
    316     DCHECK(code_pointer != nullptr);
    317     const VmapTable vmap_table(m->GetVmapTable(code_pointer));
    318     QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
    319     uint32_t vmap_offset_lo, vmap_offset_hi;
    320     // TODO: IsInContext stops before spotting floating point registers.
    321     if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
    322         vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) {
    323       bool is_float = (kind_lo == kDoubleLoVReg);
    324       uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
    325       uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo);
    326       uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi);
    327       uintptr_t new_value_lo = static_cast<uintptr_t>(new_value & 0xFFFFFFFF);
    328       uintptr_t new_value_hi = static_cast<uintptr_t>(new_value >> 32);
    329       bool target64 = Is64BitInstructionSet(kRuntimeISA);
    330       // Deal with 32 or 64-bit wide registers in a way that builds on all targets.
    331       if (target64) {
    332         uintptr_t old_reg_val_lo, old_reg_val_hi;
    333         bool success = is_float ? GetFPR(reg_lo, &old_reg_val_lo) : GetGPR(reg_lo, &old_reg_val_lo);
    334         success &= is_float ? GetFPR(reg_hi, &old_reg_val_hi) : GetGPR(reg_hi, &old_reg_val_hi);
    335         if (!success) {
    336           return false;
    337         }
    338         uint64_t new_vreg_portion_lo = static_cast<uint64_t>(new_value_lo);
    339         uint64_t new_vreg_portion_hi = static_cast<uint64_t>(new_value_hi) << 32;
    340         uint64_t old_reg_val_lo_as_wide = static_cast<uint64_t>(old_reg_val_lo);
    341         uint64_t old_reg_val_hi_as_wide = static_cast<uint64_t>(old_reg_val_hi);
    342         uint64_t mask_lo = static_cast<uint64_t>(0xffffffff) << 32;
    343         uint64_t mask_hi = 0xffffffff;
    344         new_value_lo = static_cast<uintptr_t>((old_reg_val_lo_as_wide & mask_lo) | new_vreg_portion_lo);
    345         new_value_hi = static_cast<uintptr_t>((old_reg_val_hi_as_wide & mask_hi) | new_vreg_portion_hi);
    346       }
    347       bool success = is_float ? SetFPR(reg_lo, new_value_lo) : SetGPR(reg_lo, new_value_lo);
    348       success &= is_float ? SetFPR(reg_hi, new_value_hi) : SetGPR(reg_hi, new_value_hi);
    349       return success;
    350     } else {
    351       const DexFile::CodeItem* code_item = m->GetCodeItem();
    352       DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be NULL or how would we compile
    353                                                         // its instructions?
    354       uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
    355                                    frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
    356       *reinterpret_cast<uint64_t*>(addr) = new_value;
    357       return true;
    358     }
    359   } else {
    360     cur_shadow_frame_->SetVRegLong(vreg, new_value);
    361     return true;
    362   }
    363 }
    364 
    365 uintptr_t* StackVisitor::GetGPRAddress(uint32_t reg) const {
    366   DCHECK(cur_quick_frame_ != NULL) << "This is a quick frame routine";
    367   return context_->GetGPRAddress(reg);
    368 }
    369 
    370 bool StackVisitor::GetGPR(uint32_t reg, uintptr_t* val) const {
    371   DCHECK(cur_quick_frame_ != NULL) << "This is a quick frame routine";
    372   return context_->GetGPR(reg, val);
    373 }
    374 
    375 bool StackVisitor::SetGPR(uint32_t reg, uintptr_t value) {
    376   DCHECK(cur_quick_frame_ != NULL) << "This is a quick frame routine";
    377   return context_->SetGPR(reg, value);
    378 }
    379 
    380 bool StackVisitor::GetFPR(uint32_t reg, uintptr_t* val) const {
    381   DCHECK(cur_quick_frame_ != NULL) << "This is a quick frame routine";
    382   return context_->GetFPR(reg, val);
    383 }
    384 
    385 bool StackVisitor::SetFPR(uint32_t reg, uintptr_t value) {
    386   DCHECK(cur_quick_frame_ != NULL) << "This is a quick frame routine";
    387   return context_->SetFPR(reg, value);
    388 }
    389 
    390 uintptr_t StackVisitor::GetReturnPc() const {
    391   byte* sp = reinterpret_cast<byte*>(GetCurrentQuickFrame());
    392   DCHECK(sp != NULL);
    393   byte* pc_addr = sp + GetMethod()->GetReturnPcOffsetInBytes();
    394   return *reinterpret_cast<uintptr_t*>(pc_addr);
    395 }
    396 
    397 void StackVisitor::SetReturnPc(uintptr_t new_ret_pc) {
    398   byte* sp = reinterpret_cast<byte*>(GetCurrentQuickFrame());
    399   CHECK(sp != NULL);
    400   byte* pc_addr = sp + GetMethod()->GetReturnPcOffsetInBytes();
    401   *reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc;
    402 }
    403 
    404 size_t StackVisitor::ComputeNumFrames(Thread* thread) {
    405   struct NumFramesVisitor : public StackVisitor {
    406     explicit NumFramesVisitor(Thread* thread)
    407         : StackVisitor(thread, NULL), frames(0) {}
    408 
    409     bool VisitFrame() OVERRIDE {
    410       frames++;
    411       return true;
    412     }
    413 
    414     size_t frames;
    415   };
    416   NumFramesVisitor visitor(thread);
    417   visitor.WalkStack(true);
    418   return visitor.frames;
    419 }
    420 
    421 bool StackVisitor::GetNextMethodAndDexPc(mirror::ArtMethod** next_method, uint32_t* next_dex_pc) {
    422   struct HasMoreFramesVisitor : public StackVisitor {
    423     explicit HasMoreFramesVisitor(Thread* thread, size_t num_frames, size_t frame_height)
    424         : StackVisitor(thread, nullptr, num_frames), frame_height_(frame_height),
    425           found_frame_(false), has_more_frames_(false), next_method_(nullptr), next_dex_pc_(0) {
    426     }
    427 
    428     bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    429       if (found_frame_) {
    430         mirror::ArtMethod* method = GetMethod();
    431         if (method != nullptr && !method->IsRuntimeMethod()) {
    432           has_more_frames_ = true;
    433           next_method_ = method;
    434           next_dex_pc_ = GetDexPc();
    435           return false;  // End stack walk once next method is found.
    436         }
    437       } else if (GetFrameHeight() == frame_height_) {
    438         found_frame_ = true;
    439       }
    440       return true;
    441     }
    442 
    443     size_t frame_height_;
    444     bool found_frame_;
    445     bool has_more_frames_;
    446     mirror::ArtMethod* next_method_;
    447     uint32_t next_dex_pc_;
    448   };
    449   HasMoreFramesVisitor visitor(thread_, GetNumFrames(), GetFrameHeight());
    450   visitor.WalkStack(true);
    451   *next_method = visitor.next_method_;
    452   *next_dex_pc = visitor.next_dex_pc_;
    453   return visitor.has_more_frames_;
    454 }
    455 
    456 void StackVisitor::DescribeStack(Thread* thread) {
    457   struct DescribeStackVisitor : public StackVisitor {
    458     explicit DescribeStackVisitor(Thread* thread)
    459         : StackVisitor(thread, NULL) {}
    460 
    461     bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    462       LOG(INFO) << "Frame Id=" << GetFrameId() << " " << DescribeLocation();
    463       return true;
    464     }
    465   };
    466   DescribeStackVisitor visitor(thread);
    467   visitor.WalkStack(true);
    468 }
    469 
    470 std::string StackVisitor::DescribeLocation() const {
    471   std::string result("Visiting method '");
    472   mirror::ArtMethod* m = GetMethod();
    473   if (m == NULL) {
    474     return "upcall";
    475   }
    476   result += PrettyMethod(m);
    477   result += StringPrintf("' at dex PC 0x%04x", GetDexPc());
    478   if (!IsShadowFrame()) {
    479     result += StringPrintf(" (native PC %p)", reinterpret_cast<void*>(GetCurrentQuickFramePc()));
    480   }
    481   return result;
    482 }
    483 
    484 static instrumentation::InstrumentationStackFrame& GetInstrumentationStackFrame(Thread* thread,
    485                                                                                 uint32_t depth) {
    486   CHECK_LT(depth, thread->GetInstrumentationStack()->size());
    487   return thread->GetInstrumentationStack()->at(depth);
    488 }
    489 
    490 void StackVisitor::SanityCheckFrame() const {
    491   if (kIsDebugBuild) {
    492     mirror::ArtMethod* method = GetMethod();
    493     CHECK_EQ(method->GetClass(), mirror::ArtMethod::GetJavaLangReflectArtMethod());
    494     if (cur_quick_frame_ != nullptr) {
    495       method->AssertPcIsWithinQuickCode(cur_quick_frame_pc_);
    496       // Frame sanity.
    497       size_t frame_size = method->GetFrameSizeInBytes();
    498       CHECK_NE(frame_size, 0u);
    499       // A rough guess at an upper size we expect to see for a frame.
    500       // 256 registers
    501       // 2 words HandleScope overhead
    502       // 3+3 register spills
    503       // TODO: this seems architecture specific for the case of JNI frames.
    504       // TODO: 083-compiler-regressions ManyFloatArgs shows this estimate is wrong.
    505       // const size_t kMaxExpectedFrameSize = (256 + 2 + 3 + 3) * sizeof(word);
    506       const size_t kMaxExpectedFrameSize = 2 * KB;
    507       CHECK_LE(frame_size, kMaxExpectedFrameSize);
    508       size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
    509       CHECK_LT(return_pc_offset, frame_size);
    510     }
    511   }
    512 }
    513 
    514 void StackVisitor::WalkStack(bool include_transitions) {
    515   DCHECK(thread_ == Thread::Current() || thread_->IsSuspended());
    516   CHECK_EQ(cur_depth_, 0U);
    517   bool exit_stubs_installed = Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
    518   uint32_t instrumentation_stack_depth = 0;
    519 
    520   for (const ManagedStack* current_fragment = thread_->GetManagedStack(); current_fragment != NULL;
    521        current_fragment = current_fragment->GetLink()) {
    522     cur_shadow_frame_ = current_fragment->GetTopShadowFrame();
    523     cur_quick_frame_ = current_fragment->GetTopQuickFrame();
    524     cur_quick_frame_pc_ = current_fragment->GetTopQuickFramePc();
    525 
    526     if (cur_quick_frame_ != NULL) {  // Handle quick stack frames.
    527       // Can't be both a shadow and a quick fragment.
    528       DCHECK(current_fragment->GetTopShadowFrame() == NULL);
    529       mirror::ArtMethod* method = cur_quick_frame_->AsMirrorPtr();
    530       while (method != NULL) {
    531         SanityCheckFrame();
    532         bool should_continue = VisitFrame();
    533         if (UNLIKELY(!should_continue)) {
    534           return;
    535         }
    536 
    537         if (context_ != NULL) {
    538           context_->FillCalleeSaves(*this);
    539         }
    540         size_t frame_size = method->GetFrameSizeInBytes();
    541         // Compute PC for next stack frame from return PC.
    542         size_t return_pc_offset = method->GetReturnPcOffsetInBytes(frame_size);
    543         byte* return_pc_addr = reinterpret_cast<byte*>(cur_quick_frame_) + return_pc_offset;
    544         uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr);
    545         if (UNLIKELY(exit_stubs_installed)) {
    546           // While profiling, the return pc is restored from the side stack, except when walking
    547           // the stack for an exception where the side stack will be unwound in VisitFrame.
    548           if (GetQuickInstrumentationExitPc() == return_pc) {
    549             const instrumentation::InstrumentationStackFrame& instrumentation_frame =
    550                 GetInstrumentationStackFrame(thread_, instrumentation_stack_depth);
    551             instrumentation_stack_depth++;
    552             if (GetMethod() == Runtime::Current()->GetCalleeSaveMethod(Runtime::kSaveAll)) {
    553               // Skip runtime save all callee frames which are used to deliver exceptions.
    554             } else if (instrumentation_frame.interpreter_entry_) {
    555               mirror::ArtMethod* callee = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
    556               CHECK_EQ(GetMethod(), callee) << "Expected: " << PrettyMethod(callee) << " Found: "
    557                                             << PrettyMethod(GetMethod());
    558             } else if (instrumentation_frame.method_ != GetMethod()) {
    559               LOG(FATAL)  << "Expected: " << PrettyMethod(instrumentation_frame.method_)
    560                           << " Found: " << PrettyMethod(GetMethod());
    561             }
    562             if (num_frames_ != 0) {
    563               // Check agreement of frame Ids only if num_frames_ is computed to avoid infinite
    564               // recursion.
    565               CHECK(instrumentation_frame.frame_id_ == GetFrameId())
    566                     << "Expected: " << instrumentation_frame.frame_id_
    567                     << " Found: " << GetFrameId();
    568             }
    569             return_pc = instrumentation_frame.return_pc_;
    570           }
    571         }
    572         cur_quick_frame_pc_ = return_pc;
    573         byte* next_frame = reinterpret_cast<byte*>(cur_quick_frame_) + frame_size;
    574         cur_quick_frame_ = reinterpret_cast<StackReference<mirror::ArtMethod>*>(next_frame);
    575         cur_depth_++;
    576         method = cur_quick_frame_->AsMirrorPtr();
    577       }
    578     } else if (cur_shadow_frame_ != NULL) {
    579       do {
    580         SanityCheckFrame();
    581         bool should_continue = VisitFrame();
    582         if (UNLIKELY(!should_continue)) {
    583           return;
    584         }
    585         cur_depth_++;
    586         cur_shadow_frame_ = cur_shadow_frame_->GetLink();
    587       } while (cur_shadow_frame_ != NULL);
    588     }
    589     if (include_transitions) {
    590       bool should_continue = VisitFrame();
    591       if (!should_continue) {
    592         return;
    593       }
    594     }
    595     cur_depth_++;
    596   }
    597   if (num_frames_ != 0) {
    598     CHECK_EQ(cur_depth_, num_frames_);
    599   }
    600 }
    601 
    602 }  // namespace art
    603