summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/debugger.cc36
-rw-r--r--runtime/quick_exception_handler.cc38
-rw-r--r--runtime/stack.cc153
-rw-r--r--runtime/stack.h17
4 files changed, 197 insertions, 47 deletions
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 4cf4c09..e4ab9f5 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2450,12 +2450,9 @@ JDWP::JdwpError Dbg::GetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame
}
case JDWP::JT_DOUBLE: {
CHECK_EQ(width_, 8U);
- uint32_t lo;
- uint32_t hi;
- if (GetVReg(m, reg, kDoubleLoVReg, &lo) && GetVReg(m, reg + 1, kDoubleHiVReg, &hi)) {
- uint64_t longVal = (static_cast<uint64_t>(hi) << 32) | lo;
- VLOG(jdwp) << "get double local " << reg << " = "
- << hi << ":" << lo << " = " << longVal;
+ uint64_t longVal;
+ if (GetVRegPair(m, reg, kDoubleLoVReg, kDoubleHiVReg, &longVal)) {
+ VLOG(jdwp) << "get double local " << reg << " = " << longVal;
JDWP::Set8BE(buf_+1, longVal);
} else {
VLOG(jdwp) << "failed to get double local " << reg;
@@ -2465,12 +2462,9 @@ JDWP::JdwpError Dbg::GetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame
}
case JDWP::JT_LONG: {
CHECK_EQ(width_, 8U);
- uint32_t lo;
- uint32_t hi;
- if (GetVReg(m, reg, kLongLoVReg, &lo) && GetVReg(m, reg + 1, kLongHiVReg, &hi)) {
- uint64_t longVal = (static_cast<uint64_t>(hi) << 32) | lo;
- VLOG(jdwp) << "get long local " << reg << " = "
- << hi << ":" << lo << " = " << longVal;
+ uint64_t longVal;
+ if (GetVRegPair(m, reg, kLongLoVReg, kLongHiVReg, &longVal)) {
+ VLOG(jdwp) << "get long local " << reg << " = " << longVal;
JDWP::Set8BE(buf_+1, longVal);
} else {
VLOG(jdwp) << "failed to get long local " << reg;
@@ -2593,28 +2587,18 @@ JDWP::JdwpError Dbg::SetLocalValue(JDWP::ObjectId thread_id, JDWP::FrameId frame
}
case JDWP::JT_DOUBLE: {
CHECK_EQ(width_, 8U);
- const uint32_t lo = static_cast<uint32_t>(value_);
- const uint32_t hi = static_cast<uint32_t>(value_ >> 32);
- bool success = SetVReg(m, reg, lo, kDoubleLoVReg);
- success &= SetVReg(m, reg + 1, hi, kDoubleHiVReg);
+ bool success = SetVRegPair(m, reg, value_, kDoubleLoVReg, kDoubleHiVReg);
if (!success) {
- uint64_t longVal = (static_cast<uint64_t>(hi) << 32) | lo;
- VLOG(jdwp) << "failed to set double local " << reg << " = "
- << hi << ":" << lo << " = " << longVal;
+ VLOG(jdwp) << "failed to set double local " << reg << " = " << value_;
error_ = kFailureErrorCode;
}
break;
}
case JDWP::JT_LONG: {
CHECK_EQ(width_, 8U);
- const uint32_t lo = static_cast<uint32_t>(value_);
- const uint32_t hi = static_cast<uint32_t>(value_ >> 32);
- bool success = SetVReg(m, reg, lo, kLongLoVReg);
- success &= SetVReg(m, reg + 1, hi, kLongHiVReg);
+ bool success = SetVRegPair(m, reg, value_, kLongLoVReg, kLongHiVReg);
if (!success) {
- uint64_t longVal = (static_cast<uint64_t>(hi) << 32) | lo;
- VLOG(jdwp) << "failed to set double local " << reg << " = "
- << hi << ":" << lo << " = " << longVal;
+ VLOG(jdwp) << "failed to set double local " << reg << " = " << value_;
error_ = kFailureErrorCode;
}
break;
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 6581f9b..41d6989 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -194,6 +194,10 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor {
}
private:
+ static VRegKind GetVRegKind(uint16_t reg, const std::vector<int32_t>& kinds) {
+ return static_cast<VRegKind>(kinds.at(reg * 2));
+ }
+
bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
const DexFile::CodeItem* code_item = m->GetCodeItem();
CHECK(code_item != nullptr);
@@ -210,9 +214,9 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor {
&m->GetClassDef(), code_item, m->GetDexMethodIndex(), m,
m->GetAccessFlags(), false, true, true);
verifier.Verify();
- std::vector<int32_t> kinds = verifier.DescribeVRegs(dex_pc);
+ const std::vector<int32_t> kinds(verifier.DescribeVRegs(dex_pc));
for (uint16_t reg = 0; reg < num_regs; ++reg) {
- VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
+ VRegKind kind = GetVRegKind(reg, kinds);
switch (kind) {
case kUndefined:
new_frame->SetVReg(reg, 0xEBADDE09);
@@ -224,6 +228,36 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor {
new_frame->SetVRegReference(reg,
reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kind)));
break;
+ case kLongLoVReg:
+ if (GetVRegKind(reg + 1, kinds), kLongHiVReg) {
+ // Treat it as a "long" register pair.
+ new_frame->SetVRegLong(reg, GetVRegPair(m, reg, kLongLoVReg, kLongHiVReg));
+ } else {
+ new_frame->SetVReg(reg, GetVReg(m, reg, kind));
+ }
+ break;
+ case kLongHiVReg:
+ if (GetVRegKind(reg - 1, kinds), kLongLoVReg) {
+ // Nothing to do: we treated it as a "long" register pair.
+ } else {
+ new_frame->SetVReg(reg, GetVReg(m, reg, kind));
+ }
+ break;
+ case kDoubleLoVReg:
+ if (GetVRegKind(reg + 1, kinds), kDoubleHiVReg) {
+ // Treat it as a "double" register pair.
+ new_frame->SetVRegLong(reg, GetVRegPair(m, reg, kDoubleLoVReg, kDoubleHiVReg));
+ } else {
+ new_frame->SetVReg(reg, GetVReg(m, reg, kind));
+ }
+ break;
+ case kDoubleHiVReg:
+ if (GetVRegKind(reg - 1, kinds), kDoubleLoVReg) {
+ // Nothing to do: we treated it as a "double" register pair.
+ } else {
+ new_frame->SetVReg(reg, GetVReg(m, reg, kind));
+ }
+ break;
default:
new_frame->SetVReg(reg, GetVReg(m, reg, kind));
break;
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 71e566e..2d0060e 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -144,8 +144,8 @@ size_t StackVisitor::GetNativePcOffset() const {
bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
uint32_t* val) const {
- if (cur_quick_frame_ != NULL) {
- DCHECK(context_ != NULL); // You can't reliably read registers without a context.
+ if (cur_quick_frame_ != nullptr) {
+ DCHECK(context_ != nullptr); // You can't reliably read registers without a context.
DCHECK(m == GetMethod());
const void* code_pointer = m->GetQuickOatCodePointer();
DCHECK(code_pointer != nullptr);
@@ -158,14 +158,12 @@ bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
uintptr_t ptr_val;
- bool success = false;
- bool target64 = (kRuntimeISA == kArm64) || (kRuntimeISA == kX86_64);
- if (is_float) {
- success = GetFPR(reg, &ptr_val);
- } else {
- success = GetGPR(reg, &ptr_val);
+ bool success = is_float ? GetFPR(reg, &ptr_val) : GetGPR(reg, &ptr_val);
+ if (!success) {
+ return false;
}
- if (success && target64) {
+ bool target64 = Is64BitInstructionSet(kRuntimeISA);
+ if (target64) {
bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
int64_t value_long = static_cast<int64_t>(ptr_val);
@@ -176,10 +174,11 @@ bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
}
}
*val = ptr_val;
- return success;
+ return true;
} else {
const DexFile::CodeItem* code_item = m->GetCodeItem();
- DCHECK(code_item != NULL) << PrettyMethod(m); // Can't be NULL or how would we compile its instructions?
+ DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be NULL or how would we compile
+ // its instructions?
*val = *GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
return true;
@@ -190,10 +189,64 @@ bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
}
}
+bool StackVisitor::GetVRegPair(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind_lo,
+ VRegKind kind_hi, uint64_t* val) const {
+ 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;
+ }
+ if (cur_quick_frame_ != nullptr) {
+ DCHECK(context_ != nullptr); // You can't reliably read registers without a context.
+ DCHECK(m == GetMethod());
+ const void* code_pointer = m->GetQuickOatCodePointer();
+ DCHECK(code_pointer != nullptr);
+ const VmapTable vmap_table(m->GetVmapTable(code_pointer));
+ QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
+ uint32_t vmap_offset_lo, vmap_offset_hi;
+ // TODO: IsInContext stops before spotting floating point registers.
+ if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
+ vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) {
+ bool is_float = (kind_lo == kDoubleLoVReg);
+ uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
+ uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo);
+ uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi);
+ uintptr_t ptr_val_lo, ptr_val_hi;
+ bool success = is_float ? GetFPR(reg_lo, &ptr_val_lo) : GetGPR(reg_lo, &ptr_val_lo);
+ success &= is_float ? GetFPR(reg_hi, &ptr_val_hi) : GetGPR(reg_hi, &ptr_val_hi);
+ if (!success) {
+ return false;
+ }
+ bool target64 = Is64BitInstructionSet(kRuntimeISA);
+ if (target64) {
+ int64_t value_long_lo = static_cast<int64_t>(ptr_val_lo);
+ int64_t value_long_hi = static_cast<int64_t>(ptr_val_hi);
+ ptr_val_lo = static_cast<uintptr_t>(value_long_lo & 0xFFFFFFFF);
+ ptr_val_hi = static_cast<uintptr_t>(value_long_hi >> 32);
+ }
+ *val = (static_cast<uint64_t>(ptr_val_hi) << 32) | static_cast<uint32_t>(ptr_val_lo);
+ return true;
+ } else {
+ const DexFile::CodeItem* code_item = m->GetCodeItem();
+ DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be NULL or how would we compile
+ // its instructions?
+ uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
+ frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
+ *val = *reinterpret_cast<uint64_t*>(addr);
+ return true;
+ }
+ } else {
+ *val = cur_shadow_frame_->GetVRegLong(vreg);
+ return true;
+ }
+}
+
bool StackVisitor::SetVReg(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value,
VRegKind kind) {
- if (cur_quick_frame_ != NULL) {
- DCHECK(context_ != NULL); // You can't reliably write registers without a context.
+ if (cur_quick_frame_ != nullptr) {
+ DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
DCHECK(m == GetMethod());
const void* code_pointer = m->GetQuickOatCodePointer();
DCHECK(code_pointer != nullptr);
@@ -205,7 +258,7 @@ bool StackVisitor::SetVReg(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_val
bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
const uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
- bool target64 = (kRuntimeISA == kArm64) || (kRuntimeISA == kX86_64);
+ bool target64 = Is64BitInstructionSet(kRuntimeISA);
// Deal with 32 or 64-bit wide registers in a way that builds on all targets.
if (target64) {
bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
@@ -234,11 +287,11 @@ bool StackVisitor::SetVReg(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_val
}
} else {
const DexFile::CodeItem* code_item = m->GetCodeItem();
- DCHECK(code_item != NULL) << PrettyMethod(m); // Can't be NULL or how would we compile its instructions?
- int offset = GetVRegOffset(code_item, frame_info.CoreSpillMask(), frame_info.FpSpillMask(),
- frame_info.FrameSizeInBytes(), vreg, kRuntimeISA);
- byte* vreg_addr = reinterpret_cast<byte*>(GetCurrentQuickFrame()) + offset;
- *reinterpret_cast<uint32_t*>(vreg_addr) = new_value;
+ DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be NULL or how would we compile
+ // its instructions?
+ uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
+ frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
+ *addr = new_value;
return true;
}
} else {
@@ -247,6 +300,68 @@ bool StackVisitor::SetVReg(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_val
}
}
+bool StackVisitor::SetVRegPair(mirror::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;
+ }
+ if (cur_quick_frame_ != nullptr) {
+ DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
+ DCHECK(m == GetMethod());
+ const void* code_pointer = m->GetQuickOatCodePointer();
+ DCHECK(code_pointer != nullptr);
+ const VmapTable vmap_table(m->GetVmapTable(code_pointer));
+ QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
+ uint32_t vmap_offset_lo, vmap_offset_hi;
+ // TODO: IsInContext stops before spotting floating point registers.
+ if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) &&
+ vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) {
+ bool is_float = (kind_lo == kDoubleLoVReg);
+ uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
+ uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo);
+ uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi);
+ uintptr_t new_value_lo = static_cast<uintptr_t>(new_value & 0xFFFFFFFF);
+ uintptr_t new_value_hi = static_cast<uintptr_t>(new_value >> 32);
+ bool target64 = Is64BitInstructionSet(kRuntimeISA);
+ // Deal with 32 or 64-bit wide registers in a way that builds on all targets.
+ if (target64) {
+ uintptr_t old_reg_val_lo, old_reg_val_hi;
+ bool success = is_float ? GetFPR(reg_lo, &old_reg_val_lo) : GetGPR(reg_lo, &old_reg_val_lo);
+ success &= is_float ? GetFPR(reg_hi, &old_reg_val_hi) : GetGPR(reg_hi, &old_reg_val_hi);
+ if (!success) {
+ return false;
+ }
+ uint64_t new_vreg_portion_lo = static_cast<uint64_t>(new_value_lo);
+ uint64_t new_vreg_portion_hi = static_cast<uint64_t>(new_value_hi) << 32;
+ uint64_t old_reg_val_lo_as_wide = static_cast<uint64_t>(old_reg_val_lo);
+ uint64_t old_reg_val_hi_as_wide = static_cast<uint64_t>(old_reg_val_hi);
+ uint64_t mask_lo = static_cast<uint64_t>(0xffffffff) << 32;
+ uint64_t mask_hi = 0xffffffff;
+ new_value_lo = static_cast<uintptr_t>((old_reg_val_lo_as_wide & mask_lo) | new_vreg_portion_lo);
+ new_value_hi = static_cast<uintptr_t>((old_reg_val_hi_as_wide & mask_hi) | new_vreg_portion_hi);
+ }
+ bool success = is_float ? SetFPR(reg_lo, new_value_lo) : SetGPR(reg_lo, new_value_lo);
+ success &= is_float ? SetFPR(reg_hi, new_value_hi) : SetGPR(reg_hi, new_value_hi);
+ return success;
+ } else {
+ const DexFile::CodeItem* code_item = m->GetCodeItem();
+ DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be NULL or how would we compile
+ // its instructions?
+ uint32_t* addr = GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
+ frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
+ *reinterpret_cast<uint64_t*>(addr) = new_value;
+ return true;
+ }
+ } else {
+ cur_shadow_frame_->SetVRegLong(vreg, new_value);
+ return true;
+ }
+}
+
uintptr_t* StackVisitor::GetGPRAddress(uint32_t reg) const {
DCHECK(cur_quick_frame_ != NULL) << "This is a quick frame routine";
return context_->GetGPRAddress(reg);
diff --git a/runtime/stack.h b/runtime/stack.h
index ef498ef..578f569 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -568,9 +568,26 @@ class StackVisitor {
return val;
}
+ bool GetVRegPair(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind_lo, VRegKind kind_hi,
+ uint64_t* val) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ uint64_t GetVRegPair(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind_lo,
+ VRegKind kind_hi) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ uint64_t val;
+ bool success = GetVRegPair(m, vreg, kind_lo, kind_hi, &val);
+ CHECK(success) << "Failed to read vreg pair " << vreg
+ << " of kind [" << kind_lo << "," << kind_hi << "]";
+ return val;
+ }
+
bool SetVReg(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool SetVRegPair(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
+ VRegKind kind_lo, VRegKind kind_hi)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
uintptr_t* GetGPRAddress(uint32_t reg) const;
// This is a fast-path for getting/setting values in a quick frame.