Fix sign extension issues in x86_64 code generation
movl expects an Immediate int64_t that is in the range -2GB to
2GB. Cast uint32_t addresses to int32_t before passing as an
Immediate to movl.
In VisitIntegerValueOf, the base address may not fit in the disp32
field. Fall back to storing the base address in a temporary
register if it is larger than 2GB.
Bug: 36281983
Test: m -j test-art-host with LibartImgHostBaseAddress == 0xa0000000
Change-Id: I5f8cc4f5a6220afc577707e3831113b0ead1d2b2
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 9a6dd98..1e17c6e 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -3018,13 +3018,14 @@
mirror::Object* boxed = info.cache->Get(value + (-info.low));
DCHECK(boxed != nullptr && Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(boxed));
uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(boxed));
- __ movl(out, Immediate(address));
+ __ movl(out, Immediate(static_cast<int32_t>(address)));
} else {
// Allocate and initialize a new j.l.Integer.
// TODO: If we JIT, we could allocate the j.l.Integer now, and store it in the
// JIT object table.
+ CpuRegister argument = CpuRegister(calling_convention.GetRegisterAt(0));
uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
- __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(address));
+ __ movl(argument, Immediate(static_cast<int32_t>(address)));
codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
__ movl(Address(out, info.value_offset), Immediate(value));
@@ -3039,13 +3040,20 @@
// If the value is within the bounds, load the j.l.Integer directly from the array.
uint32_t data_offset = mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.cache));
- __ movl(out, Address(out, TIMES_4, data_offset + address));
+ if (data_offset + address <= std::numeric_limits<int32_t>::max()) {
+ __ movl(out, Address(out, TIMES_4, data_offset + address));
+ } else {
+ CpuRegister temp = CpuRegister(calling_convention.GetRegisterAt(0));
+ __ movl(temp, Immediate(static_cast<int32_t>(data_offset + address)));
+ __ movl(out, Address(temp, out, TIMES_4, 0));
+ }
__ MaybeUnpoisonHeapReference(out);
__ jmp(&done);
__ Bind(&allocate);
// Otherwise allocate and initialize a new j.l.Integer.
+ CpuRegister argument = CpuRegister(calling_convention.GetRegisterAt(0));
address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
- __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(address));
+ __ movl(argument, Immediate(static_cast<int32_t>(address)));
codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
__ movl(Address(out, info.value_offset), in);