diff options
Diffstat (limited to 'runtime/stack.cc')
| -rw-r--r-- | runtime/stack.cc | 125 |
1 files changed, 115 insertions, 10 deletions
diff --git a/runtime/stack.cc b/runtime/stack.cc index d956f0e25d..d739743151 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -220,10 +220,37 @@ bool StackVisitor::IsReferenceVReg(ArtMethod* m, uint16_t vreg) { return vreg < num_regs && TestBitmap(vreg, reg_bitmap); } +bool StackVisitor::GetVRegFromDebuggerShadowFrame(uint16_t vreg, + VRegKind kind, + uint32_t* val) const { + size_t frame_id = const_cast<StackVisitor*>(this)->GetFrameId(); + ShadowFrame* shadow_frame = thread_->FindDebuggerShadowFrame(frame_id); + if (shadow_frame != nullptr) { + bool* updated_vreg_flags = thread_->GetUpdatedVRegFlags(frame_id); + DCHECK(updated_vreg_flags != nullptr); + if (updated_vreg_flags[vreg]) { + // Value is set by the debugger. + if (kind == kReferenceVReg) { + *val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>( + shadow_frame->GetVRegReference(vreg))); + } else { + *val = shadow_frame->GetVReg(vreg); + } + return true; + } + } + // No value is set by the debugger. + return false; +} + bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const { if (cur_quick_frame_ != nullptr) { DCHECK(context_ != nullptr); // You can't reliably read registers without a context. DCHECK(m == GetMethod()); + // Check if there is value set by the debugger. + if (GetVRegFromDebuggerShadowFrame(vreg, kind, val)) { + return true; + } if (m->IsOptimized(sizeof(void*))) { return GetVRegFromOptimizedCode(m, vreg, kind, val); } else { @@ -267,7 +294,6 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin // its instructions? uint16_t number_of_dex_registers = code_item->registers_size_; DCHECK_LT(vreg, code_item->registers_size_); - ArtMethod* outer_method = *GetCurrentQuickFrame(); const void* code_pointer = outer_method->GetQuickOatCodePointer(sizeof(void*)); DCHECK(code_pointer != nullptr); @@ -348,6 +374,20 @@ bool StackVisitor::GetRegisterIfAccessible(uint32_t reg, VRegKind kind, uint32_t return true; } +bool StackVisitor::GetVRegPairFromDebuggerShadowFrame(uint16_t vreg, + VRegKind kind_lo, + VRegKind kind_hi, + uint64_t* val) const { + uint32_t low_32bits; + uint32_t high_32bits; + bool success = GetVRegFromDebuggerShadowFrame(vreg, kind_lo, &low_32bits); + success &= GetVRegFromDebuggerShadowFrame(vreg + 1, kind_hi, &high_32bits); + if (success) { + *val = (static_cast<uint64_t>(high_32bits) << 32) | static_cast<uint64_t>(low_32bits); + } + return success; +} + bool StackVisitor::GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, VRegKind kind_hi, uint64_t* val) const { if (kind_lo == kLongLoVReg) { @@ -358,6 +398,10 @@ bool StackVisitor::GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi; UNREACHABLE(); } + // Check if there is value set by the debugger. + if (GetVRegPairFromDebuggerShadowFrame(vreg, kind_lo, kind_hi, val)) { + return true; + } if (cur_quick_frame_ != nullptr) { DCHECK(context_ != nullptr); // You can't reliably read registers without a context. DCHECK(m == GetMethod()); @@ -435,17 +479,17 @@ bool StackVisitor::GetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, bool StackVisitor::SetVReg(ArtMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind) { if (cur_quick_frame_ != nullptr) { - DCHECK(context_ != nullptr); // You can't reliably write registers without a context. - DCHECK(m == GetMethod()); - if (m->IsOptimized(sizeof(void*))) { - return false; - } else { - return SetVRegFromQuickCode(m, vreg, new_value, kind); - } + DCHECK(context_ != nullptr); // You can't reliably write registers without a context. + DCHECK(m == GetMethod()); + if (m->IsOptimized(sizeof(void*))) { + return false; } else { - cur_shadow_frame_->SetVReg(vreg, new_value); - return true; + return SetVRegFromQuickCode(m, vreg, new_value, kind); } + } else { + cur_shadow_frame_->SetVReg(vreg, new_value); + return true; + } } bool StackVisitor::SetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, uint32_t new_value, @@ -475,6 +519,34 @@ bool StackVisitor::SetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, uint32_t ne } } +bool StackVisitor::SetVRegFromDebugger(ArtMethod* m, + uint16_t vreg, + uint32_t new_value, + VRegKind kind) { + const DexFile::CodeItem* code_item = m->GetCodeItem(); + if (code_item == nullptr) { + return false; + } + ShadowFrame* shadow_frame = GetCurrentShadowFrame(); + if (shadow_frame == nullptr) { + // This is a compiled frame: we must prepare and update a shadow frame that will + // be executed by the interpreter after deoptimization of the stack. + const size_t frame_id = GetFrameId(); + const uint16_t num_regs = code_item->registers_size_; + shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc()); + CHECK(shadow_frame != nullptr); + // Remember the vreg has been set for debugging and must not be overwritten by the + // original value during deoptimization of the stack. + thread_->GetUpdatedVRegFlags(frame_id)[vreg] = true; + } + if (kind == kReferenceVReg) { + shadow_frame->SetVRegReference(vreg, reinterpret_cast<mirror::Object*>(new_value)); + } else { + shadow_frame->SetVReg(vreg, new_value); + } + return true; +} + bool StackVisitor::SetRegisterIfAccessible(uint32_t reg, uint32_t new_value, VRegKind kind) { const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); if (!IsAccessibleRegister(reg, is_float)) { @@ -557,6 +629,39 @@ bool StackVisitor::SetVRegPairFromQuickCode( } } +bool StackVisitor::SetVRegPairFromDebugger(ArtMethod* m, + uint16_t vreg, + uint64_t new_value, + VRegKind kind_lo, + VRegKind kind_hi) { + if (kind_lo == kLongLoVReg) { + DCHECK_EQ(kind_hi, kLongHiVReg); + } else if (kind_lo == kDoubleLoVReg) { + DCHECK_EQ(kind_hi, kDoubleHiVReg); + } else { + LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi; + UNREACHABLE(); + } + const DexFile::CodeItem* code_item = m->GetCodeItem(); + if (code_item == nullptr) { + return false; + } + ShadowFrame* shadow_frame = GetCurrentShadowFrame(); + if (shadow_frame == nullptr) { + // This is a compiled frame: we must prepare for deoptimization (see SetVRegFromDebugger). + const size_t frame_id = GetFrameId(); + const uint16_t num_regs = code_item->registers_size_; + shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc()); + CHECK(shadow_frame != nullptr); + // Remember the vreg pair has been set for debugging and must not be overwritten by the + // original value during deoptimization of the stack. + thread_->GetUpdatedVRegFlags(frame_id)[vreg] = true; + thread_->GetUpdatedVRegFlags(frame_id)[vreg + 1] = true; + } + shadow_frame->SetVRegLong(vreg, new_value); + return true; +} + bool StackVisitor::SetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, uint64_t new_value, bool is_float) { if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) { |