ART: Use StackReference in Quick Stack Frame
The method reference at the bottom of a quick frame is a stack
reference and not a native pointer. This is important for 64b
architectures, where the notions do not coincide.
Change key methods to have StackReference<mirror::ArtMethod>*
parameter instead of mirror::ArtMethod**. Make changes to
invoke stubs for 64b archs, change the frame setup for JNI code
(both generic JNI and compilers), tie up loose ends.
Tested on x86 and x86-64 with host tests. On x86-64, tests succeed
with jni compiler activated. x86-64 QCG was not tested.
Tested on ARM32 with device tests.
Fix ARM64 not saving x19 (used for wSUSPEND) on upcalls.
Tested on ARM64 in interpreter-only + generic-jni mode.
Fix ARM64 JNI Compiler to work with the CL.
Tested on ARM64 in interpreter-only + jni compiler.
Change-Id: I77931a0cbadd04d163b3eb8d6f6a6f8740578f13
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index 27188b2..009b227 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -530,7 +530,7 @@
Arm64ManagedRegister scratch = m_scratch.AsArm64();
CHECK(scratch.IsCoreRegister()) << scratch;
// Call *(*(SP + base) + offset)
- LoadFromOffset(scratch.AsCoreRegister(), SP, base.Int32Value());
+ LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(), SP, base.Int32Value());
LoadFromOffset(scratch.AsCoreRegister(), scratch.AsCoreRegister(), offs.Int32Value());
___ Blr(reg_x(scratch.AsCoreRegister()));
}
@@ -656,16 +656,17 @@
// trashed by native code.
___ Mov(reg_x(ETR), reg_x(TR));
- // Increate frame to required size - must be at least space to push Method*.
+ // Increase frame to required size - must be at least space to push StackReference<Method>.
CHECK_GT(frame_size, kCalleeSavedRegsSize * kFramePointerSize);
size_t adjust = frame_size - (kCalleeSavedRegsSize * kFramePointerSize);
IncreaseFrameSize(adjust);
- // Write Method*.
- StoreToOffset(X0, SP, 0);
+ // Write StackReference<Method>.
+ DCHECK_EQ(4U, sizeof(StackReference<mirror::ArtMethod>));
+ StoreWToOffset(StoreOperandType::kStoreWord, W0, SP, 0);
// Write out entry spills
- int32_t offset = frame_size + kFramePointerSize;
+ int32_t offset = frame_size + sizeof(StackReference<mirror::ArtMethod>);
for (size_t i = 0; i < entry_spills.size(); ++i) {
Arm64ManagedRegister reg = entry_spills.at(i).AsArm64();
if (reg.IsNoRegister()) {
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 0791c63..56c6536 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1411,10 +1411,12 @@
}
// return address then method on stack
addl(ESP, Immediate(-frame_size + (spill_regs.size() * kFramePointerSize) +
- kFramePointerSize /*method*/ + kFramePointerSize /*return address*/));
+ sizeof(StackReference<mirror::ArtMethod>) /*method*/ +
+ kFramePointerSize /*return address*/));
pushl(method_reg.AsX86().AsCpuRegister());
for (size_t i = 0; i < entry_spills.size(); ++i) {
- movl(Address(ESP, frame_size + kFramePointerSize + (i * kFramePointerSize)),
+ movl(Address(ESP, frame_size + sizeof(StackReference<mirror::ArtMethod>) +
+ (i * kFramePointerSize)),
entry_spills.at(i).AsX86().AsCpuRegister());
}
}
@@ -1422,7 +1424,8 @@
void X86Assembler::RemoveFrame(size_t frame_size,
const std::vector<ManagedRegister>& spill_regs) {
CHECK_ALIGNED(frame_size, kStackAlignment);
- addl(ESP, Immediate(frame_size - (spill_regs.size() * kFramePointerSize) - kFramePointerSize));
+ addl(ESP, Immediate(frame_size - (spill_regs.size() * kFramePointerSize) -
+ sizeof(StackReference<mirror::ArtMethod>)));
for (size_t i = 0; i < spill_regs.size(); ++i) {
popl(spill_regs.at(i).AsX86().AsCpuRegister());
}
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 0ede875..a14551c 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -59,7 +59,6 @@
EmitLabel(label, kSize);
}
-
void X86_64Assembler::pushq(CpuRegister reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitOptionalRex32(reg);
@@ -1652,8 +1651,12 @@
}
// return address then method on stack
addq(CpuRegister(RSP), Immediate(-frame_size + (spill_regs.size() * kFramePointerSize) +
- kFramePointerSize /*method*/ + kFramePointerSize /*return address*/));
- pushq(method_reg.AsX86_64().AsCpuRegister());
+ sizeof(StackReference<mirror::ArtMethod>) /*method*/ +
+ kFramePointerSize /*return address*/));
+
+ DCHECK_EQ(4U, sizeof(StackReference<mirror::ArtMethod>));
+ subq(CpuRegister(RSP), Immediate(4));
+ movl(Address(CpuRegister(RSP), 0), method_reg.AsX86_64().AsCpuRegister());
for (size_t i = 0; i < entry_spills.size(); ++i) {
ManagedRegisterSpill spill = entry_spills.at(i);
@@ -1732,7 +1735,7 @@
void X86_64Assembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
X86_64ManagedRegister src = msrc.AsX86_64();
CHECK(src.IsCpuRegister());
- movq(Address(CpuRegister(RSP), dest), src.AsCpuRegister());
+ movl(Address(CpuRegister(RSP), dest), src.AsCpuRegister());
}
void X86_64Assembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
@@ -2070,7 +2073,7 @@
void X86_64Assembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
CpuRegister scratch = mscratch.AsX86_64().AsCpuRegister();
- movq(scratch, Address(CpuRegister(RSP), base));
+ movl(scratch, Address(CpuRegister(RSP), base));
call(Address(scratch, offset));
}