summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/jni/quick/arm/calling_convention_arm.cc16
-rw-r--r--compiler/jni/quick/arm/calling_convention_arm.h4
-rw-r--r--compiler/jni/quick/arm64/calling_convention_arm64.cc17
-rw-r--r--compiler/utils/arm/assembler_arm.cc40
-rw-r--r--compiler/utils/arm64/assembler_arm64.cc37
-rw-r--r--compiler/utils/arm64/constants_arm64.h2
-rw-r--r--runtime/stack.cc468
-rw-r--r--runtime/stack.h45
-rw-r--r--runtime/stack_map.h22
-rw-r--r--test/454-get-vreg/expected.txt0
-rw-r--r--test/454-get-vreg/get_vreg_jni.cc122
-rw-r--r--test/454-get-vreg/info.txt1
-rw-r--r--test/454-get-vreg/src/Main.java53
-rw-r--r--test/455-set-vreg/expected.txt0
-rw-r--r--test/455-set-vreg/info.txt1
-rw-r--r--test/455-set-vreg/set_vreg_jni.cc95
-rw-r--r--test/455-set-vreg/src/Main.java73
-rw-r--r--test/Android.libarttest.mk4
-rwxr-xr-xtest/etc/run-test-jar2
19 files changed, 823 insertions, 179 deletions
diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc
index 669c3bb..d3690b2 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.cc
+++ b/compiler/jni/quick/arm/calling_convention_arm.cc
@@ -31,6 +31,10 @@ static const SRegister kHFSArgumentRegisters[] = {
S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15
};
+static const SRegister kHFSCalleeSaveRegisters[] = {
+ S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31
+};
+
static const DRegister kHFDArgumentRegisters[] = {
D0, D1, D2, D3, D4, D5, D6, D7
};
@@ -226,6 +230,10 @@ ArmJniCallingConvention::ArmJniCallingConvention(bool is_static, bool is_synchro
callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R8));
callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R10));
callee_save_regs_.push_back(ArmManagedRegister::FromCoreRegister(R11));
+
+ for (size_t i = 0; i < arraysize(kHFSCalleeSaveRegisters); ++i) {
+ callee_save_regs_.push_back(ArmManagedRegister::FromSRegister(kHFSCalleeSaveRegisters[i]));
+ }
}
uint32_t ArmJniCallingConvention::CoreSpillMask() const {
@@ -235,6 +243,14 @@ uint32_t ArmJniCallingConvention::CoreSpillMask() const {
return result;
}
+uint32_t ArmJniCallingConvention::FpSpillMask() const {
+ uint32_t result = 0;
+ for (size_t i = 0; i < arraysize(kHFSCalleeSaveRegisters); ++i) {
+ result |= (1 << kHFSCalleeSaveRegisters[i]);
+ }
+ return result;
+}
+
ManagedRegister ArmJniCallingConvention::ReturnScratchRegister() const {
return ArmManagedRegister::FromCoreRegister(R2);
}
diff --git a/compiler/jni/quick/arm/calling_convention_arm.h b/compiler/jni/quick/arm/calling_convention_arm.h
index 604ce1c..dbecb8e 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.h
+++ b/compiler/jni/quick/arm/calling_convention_arm.h
@@ -63,9 +63,7 @@ class ArmJniCallingConvention FINAL : public JniCallingConvention {
}
ManagedRegister ReturnScratchRegister() const OVERRIDE;
uint32_t CoreSpillMask() const OVERRIDE;
- uint32_t FpSpillMask() const OVERRIDE {
- return 0; // Floats aren't spilled in JNI down call
- }
+ uint32_t FpSpillMask() const OVERRIDE;
bool IsCurrentParamInRegister() OVERRIDE;
bool IsCurrentParamOnStack() OVERRIDE;
ManagedRegister CurrentParamRegister() OVERRIDE;
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index b9c8178..05eb80a 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -38,6 +38,10 @@ static const SRegister kSArgumentRegisters[] = {
S0, S1, S2, S3, S4, S5, S6, S7
};
+static const DRegister kDCalleeSaveRegisters[] = {
+ D8, D9, D10, D11, D12, D13, D14, D15
+};
+
// Calling convention
ManagedRegister Arm64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
return Arm64ManagedRegister::FromXRegister(X20); // saved on entry restored on exit
@@ -166,6 +170,10 @@ Arm64JniCallingConvention::Arm64JniCallingConvention(bool is_static, bool is_syn
callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X28));
callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X29));
callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X30));
+
+ for (size_t i = 0; i < arraysize(kDCalleeSaveRegisters); ++i) {
+ callee_save_regs_.push_back(Arm64ManagedRegister::FromDRegister(kDCalleeSaveRegisters[i]));
+ }
}
uint32_t Arm64JniCallingConvention::CoreSpillMask() const {
@@ -184,10 +192,11 @@ uint32_t Arm64JniCallingConvention::CoreSpillMask() const {
}
uint32_t Arm64JniCallingConvention::FpSpillMask() const {
- // Compute spill mask to agree with callee saves initialized in the constructor
- // Note: All callee-save fp registers will be preserved by aapcs64. And they are not used
- // in the jni method.
- return 0;
+ uint32_t result = 0;
+ for (size_t i = 0; i < arraysize(kDCalleeSaveRegisters); ++i) {
+ result |= (1 << kDCalleeSaveRegisters[i]);
+ }
+ return result;
}
ManagedRegister Arm64JniCallingConvention::ReturnScratchRegister() const {
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index a52e6eb..a02191b 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -385,12 +385,24 @@ void ArmAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
// Push callee saves and link register.
RegList push_list = 1 << LR;
size_t pushed_values = 1;
+ int32_t min_s = kNumberOfSRegisters;
+ int32_t max_s = -1;
for (size_t i = 0; i < callee_save_regs.size(); i++) {
- Register reg = callee_save_regs.at(i).AsArm().AsCoreRegister();
- push_list |= 1 << reg;
- pushed_values++;
+ if (callee_save_regs.at(i).AsArm().IsCoreRegister()) {
+ Register reg = callee_save_regs.at(i).AsArm().AsCoreRegister();
+ push_list |= 1 << reg;
+ pushed_values++;
+ } else {
+ CHECK(callee_save_regs.at(i).AsArm().IsSRegister());
+ min_s = std::min(static_cast<int>(callee_save_regs.at(i).AsArm().AsSRegister()), min_s);
+ max_s = std::max(static_cast<int>(callee_save_regs.at(i).AsArm().AsSRegister()), max_s);
+ }
}
PushList(push_list);
+ if (max_s != -1) {
+ pushed_values += 1 + max_s - min_s;
+ vpushs(static_cast<SRegister>(min_s), 1 + max_s - min_s);
+ }
// Increase frame to required size.
CHECK_GT(frame_size, pushed_values * kFramePointerSize); // Must at least have space for Method*.
@@ -427,10 +439,22 @@ void ArmAssembler::RemoveFrame(size_t frame_size,
// Compute callee saves to pop and PC.
RegList pop_list = 1 << PC;
size_t pop_values = 1;
+ int32_t min_s = kNumberOfSRegisters;
+ int32_t max_s = -1;
for (size_t i = 0; i < callee_save_regs.size(); i++) {
- Register reg = callee_save_regs.at(i).AsArm().AsCoreRegister();
- pop_list |= 1 << reg;
- pop_values++;
+ if (callee_save_regs.at(i).AsArm().IsCoreRegister()) {
+ Register reg = callee_save_regs.at(i).AsArm().AsCoreRegister();
+ pop_list |= 1 << reg;
+ pop_values++;
+ } else {
+ CHECK(callee_save_regs.at(i).AsArm().IsSRegister());
+ min_s = std::min(static_cast<int>(callee_save_regs.at(i).AsArm().AsSRegister()), min_s);
+ max_s = std::max(static_cast<int>(callee_save_regs.at(i).AsArm().AsSRegister()), max_s);
+ }
+ }
+
+ if (max_s != -1) {
+ pop_values += 1 + max_s - min_s;
}
// Decrease frame to start of callee saves.
@@ -438,6 +462,10 @@ void ArmAssembler::RemoveFrame(size_t frame_size,
size_t adjust = frame_size - (pop_values * kFramePointerSize);
DecreaseFrameSize(adjust);
+ if (max_s != -1) {
+ vpops(static_cast<SRegister>(min_s), 1 + max_s - min_s);
+ }
+
// Pop callee saves and PC.
PopList(pop_list);
}
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index 21014c8..58c7367 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -639,6 +639,7 @@ void Arm64Assembler::EmitExceptionPoll(Arm64Exception *exception) {
}
constexpr size_t kFramePointerSize = 8;
+constexpr unsigned int kJniRefSpillRegsSize = 11 + 8;
void Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
const std::vector<ManagedRegister>& callee_save_regs,
@@ -648,7 +649,7 @@ void Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
// TODO: *create APCS FP - end of FP chain;
// *add support for saving a different set of callee regs.
- // For now we check that the size of callee regs vector is 11.
+ // For now we check that the size of callee regs vector is 11 core registers and 8 fp registers.
CHECK_EQ(callee_save_regs.size(), kJniRefSpillRegsSize);
// Increase frame to required size - must be at least space to push StackReference<Method>.
CHECK_GT(frame_size, kJniRefSpillRegsSize * kFramePointerSize);
@@ -682,6 +683,23 @@ void Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
reg_offset -= 8;
StoreToOffset(X20, SP, reg_offset);
+ reg_offset -= 8;
+ StoreDToOffset(D15, SP, reg_offset);
+ reg_offset -= 8;
+ StoreDToOffset(D14, SP, reg_offset);
+ reg_offset -= 8;
+ StoreDToOffset(D13, SP, reg_offset);
+ reg_offset -= 8;
+ StoreDToOffset(D12, SP, reg_offset);
+ reg_offset -= 8;
+ StoreDToOffset(D11, SP, reg_offset);
+ reg_offset -= 8;
+ StoreDToOffset(D10, SP, reg_offset);
+ reg_offset -= 8;
+ StoreDToOffset(D9, SP, reg_offset);
+ reg_offset -= 8;
+ StoreDToOffset(D8, SP, reg_offset);
+
// Move TR(Caller saved) to ETR(Callee saved). The original (ETR)X21 has been saved on stack.
// This way we make sure that TR is not trashed by native code.
___ Mov(reg_x(ETR), reg_x(TR));
@@ -753,6 +771,23 @@ void Arm64Assembler::RemoveFrame(size_t frame_size, const std::vector<ManagedReg
reg_offset -= 8;
LoadFromOffset(X20, SP, reg_offset);
+ reg_offset -= 8;
+ LoadDFromOffset(D15, SP, reg_offset);
+ reg_offset -= 8;
+ LoadDFromOffset(D14, SP, reg_offset);
+ reg_offset -= 8;
+ LoadDFromOffset(D13, SP, reg_offset);
+ reg_offset -= 8;
+ LoadDFromOffset(D12, SP, reg_offset);
+ reg_offset -= 8;
+ LoadDFromOffset(D11, SP, reg_offset);
+ reg_offset -= 8;
+ LoadDFromOffset(D10, SP, reg_offset);
+ reg_offset -= 8;
+ LoadDFromOffset(D9, SP, reg_offset);
+ reg_offset -= 8;
+ LoadDFromOffset(D8, SP, reg_offset);
+
// Decrease frame size to start of callee saved regs.
DecreaseFrameSize(frame_size);
diff --git a/compiler/utils/arm64/constants_arm64.h b/compiler/utils/arm64/constants_arm64.h
index ffb54d3..01e8be9 100644
--- a/compiler/utils/arm64/constants_arm64.h
+++ b/compiler/utils/arm64/constants_arm64.h
@@ -29,8 +29,6 @@
namespace art {
namespace arm64 {
-constexpr unsigned int kJniRefSpillRegsSize = 11;
-
constexpr size_t kArm64BaseBufferSize = 4096;
} // namespace arm64
diff --git a/runtime/stack.cc b/runtime/stack.cc
index b39aebf..d570880 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -134,8 +134,7 @@ mirror::Object* StackVisitor::GetThisObject() const {
} else {
return cur_shadow_frame_->GetVRegReference(0);
}
- } else if (m->IsOptimized(GetInstructionSetPointerSize(
- Runtime::Current()->GetInstructionSet()))) {
+ } else if (m->IsOptimized(sizeof(void*))) {
// TODO: Implement, currently only used for exceptions when jdwp is enabled.
UNIMPLEMENTED(WARNING)
<< "StackVisitor::GetThisObject is unimplemented with the optimizing compiler";
@@ -163,42 +162,10 @@ bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
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(sizeof(void*));
- DCHECK(code_pointer != nullptr);
- const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
- QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
- uint32_t vmap_offset;
- // TODO: IsInContext stops before spotting floating point registers.
- if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
- bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
- uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
- uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
- if (!IsAccessibleRegister(reg, is_float)) {
- return false;
- }
- uintptr_t ptr_val = GetRegister(reg, is_float);
- 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);
- if (wide_lo) {
- ptr_val = static_cast<uintptr_t>(value_long & 0xFFFFFFFF);
- } else if (wide_hi) {
- ptr_val = static_cast<uintptr_t>(value_long >> 32);
- }
- }
- *val = ptr_val;
- return true;
+ if (m->IsOptimized(sizeof(void*))) {
+ return GetVRegFromOptimizedCode(m, vreg, kind, val);
} 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);
- DCHECK(addr != nullptr);
- *val = *addr;
- return true;
+ return GetVRegFromQuickCode(m, vreg, kind, val);
}
} else {
DCHECK(cur_shadow_frame_ != nullptr);
@@ -207,6 +174,86 @@ bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
}
}
+bool StackVisitor::GetVRegFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
+ uint32_t* val) const {
+ const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+ DCHECK(code_pointer != nullptr);
+ const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
+ QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
+ uint32_t vmap_offset;
+ // TODO: IsInContext stops before spotting floating point registers.
+ if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
+ bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+ uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
+ uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
+ return GetRegisterIfAccessible(reg, kind, val);
+ } 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?
+ *val = *GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
+ frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
+ return true;
+ }
+}
+
+bool StackVisitor::GetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
+ uint32_t* val) const {
+ const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+ DCHECK(code_pointer != nullptr);
+ uint32_t native_pc_offset = m->NativeQuickPcOffset(cur_quick_frame_pc_);
+ CodeInfo code_info = m->GetOptimizedCodeInfo();
+ StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+ const DexFile::CodeItem* code_item = m->GetCodeItem();
+ DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be NULL or how would we compile
+ // its instructions?
+ DCHECK_LT(vreg, code_item->registers_size_);
+ DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map,
+ code_item->registers_size_);
+ DexRegisterMap::LocationKind location_kind = dex_register_map.GetLocationKind(vreg);
+ switch (location_kind) {
+ case DexRegisterMap::kInStack: {
+ const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg);
+ const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset;
+ *val = *reinterpret_cast<const uint32_t*>(addr);
+ return true;
+ }
+ case DexRegisterMap::kInRegister:
+ case DexRegisterMap::kInFpuRegister: {
+ uint32_t reg = dex_register_map.GetMachineRegister(vreg);
+ return GetRegisterIfAccessible(reg, kind, val);
+ }
+ case DexRegisterMap::kConstant:
+ *val = dex_register_map.GetConstant(vreg);
+ return true;
+ case DexRegisterMap::kNone:
+ return false;
+ }
+ UNREACHABLE();
+ return false;
+}
+
+bool StackVisitor::GetRegisterIfAccessible(uint32_t reg, VRegKind kind, uint32_t* val) const {
+ const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+ if (!IsAccessibleRegister(reg, is_float)) {
+ return false;
+ }
+ uintptr_t ptr_val = GetRegister(reg, is_float);
+ const bool target64 = Is64BitInstructionSet(kRuntimeISA);
+ if (target64) {
+ const bool wide_lo = (kind == kLongLoVReg) || (kind == kDoubleLoVReg);
+ const bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
+ int64_t value_long = static_cast<int64_t>(ptr_val);
+ if (wide_lo) {
+ ptr_val = static_cast<uintptr_t>(Low32Bits(value_long));
+ } else if (wide_hi) {
+ ptr_val = static_cast<uintptr_t>(High32Bits(value_long));
+ }
+ }
+ *val = ptr_val;
+ return true;
+}
+
bool StackVisitor::GetVRegPair(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind_lo,
VRegKind kind_hi, uint64_t* val) const {
if (kind_lo == kLongLoVReg) {
@@ -215,45 +262,15 @@ bool StackVisitor::GetVRegPair(mirror::ArtMethod* m, uint16_t vreg, VRegKind kin
DCHECK_EQ(kind_hi, kDoubleHiVReg);
} else {
LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
+ UNREACHABLE();
}
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(sizeof(void*));
- DCHECK(code_pointer != nullptr);
- const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
- 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);
- if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) {
- return false;
- }
- uintptr_t ptr_val_lo = GetRegister(reg_lo, is_float);
- uintptr_t ptr_val_hi = GetRegister(reg_hi, is_float);
- 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;
+ if (m->IsOptimized(sizeof(void*))) {
+ return GetVRegPairFromOptimizedCode(m, vreg, kind_lo, kind_hi, val);
} 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);
- DCHECK(addr != nullptr);
- *val = *reinterpret_cast<uint64_t*>(addr);
- return true;
+ return GetVRegPairFromQuickCode(m, vreg, kind_lo, kind_hi, val);
}
} else {
DCHECK(cur_shadow_frame_ != nullptr);
@@ -262,61 +279,185 @@ bool StackVisitor::GetVRegPair(mirror::ArtMethod* m, uint16_t vreg, VRegKind kin
}
}
+bool StackVisitor::GetVRegPairFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind_lo,
+ VRegKind kind_hi, uint64_t* val) const {
+ const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+ DCHECK(code_pointer != nullptr);
+ const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
+ 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);
+ return GetRegisterPairIfAccessible(reg_lo, reg_hi, kind_lo, val);
+ } 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;
+ }
+}
+
+bool StackVisitor::GetVRegPairFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg,
+ VRegKind kind_lo, VRegKind kind_hi,
+ uint64_t* val) const {
+ uint32_t low_32bits;
+ uint32_t high_32bits;
+ bool success = GetVRegFromOptimizedCode(m, vreg, kind_lo, &low_32bits);
+ success &= GetVRegFromOptimizedCode(m, 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::GetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi,
+ VRegKind kind_lo, uint64_t* val) const {
+ const bool is_float = (kind_lo == kDoubleLoVReg);
+ if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) {
+ return false;
+ }
+ uintptr_t ptr_val_lo = GetRegister(reg_lo, is_float);
+ uintptr_t ptr_val_hi = GetRegister(reg_hi, is_float);
+ 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>(Low32Bits(value_long_lo));
+ ptr_val_hi = static_cast<uintptr_t>(High32Bits(value_long_hi));
+ }
+ *val = (static_cast<uint64_t>(ptr_val_hi) << 32) | static_cast<uint32_t>(ptr_val_lo);
+ return true;
+}
+
bool StackVisitor::SetVReg(mirror::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());
- const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
- DCHECK(code_pointer != nullptr);
- const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
- QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
- uint32_t vmap_offset;
- // TODO: IsInContext stops before spotting floating point registers.
- if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
- 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);
- if (!IsAccessibleRegister(reg, is_float)) {
- return false;
- }
- 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);
- bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
- if (wide_lo || wide_hi) {
- uintptr_t old_reg_val = GetRegister(reg, is_float);
- uint64_t new_vreg_portion = static_cast<uint64_t>(new_value);
- uint64_t old_reg_val_as_wide = static_cast<uint64_t>(old_reg_val);
- uint64_t mask = 0xffffffff;
- if (wide_lo) {
- mask = mask << 32;
- } else {
- new_vreg_portion = new_vreg_portion << 32;
- }
- new_value = static_cast<uintptr_t>((old_reg_val_as_wide & mask) | new_vreg_portion);
- }
+ DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
+ DCHECK(m == GetMethod());
+ if (m->IsOptimized(sizeof(void*))) {
+ return SetVRegFromOptimizedCode(m, vreg, new_value, kind);
+ } else {
+ return SetVRegFromQuickCode(m, vreg, new_value, kind);
}
- SetRegister(reg, new_value, is_float);
- 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);
- DCHECK(addr != nullptr);
- *addr = new_value;
+ cur_shadow_frame_->SetVReg(vreg, new_value);
return true;
}
+}
+
+bool StackVisitor::SetVRegFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value,
+ VRegKind kind) {
+ DCHECK(context_ != nullptr); // You can't reliably write registers without a context.
+ DCHECK(m == GetMethod());
+ const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+ DCHECK(code_pointer != nullptr);
+ const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
+ QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer);
+ uint32_t vmap_offset;
+ // TODO: IsInContext stops before spotting floating point registers.
+ if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) {
+ bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
+ uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
+ uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
+ return SetRegisterIfAccessible(reg, new_value, kind);
} else {
- DCHECK(cur_shadow_frame_ != nullptr);
- cur_shadow_frame_->SetVReg(vreg, new_value);
+ 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);
+ *addr = new_value;
return true;
}
}
+bool StackVisitor::SetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value,
+ VRegKind kind) {
+ const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+ DCHECK(code_pointer != nullptr);
+ uint32_t native_pc_offset = m->NativeQuickPcOffset(cur_quick_frame_pc_);
+ CodeInfo code_info = m->GetOptimizedCodeInfo();
+ StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+ const DexFile::CodeItem* code_item = m->GetCodeItem();
+ DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be NULL or how would we compile
+ // its instructions?
+ DCHECK_LT(vreg, code_item->registers_size_);
+ DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map,
+ code_item->registers_size_);
+ DexRegisterMap::LocationKind location_kind = dex_register_map.GetLocationKind(vreg);
+ uint32_t dex_pc = m->ToDexPc(cur_quick_frame_pc_, false);
+ switch (location_kind) {
+ case DexRegisterMap::kInStack: {
+ const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg);
+ uint8_t* addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + offset;
+ *reinterpret_cast<uint32_t*>(addr) = new_value;
+ return true;
+ }
+ case DexRegisterMap::kInRegister:
+ case DexRegisterMap::kInFpuRegister: {
+ uint32_t reg = dex_register_map.GetMachineRegister(vreg);
+ return SetRegisterIfAccessible(reg, new_value, kind);
+ }
+ case DexRegisterMap::kConstant:
+ LOG(ERROR) << StringPrintf("Cannot change value of DEX register v%u used as a constant at "
+ "DEX pc 0x%x (native pc 0x%x) of method %s",
+ vreg, dex_pc, native_pc_offset,
+ PrettyMethod(cur_quick_frame_->AsMirrorPtr()).c_str());
+ return false;
+ case DexRegisterMap::kNone:
+ LOG(ERROR) << StringPrintf("No location for DEX register v%u at DEX pc 0x%x "
+ "(native pc 0x%x) of method %s",
+ vreg, dex_pc, native_pc_offset,
+ PrettyMethod(cur_quick_frame_->AsMirrorPtr()).c_str());
+ return false;
+ default:
+ LOG(FATAL) << StringPrintf("Unknown location for DEX register v%u at DEX pc 0x%x "
+ "(native pc 0x%x) of method %s",
+ vreg, dex_pc, native_pc_offset,
+ PrettyMethod(cur_quick_frame_->AsMirrorPtr()).c_str());
+ UNREACHABLE();
+ }
+}
+
+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)) {
+ return false;
+ }
+ const bool target64 = Is64BitInstructionSet(kRuntimeISA);
+
+ // Create a new value that can hold both low 32 and high 32 bits, in
+ // case we are running 64 bits.
+ uintptr_t full_new_value = new_value;
+ // 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);
+ bool wide_hi = (kind == kLongHiVReg) || (kind == kDoubleHiVReg);
+ if (wide_lo || wide_hi) {
+ uintptr_t old_reg_val = GetRegister(reg, is_float);
+ uint64_t new_vreg_portion = static_cast<uint64_t>(new_value);
+ uint64_t old_reg_val_as_wide = static_cast<uint64_t>(old_reg_val);
+ uint64_t mask = 0xffffffff;
+ if (wide_lo) {
+ mask = mask << 32;
+ } else {
+ new_vreg_portion = new_vreg_portion << 32;
+ }
+ full_new_value = static_cast<uintptr_t>((old_reg_val_as_wide & mask) | new_vreg_portion);
+ }
+ }
+ SetRegister(reg, full_new_value, is_float);
+ return true;
+}
+
bool StackVisitor::SetVRegPair(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
VRegKind kind_lo, VRegKind kind_hi) {
if (kind_lo == kLongLoVReg) {
@@ -329,49 +470,10 @@ bool StackVisitor::SetVRegPair(mirror::ArtMethod* m, uint16_t vreg, uint64_t new
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(sizeof(void*));
- DCHECK(code_pointer != nullptr);
- const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
- 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);
- if (!IsAccessibleRegister(reg_lo, is_float) || !IsAccessibleRegister(reg_hi, is_float)) {
- return false;
- }
- 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 = GetRegister(reg_lo, is_float);
- uintptr_t old_reg_val_hi = GetRegister(reg_hi, is_float);
- 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);
- }
- SetRegister(reg_lo, new_value_lo, is_float);
- SetRegister(reg_hi, new_value_hi, is_float);
- return true;
+ if (m->IsOptimized(sizeof(void*))) {
+ return SetVRegPairFromOptimizedCode(m, vreg, new_value, kind_lo, kind_hi);
} 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);
- DCHECK(addr != nullptr);
- *reinterpret_cast<uint64_t*>(addr) = new_value;
- return true;
+ return SetVRegPairFromQuickCode(m, vreg, new_value, kind_lo, kind_hi);
}
} else {
DCHECK(cur_shadow_frame_ != nullptr);
@@ -380,6 +482,60 @@ bool StackVisitor::SetVRegPair(mirror::ArtMethod* m, uint16_t vreg, uint64_t new
}
}
+bool StackVisitor::SetVRegPairFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
+ VRegKind kind_lo, VRegKind kind_hi) {
+ const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
+ DCHECK(code_pointer != nullptr);
+ const VmapTable vmap_table(m->GetVmapTable(code_pointer, sizeof(void*)));
+ 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);
+ return SetRegisterPairIfAccessible(reg_lo, reg_hi, new_value, is_float);
+ } 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;
+ }
+}
+
+bool StackVisitor::SetVRegPairFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
+ VRegKind kind_lo, VRegKind kind_hi) {
+ uint32_t low_32bits = Low32Bits(new_value);
+ uint32_t high_32bits = High32Bits(new_value);
+ bool success = SetVRegFromOptimizedCode(m, vreg, low_32bits, kind_lo);
+ success &= SetVRegFromOptimizedCode(m, vreg + 1, high_32bits, kind_hi);
+ return success;
+}
+
+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)) {
+ return false;
+ }
+ 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) {
+ DCHECK_EQ(reg_lo, reg_hi);
+ SetRegister(reg_lo, new_value, is_float);
+ } else {
+ SetRegister(reg_lo, new_value_lo, is_float);
+ SetRegister(reg_hi, new_value_hi, is_float);
+ }
+ return true;
+}
+
bool StackVisitor::IsAccessibleGPR(uint32_t reg) const {
DCHECK(context_ != nullptr);
return context_->IsAccessibleGPR(reg);
diff --git a/runtime/stack.h b/runtime/stack.h
index 5a86ca1..b495f03 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -492,7 +492,8 @@ class StackVisitor {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
uint32_t val;
bool success = GetVReg(m, vreg, kind, &val);
- CHECK(success) << "Failed to read vreg " << vreg << " of kind " << kind;
+ CHECK(success) << "Failed to read v" << vreg << " of kind " << kind << " in method "
+ << PrettyMethod(m);
return val;
}
@@ -505,7 +506,8 @@ class StackVisitor {
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 << "]";
+ << " of kind [" << kind_lo << "," << kind_hi << "] in method "
+ << PrettyMethod(m);
return val;
}
@@ -673,6 +675,45 @@ class StackVisitor {
uintptr_t GetFPR(uint32_t reg) const;
void SetFPR(uint32_t reg, uintptr_t value);
+ bool GetVRegFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
+ uint32_t* val) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool GetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
+ uint32_t* val) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool GetRegisterIfAccessible(uint32_t reg, VRegKind kind, uint32_t* val) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ bool GetVRegPairFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind_lo,
+ VRegKind kind_hi, uint64_t* val) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool GetVRegPairFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg,
+ VRegKind kind_lo, VRegKind kind_hi,
+ uint64_t* val) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool GetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, VRegKind kind_lo,
+ uint64_t* val) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ bool SetVRegFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value,
+ VRegKind kind)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool SetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value,
+ VRegKind kind)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool SetRegisterIfAccessible(uint32_t reg, uint32_t new_value, VRegKind kind)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ bool SetVRegPairFromQuickCode(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
+ VRegKind kind_lo, VRegKind kind_hi)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool SetVRegPairFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, uint64_t new_value,
+ VRegKind kind_lo, VRegKind kind_hi)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool SetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, uint64_t new_value,
+ bool is_float)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void SanityCheckFrame() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Thread* const thread_;
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index fd22361..ec37699 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -104,10 +104,9 @@ class DexRegisterMap {
return "in fpu register";
case kConstant:
return "as constant";
- default:
- LOG(FATAL) << "Invalid location kind " << static_cast<int>(kind);
- return nullptr;
}
+ UNREACHABLE();
+ return nullptr;
}
LocationKind GetLocationKind(uint16_t register_index) const {
@@ -126,6 +125,23 @@ class DexRegisterMap {
kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize());
}
+ int32_t GetStackOffsetInBytes(uint16_t register_index) const {
+ DCHECK(GetLocationKind(register_index) == kInStack);
+ // We currently encode the offset in bytes.
+ return GetValue(register_index);
+ }
+
+ int32_t GetConstant(uint16_t register_index) const {
+ DCHECK(GetLocationKind(register_index) == kConstant);
+ return GetValue(register_index);
+ }
+
+ int32_t GetMachineRegister(uint16_t register_index) const {
+ DCHECK(GetLocationKind(register_index) == kInRegister
+ || GetLocationKind(register_index) == kInFpuRegister);
+ return GetValue(register_index);
+ }
+
static size_t SingleEntrySize() {
return sizeof(LocationKind) + sizeof(int32_t);
}
diff --git a/test/454-get-vreg/expected.txt b/test/454-get-vreg/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/454-get-vreg/expected.txt
diff --git a/test/454-get-vreg/get_vreg_jni.cc b/test/454-get-vreg/get_vreg_jni.cc
new file mode 100644
index 0000000..937d2fe
--- /dev/null
+++ b/test/454-get-vreg/get_vreg_jni.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "arch/context.h"
+#include "jni.h"
+#include "mirror/art_method-inl.h"
+#include "scoped_thread_state_change.h"
+#include "stack.h"
+#include "thread.h"
+
+namespace art {
+
+namespace {
+
+class TestVisitor : public StackVisitor {
+ public:
+ TestVisitor(Thread* thread, Context* context, mirror::Object* this_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : StackVisitor(thread, context), this_value_(this_value), found_method_index_(0) {}
+
+ bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::ArtMethod* m = GetMethod();
+ std::string m_name(m->GetName());
+
+ if (m_name.compare("testSimpleVReg") == 0) {
+ found_method_index_ = 1;
+ uint32_t value = 0;
+
+ CHECK(GetVReg(m, 0, kIntVReg, &value));
+ CHECK_EQ(value, 42u);
+
+ bool success = GetVReg(m, 1, kIntVReg, &value);
+ if (m->IsOptimized(sizeof(void*))) CHECK(!success);
+
+ success = GetVReg(m, 2, kIntVReg, &value);
+ if (m->IsOptimized(sizeof(void*))) CHECK(!success);
+
+ CHECK(GetVReg(m, 3, kReferenceVReg, &value));
+ CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
+
+ CHECK(GetVReg(m, 4, kIntVReg, &value));
+ CHECK_EQ(value, 1u);
+
+ CHECK(GetVReg(m, 5, kFloatVReg, &value));
+ uint32_t cast = bit_cast<float, uint32_t>(1.0f);
+ CHECK_EQ(value, cast);
+
+ CHECK(GetVReg(m, 6, kIntVReg, &value));
+ CHECK_EQ(value, 2u);
+
+ CHECK(GetVReg(m, 7, kIntVReg, &value));
+ CHECK_EQ(value, true);
+
+ CHECK(GetVReg(m, 8, kIntVReg, &value));
+ CHECK_EQ(value, 3u);
+
+ CHECK(GetVReg(m, 9, kIntVReg, &value));
+ CHECK_EQ(value, static_cast<uint32_t>('c'));
+ } else if (m_name.compare("testPairVReg") == 0) {
+ found_method_index_ = 2;
+ uint64_t value = 0;
+ CHECK(GetVRegPair(m, 0, kLongLoVReg, kLongHiVReg, &value));
+ CHECK_EQ(value, 42u);
+
+ bool success = GetVRegPair(m, 2, kLongLoVReg, kLongHiVReg, &value);
+ if (m->IsOptimized(sizeof(void*))) CHECK(!success);
+
+ success = GetVRegPair(m, 4, kLongLoVReg, kLongHiVReg, &value);
+ if (m->IsOptimized(sizeof(void*))) CHECK(!success);
+
+ uint32_t value32 = 0;
+ CHECK(GetVReg(m, 6, kReferenceVReg, &value32));
+ CHECK_EQ(reinterpret_cast<mirror::Object*>(value32), this_value_);
+
+ CHECK(GetVRegPair(m, 7, kLongLoVReg, kLongHiVReg, &value));
+ CHECK_EQ(static_cast<int64_t>(value), std::numeric_limits<int64_t>::min());
+
+ CHECK(GetVRegPair(m, 9, kLongLoVReg, kLongHiVReg, &value));
+ CHECK_EQ(static_cast<int64_t>(value), std::numeric_limits<int64_t>::max());
+
+ CHECK(GetVRegPair(m, 11, kLongLoVReg, kLongHiVReg, &value));
+ CHECK_EQ(value, 0u);
+
+ CHECK(GetVRegPair(m, 13, kDoubleLoVReg, kDoubleHiVReg, &value));
+ uint64_t cast = bit_cast<double, uint64_t>(2.0);
+ CHECK_EQ(value, cast);
+ }
+
+ return true;
+ }
+
+ mirror::Object* this_value_;
+
+ // Value returned to Java to ensure the methods testSimpleVReg and testPairVReg
+ // have been found and tested.
+ jint found_method_index_;
+};
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_doNativeCall(JNIEnv*, jobject value) {
+ ScopedObjectAccess soa(Thread::Current());
+ std::unique_ptr<Context> context(Context::Create());
+ TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object*>(value));
+ visitor.WalkStack();
+ return visitor.found_method_index_;
+}
+
+} // namespace
+
+} // namespace art
diff --git a/test/454-get-vreg/info.txt b/test/454-get-vreg/info.txt
new file mode 100644
index 0000000..20df0b5
--- /dev/null
+++ b/test/454-get-vreg/info.txt
@@ -0,0 +1 @@
+Tests for inspecting DEX registers in a Java method.
diff --git a/test/454-get-vreg/src/Main.java b/test/454-get-vreg/src/Main.java
new file mode 100644
index 0000000..df07d44
--- /dev/null
+++ b/test/454-get-vreg/src/Main.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public Main() {
+ }
+
+ int testSimpleVReg(int a, float f, short s, boolean z, byte b, char c) {
+ int e = doCall();
+ int g = doNativeCall();
+ return e + g;
+ }
+
+ long testPairVReg(long a, long b, long c, double e) {
+ long f = doCall();
+ long g = doNativeCall();
+ return f + g;
+ }
+
+ native int doNativeCall();
+
+ int doCall() {
+ return 42;
+ }
+
+ static {
+ System.loadLibrary("arttest");
+ }
+
+ public static void main(String[] args) {
+ Main rm = new Main();
+ if (rm.testSimpleVReg(1, 1.0f, (short)2, true, (byte)3, 'c') != 43) {
+ throw new Error("Expected 43");
+ }
+
+ if (rm.testPairVReg(Long.MIN_VALUE, Long.MAX_VALUE, 0, 2.0) != 44) {
+ throw new Error("Expected 44");
+ }
+ }
+}
diff --git a/test/455-set-vreg/expected.txt b/test/455-set-vreg/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/455-set-vreg/expected.txt
diff --git a/test/455-set-vreg/info.txt b/test/455-set-vreg/info.txt
new file mode 100644
index 0000000..e8c57b5
--- /dev/null
+++ b/test/455-set-vreg/info.txt
@@ -0,0 +1 @@
+Tests for setting DEX registers in a Java method.
diff --git a/test/455-set-vreg/set_vreg_jni.cc b/test/455-set-vreg/set_vreg_jni.cc
new file mode 100644
index 0000000..24d7832
--- /dev/null
+++ b/test/455-set-vreg/set_vreg_jni.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "arch/context.h"
+#include "jni.h"
+#include "mirror/art_method-inl.h"
+#include "scoped_thread_state_change.h"
+#include "stack.h"
+#include "thread.h"
+
+namespace art {
+
+namespace {
+
+class TestVisitor : public StackVisitor {
+ public:
+ TestVisitor(Thread* thread, Context* context, mirror::Object* this_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : StackVisitor(thread, context), this_value_(this_value) {}
+
+ bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::ArtMethod* m = GetMethod();
+ std::string m_name(m->GetName());
+
+ if (m_name.compare("testIntVReg") == 0) {
+ uint32_t value = 0;
+ CHECK(GetVReg(m, 1, kReferenceVReg, &value));
+ CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
+
+ CHECK(SetVReg(m, 2, 5, kIntVReg));
+ CHECK(SetVReg(m, 3, 4, kIntVReg));
+ CHECK(SetVReg(m, 4, 3, kIntVReg));
+ CHECK(SetVReg(m, 5, 2, kIntVReg));
+ CHECK(SetVReg(m, 6, 1, kIntVReg));
+ } else if (m_name.compare("testLongVReg") == 0) {
+ uint32_t value = 0;
+ CHECK(GetVReg(m, 3, kReferenceVReg, &value));
+ CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
+
+ CHECK(SetVRegPair(m, 4, std::numeric_limits<int64_t>::max(), kLongLoVReg, kLongHiVReg));
+ CHECK(SetVRegPair(m, 6, 4, kLongLoVReg, kLongHiVReg));
+ CHECK(SetVRegPair(m, 8, 3, kLongLoVReg, kLongHiVReg));
+ CHECK(SetVRegPair(m, 10, 2, kLongLoVReg, kLongHiVReg));
+ CHECK(SetVRegPair(m, 12, 1, kLongLoVReg, kLongHiVReg));
+ } else if (m_name.compare("testFloatVReg") == 0) {
+ uint32_t value = 0;
+ CHECK(GetVReg(m, 1, kReferenceVReg, &value));
+ CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
+
+ CHECK(SetVReg(m, 2, bit_cast<float, uint32_t>(5.0f), kFloatVReg));
+ CHECK(SetVReg(m, 3, bit_cast<float, uint32_t>(4.0f), kFloatVReg));
+ CHECK(SetVReg(m, 4, bit_cast<float, uint32_t>(3.0f), kFloatVReg));
+ CHECK(SetVReg(m, 5, bit_cast<float, uint32_t>(2.0f), kFloatVReg));
+ CHECK(SetVReg(m, 6, bit_cast<float, uint32_t>(1.0f), kFloatVReg));
+ } else if (m_name.compare("testDoubleVReg") == 0) {
+ uint32_t value = 0;
+ CHECK(GetVReg(m, 3, kReferenceVReg, &value));
+ CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
+
+ CHECK(SetVRegPair(m, 4, bit_cast<double, uint64_t>(5.0), kDoubleLoVReg, kDoubleHiVReg));
+ CHECK(SetVRegPair(m, 6, bit_cast<double, uint64_t>(4.0), kDoubleLoVReg, kDoubleHiVReg));
+ CHECK(SetVRegPair(m, 8, bit_cast<double, uint64_t>(3.0), kDoubleLoVReg, kDoubleHiVReg));
+ CHECK(SetVRegPair(m, 10, bit_cast<double, uint64_t>(2.0), kDoubleLoVReg, kDoubleHiVReg));
+ CHECK(SetVRegPair(m, 12, bit_cast<double, uint64_t>(1.0), kDoubleLoVReg, kDoubleHiVReg));
+ }
+
+ return true;
+ }
+
+ mirror::Object* this_value_;
+};
+
+extern "C" JNIEXPORT void JNICALL Java_Main_doNativeCallSetVReg(JNIEnv*, jobject value) {
+ ScopedObjectAccess soa(Thread::Current());
+ std::unique_ptr<Context> context(Context::Create());
+ TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object*>(value));
+ visitor.WalkStack();
+}
+
+} // namespace
+
+} // namespace art
diff --git a/test/455-set-vreg/src/Main.java b/test/455-set-vreg/src/Main.java
new file mode 100644
index 0000000..2172d92
--- /dev/null
+++ b/test/455-set-vreg/src/Main.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public Main() {
+ }
+
+ int testIntVReg(int a, int b, int c, int d, int e) {
+ doNativeCallSetVReg();
+ return a - b - c - d - e;
+ }
+
+ long testLongVReg(long a, long b, long c, long d, long e) {
+ doNativeCallSetVReg();
+ return a - b - c - d - e;
+ }
+
+ float testFloatVReg(float a, float b, float c, float d, float e) {
+ doNativeCallSetVReg();
+ return a - b - c - d - e;
+ }
+
+ double testDoubleVReg(double a, double b, double c, double d, double e) {
+ doNativeCallSetVReg();
+ return a - b - c - d - e;
+ }
+
+ native void doNativeCallSetVReg();
+
+ static {
+ System.loadLibrary("arttest");
+ }
+
+ public static void main(String[] args) {
+ Main rm = new Main();
+ int intExpected = 5 - 4 - 3 - 2 - 1;
+ int intResult = rm.testIntVReg(0, 0, 0, 0, 0);
+ if (intResult != intExpected) {
+ throw new Error("Expected " + intExpected + ", got " + intResult);
+ }
+
+ long longExpected = Long.MAX_VALUE - 4 - 3 - 2 - 1;
+ long longResult = rm.testLongVReg(0, 0, 0, 0, 0);
+ if (longResult != longExpected) {
+ throw new Error("Expected " + longExpected + ", got " + longResult);
+ }
+
+ float floatExpected = 5.0f - 4.0f - 3.0f - 2.0f - 1.0f;
+ float floatResult = rm.testFloatVReg(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ if (floatResult != floatExpected) {
+ throw new Error("Expected " + floatExpected + ", got " + floatResult);
+ }
+
+ double doubleExpected = 5.0 - 4.0 - 3.0 - 2.0 - 1.0;
+ double doubleResult = rm.testDoubleVReg(0.0, 0.0, 0.0, 0.0, 0.0);
+ if (doubleResult != doubleExpected) {
+ throw new Error("Expected " + doubleExpected + ", got " + doubleResult);
+ }
+ }
+}
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index e64df5c..75c5d72 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -27,7 +27,9 @@ LIBARTTEST_COMMON_SRC_FILES := \
051-thread/thread_test.cc \
116-nodex2oat/nodex2oat.cc \
117-nopatchoat/nopatchoat.cc \
- 118-noimage-dex2oat/noimage-dex2oat.cc
+ 118-noimage-dex2oat/noimage-dex2oat.cc \
+ 454-get-vreg/get_vreg_jni.cc \
+ 455-set-vreg/set_vreg_jni.cc
ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
ifdef TARGET_2ND_ARCH
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index ee40ee8..7a2ad1c 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -361,8 +361,8 @@ if [ "$HOST" = "n" ]; then
export ANDROID_DATA=$DEX_LOCATION && \
export DEX_LOCATION=$DEX_LOCATION && \
export ANDROID_ROOT=$ANDROID_ROOT && \
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH && \
$mkdir_cmdline && \
+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH && \
$dex2oat_cmdline && \
$dalvikvm_cmdline"