summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/optimizing/code_generator_arm.cc49
-rw-r--r--compiler/optimizing/code_generator_arm.h20
-rw-r--r--compiler/optimizing/code_generator_arm64.cc95
-rw-r--r--compiler/optimizing/code_generator_arm64.h22
-rw-r--r--compiler/optimizing/code_generator_x86.cc23
-rw-r--r--compiler/optimizing/code_generator_x86.h17
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc23
-rw-r--r--compiler/optimizing/code_generator_x86_64.h17
-rw-r--r--compiler/optimizing/intrinsics_arm.cc50
-rw-r--r--compiler/optimizing/intrinsics_arm64.cc51
-rw-r--r--compiler/optimizing/intrinsics_x86.cc38
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc50
-rw-r--r--compiler/optimizing/locations.h10
-rw-r--r--compiler/utils/string_reference.h7
-rw-r--r--compiler/utils/string_reference_test.cc107
15 files changed, 402 insertions, 177 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index b9466ba212..83b4705302 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -430,7 +430,9 @@ class ReadBarrierMarkSlowPathARM : public SlowPathCode {
instruction_->IsLoadClass() ||
instruction_->IsLoadString() ||
instruction_->IsInstanceOf() ||
- instruction_->IsCheckCast())
+ instruction_->IsCheckCast() ||
+ ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
+ instruction_->GetLocations()->Intrinsified()))
<< "Unexpected instruction in read barrier marking slow path: "
<< instruction_->DebugName();
@@ -493,8 +495,12 @@ class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
Register reg_out = out_.AsRegister<Register>();
DCHECK(locations->CanCall());
DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
- DCHECK(!instruction_->IsInvoke() ||
- (instruction_->IsInvokeStaticOrDirect() &&
+ DCHECK(instruction_->IsInstanceFieldGet() ||
+ instruction_->IsStaticFieldGet() ||
+ instruction_->IsArrayGet() ||
+ instruction_->IsInstanceOf() ||
+ instruction_->IsCheckCast() ||
+ ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
instruction_->GetLocations()->Intrinsified()))
<< "Unexpected instruction in read barrier for heap reference slow path: "
<< instruction_->DebugName();
@@ -507,7 +513,7 @@ class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
// introduce a copy of it, `index`.
Location index = index_;
if (index_.IsValid()) {
- // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
+ // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
if (instruction_->IsArrayGet()) {
// Compute the actual memory offset and store it in `index`.
Register index_reg = index_.AsRegister<Register>();
@@ -555,7 +561,11 @@ class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode {
"art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
__ AddConstant(index_reg, index_reg, offset_);
} else {
- DCHECK(instruction_->IsInvoke());
+ // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
+ // intrinsics, `index_` is not shifted by a scale factor of 2
+ // (as in the case of ArrayGet), as it is actually an offset
+ // to an object field within an object.
+ DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
DCHECK(instruction_->GetLocations()->Intrinsified());
DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
(instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
@@ -6203,8 +6213,9 @@ void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instr
// /* HeapReference<Object> */ ref = *(obj + offset)
Location no_index = Location::NoLocation();
+ ScaleFactor no_scale_factor = TIMES_1;
GenerateReferenceLoadWithBakerReadBarrier(
- instruction, ref, obj, offset, no_index, temp, needs_null_check);
+ instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check);
}
void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
@@ -6217,10 +6228,14 @@ void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instr
DCHECK(kEmitCompilerReadBarrier);
DCHECK(kUseBakerReadBarrier);
+ static_assert(
+ sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
+ "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
// /* HeapReference<Object> */ ref =
// *(obj + data_offset + index * sizeof(HeapReference<Object>))
+ ScaleFactor scale_factor = TIMES_4;
GenerateReferenceLoadWithBakerReadBarrier(
- instruction, ref, obj, data_offset, index, temp, needs_null_check);
+ instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check);
}
void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
@@ -6228,6 +6243,7 @@ void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* i
Register obj,
uint32_t offset,
Location index,
+ ScaleFactor scale_factor,
Location temp,
bool needs_null_check) {
DCHECK(kEmitCompilerReadBarrier);
@@ -6282,17 +6298,22 @@ void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* i
// The actual reference load.
if (index.IsValid()) {
- static_assert(
- sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
- "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
- // /* HeapReference<Object> */ ref =
- // *(obj + offset + index * sizeof(HeapReference<Object>))
+ // Load types involving an "index": ArrayGet and
+ // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
+ // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
if (index.IsConstant()) {
size_t computed_offset =
- (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset;
+ (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
__ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
} else {
- __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
+ // Handle the special case of the
+ // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics, which use
+ // a register pair as index ("long offset"), of which only the low
+ // part contains data.
+ Register index_reg = index.IsRegisterPair()
+ ? index.AsRegisterPairLow<Register>()
+ : index.AsRegister<Register>();
+ __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor));
__ LoadFromOffset(kLoadWord, ref_reg, IP, offset);
}
} else {
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 4fce5af8e6..477c4f18c1 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -472,6 +472,16 @@ class CodeGeneratorARM : public CodeGenerator {
Location index,
Location temp,
bool needs_null_check);
+ // Factored implementation used by GenerateFieldLoadWithBakerReadBarrier
+ // and GenerateArrayLoadWithBakerReadBarrier.
+ void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
+ Location ref,
+ Register obj,
+ uint32_t offset,
+ Location index,
+ ScaleFactor scale_factor,
+ Location temp,
+ bool needs_null_check);
// Generate a read barrier for a heap reference within `instruction`
// using a slow path.
@@ -527,16 +537,6 @@ class CodeGeneratorARM : public CodeGenerator {
void GenerateExplicitNullCheck(HNullCheck* instruction);
private:
- // Factored implementation of GenerateFieldLoadWithBakerReadBarrier
- // and GenerateArrayLoadWithBakerReadBarrier.
- void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
- Location ref,
- Register obj,
- uint32_t offset,
- Location index,
- Location temp,
- bool needs_null_check);
-
Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 4692a4a876..07d5e50c6b 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -598,7 +598,9 @@ class ReadBarrierMarkSlowPathARM64 : public SlowPathCodeARM64 {
instruction_->IsLoadClass() ||
instruction_->IsLoadString() ||
instruction_->IsInstanceOf() ||
- instruction_->IsCheckCast())
+ instruction_->IsCheckCast() ||
+ ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
+ instruction_->GetLocations()->Intrinsified()))
<< "Unexpected instruction in read barrier marking slow path: "
<< instruction_->DebugName();
@@ -661,8 +663,12 @@ class ReadBarrierForHeapReferenceSlowPathARM64 : public SlowPathCodeARM64 {
Primitive::Type type = Primitive::kPrimNot;
DCHECK(locations->CanCall());
DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
- DCHECK(!instruction_->IsInvoke() ||
- (instruction_->IsInvokeStaticOrDirect() &&
+ DCHECK(instruction_->IsInstanceFieldGet() ||
+ instruction_->IsStaticFieldGet() ||
+ instruction_->IsArrayGet() ||
+ instruction_->IsInstanceOf() ||
+ instruction_->IsCheckCast() ||
+ ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
instruction_->GetLocations()->Intrinsified()))
<< "Unexpected instruction in read barrier for heap reference slow path: "
<< instruction_->DebugName();
@@ -680,7 +686,7 @@ class ReadBarrierForHeapReferenceSlowPathARM64 : public SlowPathCodeARM64 {
// introduce a copy of it, `index`.
Location index = index_;
if (index_.IsValid()) {
- // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
+ // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
if (instruction_->IsArrayGet()) {
// Compute the actual memory offset and store it in `index`.
Register index_reg = RegisterFrom(index_, Primitive::kPrimInt);
@@ -728,7 +734,11 @@ class ReadBarrierForHeapReferenceSlowPathARM64 : public SlowPathCodeARM64 {
"art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
__ Add(index_reg, index_reg, Operand(offset_));
} else {
- DCHECK(instruction_->IsInvoke());
+ // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
+ // intrinsics, `index_` is not shifted by a scale factor of 2
+ // (as in the case of ArrayGet), as it is actually an offset
+ // to an object field within an object.
+ DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
DCHECK(instruction_->GetLocations()->Intrinsified());
DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
(instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
@@ -5102,8 +5112,16 @@ void CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier(HInstruction* ins
// /* HeapReference<Object> */ ref = *(obj + offset)
Location no_index = Location::NoLocation();
- GenerateReferenceLoadWithBakerReadBarrier(
- instruction, ref, obj, offset, no_index, temp, needs_null_check, use_load_acquire);
+ size_t no_scale_factor = 0U;
+ GenerateReferenceLoadWithBakerReadBarrier(instruction,
+ ref,
+ obj,
+ offset,
+ no_index,
+ no_scale_factor,
+ temp,
+ needs_null_check,
+ use_load_acquire);
}
void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
@@ -5120,10 +5138,21 @@ void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* ins
// never use Load-Acquire instructions on ARM64.
const bool use_load_acquire = false;
+ static_assert(
+ sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
+ "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
// /* HeapReference<Object> */ ref =
// *(obj + data_offset + index * sizeof(HeapReference<Object>))
- GenerateReferenceLoadWithBakerReadBarrier(
- instruction, ref, obj, data_offset, index, temp, needs_null_check, use_load_acquire);
+ size_t scale_factor = Primitive::ComponentSizeShift(Primitive::kPrimNot);
+ GenerateReferenceLoadWithBakerReadBarrier(instruction,
+ ref,
+ obj,
+ data_offset,
+ index,
+ scale_factor,
+ temp,
+ needs_null_check,
+ use_load_acquire);
}
void CodeGeneratorARM64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
@@ -5131,15 +5160,16 @@ void CodeGeneratorARM64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction*
vixl::Register obj,
uint32_t offset,
Location index,
+ size_t scale_factor,
Register temp,
bool needs_null_check,
bool use_load_acquire) {
DCHECK(kEmitCompilerReadBarrier);
DCHECK(kUseBakerReadBarrier);
- // If `index` is a valid location, then we are emitting an array
- // load, so we shouldn't be using a Load Acquire instruction.
- // In other words: `index.IsValid()` => `!use_load_acquire`.
- DCHECK(!index.IsValid() || !use_load_acquire);
+ // If we are emitting an array load, we should not be using a
+ // Load Acquire instruction. In other words:
+ // `instruction->IsArrayGet()` => `!use_load_acquire`.
+ DCHECK(!instruction->IsArrayGet() || !use_load_acquire);
MacroAssembler* masm = GetVIXLAssembler();
UseScratchRegisterScope temps(masm);
@@ -5196,20 +5226,33 @@ void CodeGeneratorARM64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction*
// The actual reference load.
if (index.IsValid()) {
- static_assert(
- sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
- "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
- // /* HeapReference<Object> */ ref =
- // *(obj + offset + index * sizeof(HeapReference<Object>))
- const size_t shift_amount = Primitive::ComponentSizeShift(type);
- if (index.IsConstant()) {
- uint32_t computed_offset = offset + (Int64ConstantFrom(index) << shift_amount);
- Load(type, ref_reg, HeapOperand(obj, computed_offset));
+ // Load types involving an "index".
+ if (use_load_acquire) {
+ // UnsafeGetObjectVolatile intrinsic case.
+ // Register `index` is not an index in an object array, but an
+ // offset to an object reference field within object `obj`.
+ DCHECK(instruction->IsInvoke()) << instruction->DebugName();
+ DCHECK(instruction->GetLocations()->Intrinsified());
+ DCHECK(instruction->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile)
+ << instruction->AsInvoke()->GetIntrinsic();
+ DCHECK_EQ(offset, 0U);
+ DCHECK_EQ(scale_factor, 0U);
+ DCHECK_EQ(needs_null_check, 0U);
+ // /* HeapReference<Object> */ ref = *(obj + index)
+ MemOperand field = HeapOperand(obj, XRegisterFrom(index));
+ LoadAcquire(instruction, ref_reg, field, /* needs_null_check */ false);
} else {
- temp2 = temps.AcquireW();
- __ Add(temp2, obj, offset);
- Load(type, ref_reg, HeapOperand(temp2, XRegisterFrom(index), LSL, shift_amount));
- temps.Release(temp2);
+ // ArrayGet and UnsafeGetObject intrinsics cases.
+ // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
+ if (index.IsConstant()) {
+ uint32_t computed_offset = offset + (Int64ConstantFrom(index) << scale_factor);
+ Load(type, ref_reg, HeapOperand(obj, computed_offset));
+ } else {
+ temp2 = temps.AcquireW();
+ __ Add(temp2, obj, offset);
+ Load(type, ref_reg, HeapOperand(temp2, XRegisterFrom(index), LSL, scale_factor));
+ temps.Release(temp2);
+ }
}
} else {
// /* HeapReference<Object> */ ref = *(obj + offset)
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index e6fd336be7..d4bf695602 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -531,6 +531,17 @@ class CodeGeneratorARM64 : public CodeGenerator {
Location index,
vixl::Register temp,
bool needs_null_check);
+ // Factored implementation used by GenerateFieldLoadWithBakerReadBarrier
+ // and GenerateArrayLoadWithBakerReadBarrier.
+ void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
+ Location ref,
+ vixl::Register obj,
+ uint32_t offset,
+ Location index,
+ size_t scale_factor,
+ vixl::Register temp,
+ bool needs_null_check,
+ bool use_load_acquire);
// Generate a read barrier for a heap reference within `instruction`
// using a slow path.
@@ -586,17 +597,6 @@ class CodeGeneratorARM64 : public CodeGenerator {
void GenerateExplicitNullCheck(HNullCheck* instruction);
private:
- // Factored implementation of GenerateFieldLoadWithBakerReadBarrier
- // and GenerateArrayLoadWithBakerReadBarrier.
- void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
- Location ref,
- vixl::Register obj,
- uint32_t offset,
- Location index,
- vixl::Register temp,
- bool needs_null_check,
- bool use_load_acquire);
-
using Uint64ToLiteralMap = ArenaSafeMap<uint64_t, vixl::Literal<uint64_t>*>;
using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, vixl::Literal<uint32_t>*>;
using MethodToLiteralMap = ArenaSafeMap<MethodReference,
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 52868f4b2e..af10bad6cc 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -448,7 +448,9 @@ class ReadBarrierMarkSlowPathX86 : public SlowPathCode {
instruction_->IsLoadClass() ||
instruction_->IsLoadString() ||
instruction_->IsInstanceOf() ||
- instruction_->IsCheckCast())
+ instruction_->IsCheckCast() ||
+ ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
+ instruction_->GetLocations()->Intrinsified()))
<< "Unexpected instruction in read barrier marking slow path: "
<< instruction_->DebugName();
@@ -511,8 +513,12 @@ class ReadBarrierForHeapReferenceSlowPathX86 : public SlowPathCode {
Register reg_out = out_.AsRegister<Register>();
DCHECK(locations->CanCall());
DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
- DCHECK(!instruction_->IsInvoke() ||
- (instruction_->IsInvokeStaticOrDirect() &&
+ DCHECK(instruction_->IsInstanceFieldGet() ||
+ instruction_->IsStaticFieldGet() ||
+ instruction_->IsArrayGet() ||
+ instruction_->IsInstanceOf() ||
+ instruction_->IsCheckCast() ||
+ ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
instruction_->GetLocations()->Intrinsified()))
<< "Unexpected instruction in read barrier for heap reference slow path: "
<< instruction_->DebugName();
@@ -525,7 +531,7 @@ class ReadBarrierForHeapReferenceSlowPathX86 : public SlowPathCode {
// introduce a copy of it, `index`.
Location index = index_;
if (index_.IsValid()) {
- // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
+ // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
if (instruction_->IsArrayGet()) {
// Compute the actual memory offset and store it in `index`.
Register index_reg = index_.AsRegister<Register>();
@@ -573,7 +579,11 @@ class ReadBarrierForHeapReferenceSlowPathX86 : public SlowPathCode {
"art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
__ AddImmediate(index_reg, Immediate(offset_));
} else {
- DCHECK(instruction_->IsInvoke());
+ // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
+ // intrinsics, `index_` is not shifted by a scale factor of 2
+ // (as in the case of ArrayGet), as it is actually an offset
+ // to an object field within an object.
+ DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
DCHECK(instruction_->GetLocations()->Intrinsified());
DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
(instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
@@ -6977,6 +6987,9 @@ void CodeGeneratorX86::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instr
DCHECK(kEmitCompilerReadBarrier);
DCHECK(kUseBakerReadBarrier);
+ static_assert(
+ sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
+ "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
// /* HeapReference<Object> */ ref =
// *(obj + data_offset + index * sizeof(HeapReference<Object>))
Address src = index.IsConstant() ?
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index fb402bef00..2a9fb80995 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -491,6 +491,14 @@ class CodeGeneratorX86 : public CodeGenerator {
Location index,
Location temp,
bool needs_null_check);
+ // Factored implementation used by GenerateFieldLoadWithBakerReadBarrier
+ // and GenerateArrayLoadWithBakerReadBarrier.
+ void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
+ Location ref,
+ Register obj,
+ const Address& src,
+ Location temp,
+ bool needs_null_check);
// Generate a read barrier for a heap reference within `instruction`
// using a slow path.
@@ -561,15 +569,6 @@ class CodeGeneratorX86 : public CodeGenerator {
static constexpr int32_t kDummy32BitOffset = 256;
private:
- // Factored implementation of GenerateFieldLoadWithBakerReadBarrier
- // and GenerateArrayLoadWithBakerReadBarrier.
- void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
- Location ref,
- Register obj,
- const Address& src,
- Location temp,
- bool needs_null_check);
-
Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
struct PcRelativeDexCacheAccessInfo {
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 9a3e8d266b..2b21454101 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -469,7 +469,9 @@ class ReadBarrierMarkSlowPathX86_64 : public SlowPathCode {
instruction_->IsLoadClass() ||
instruction_->IsLoadString() ||
instruction_->IsInstanceOf() ||
- instruction_->IsCheckCast())
+ instruction_->IsCheckCast() ||
+ ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
+ instruction_->GetLocations()->Intrinsified()))
<< "Unexpected instruction in read barrier marking slow path: "
<< instruction_->DebugName();
@@ -532,8 +534,12 @@ class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode {
CpuRegister reg_out = out_.AsRegister<CpuRegister>();
DCHECK(locations->CanCall());
DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out.AsRegister())) << out_;
- DCHECK(!instruction_->IsInvoke() ||
- (instruction_->IsInvokeStaticOrDirect() &&
+ DCHECK(instruction_->IsInstanceFieldGet() ||
+ instruction_->IsStaticFieldGet() ||
+ instruction_->IsArrayGet() ||
+ instruction_->IsInstanceOf() ||
+ instruction_->IsCheckCast() ||
+ ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) &&
instruction_->GetLocations()->Intrinsified()))
<< "Unexpected instruction in read barrier for heap reference slow path: "
<< instruction_->DebugName();
@@ -546,7 +552,7 @@ class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode {
// introduce a copy of it, `index`.
Location index = index_;
if (index_.IsValid()) {
- // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject.
+ // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
if (instruction_->IsArrayGet()) {
// Compute real offset and store it in index_.
Register index_reg = index_.AsRegister<CpuRegister>().AsRegister();
@@ -594,7 +600,11 @@ class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode {
"art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
__ AddImmediate(CpuRegister(index_reg), Immediate(offset_));
} else {
- DCHECK(instruction_->IsInvoke());
+ // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
+ // intrinsics, `index_` is not shifted by a scale factor of 2
+ // (as in the case of ArrayGet), as it is actually an offset
+ // to an object field within an object.
+ DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
DCHECK(instruction_->GetLocations()->Intrinsified());
DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
(instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
@@ -6430,6 +6440,9 @@ void CodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* in
DCHECK(kEmitCompilerReadBarrier);
DCHECK(kUseBakerReadBarrier);
+ static_assert(
+ sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
+ "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
// /* HeapReference<Object> */ ref =
// *(obj + data_offset + index * sizeof(HeapReference<Object>))
Address src = index.IsConstant() ?
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index cf4cc4c8d2..d7cfd37c33 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -433,6 +433,14 @@ class CodeGeneratorX86_64 : public CodeGenerator {
Location index,
Location temp,
bool needs_null_check);
+ // Factored implementation used by GenerateFieldLoadWithBakerReadBarrier
+ // and GenerateArrayLoadWithBakerReadBarrier.
+ void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
+ Location ref,
+ CpuRegister obj,
+ const Address& src,
+ Location temp,
+ bool needs_null_check);
// Generate a read barrier for a heap reference within `instruction`
// using a slow path.
@@ -535,15 +543,6 @@ class CodeGeneratorX86_64 : public CodeGenerator {
static constexpr int32_t kDummy32BitOffset = 256;
private:
- // Factored implementation of GenerateFieldLoadWithBakerReadBarrier
- // and GenerateArrayLoadWithBakerReadBarrier.
- void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
- Location ref,
- CpuRegister obj,
- const Address& src,
- Location temp,
- bool needs_null_check);
-
struct PcRelativeDexCacheAccessInfo {
PcRelativeDexCacheAccessInfo(const DexFile& dex_file, uint32_t element_off)
: target_dex_file(dex_file), element_offset(element_off), label() { }
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 93950d58b5..f43f8edf06 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -47,19 +47,6 @@ bool IntrinsicLocationsBuilderARM::TryDispatch(HInvoke* invoke) {
if (res == nullptr) {
return false;
}
- if (kEmitCompilerReadBarrier && res->CanCall()) {
- // Generating an intrinsic for this HInvoke may produce an
- // IntrinsicSlowPathARM slow path. Currently this approach
- // does not work when using read barriers, as the emitted
- // calling sequence will make use of another slow path
- // (ReadBarrierForRootSlowPathARM for HInvokeStaticOrDirect,
- // ReadBarrierSlowPathARM for HInvokeVirtual). So we bail
- // out in this case.
- //
- // TODO: Find a way to have intrinsics work with read barriers.
- invoke->SetLocations(nullptr);
- return false;
- }
return res->Intrinsified();
}
@@ -524,8 +511,8 @@ static void GenUnsafeGet(HInvoke* invoke,
if (kEmitCompilerReadBarrier) {
if (kUseBakerReadBarrier) {
Location temp = locations->GetTemp(0);
- codegen->GenerateArrayLoadWithBakerReadBarrier(
- invoke, trg_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false);
+ codegen->GenerateReferenceLoadWithBakerReadBarrier(
+ invoke, trg_loc, base, 0U, offset_loc, TIMES_1, temp, /* needs_null_check */ false);
if (is_volatile) {
__ dmb(ISH);
}
@@ -581,10 +568,11 @@ static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
locations->SetInAt(1, Location::RequiresRegister());
locations->SetInAt(2, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ locations->SetOut(Location::RequiresRegister(),
+ can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap);
if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
// We need a temporary register for the read barrier marking slow
- // path in InstructionCodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
+ // path in InstructionCodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier.
locations->AddTemp(Location::RequiresRegister());
}
}
@@ -919,9 +907,10 @@ void IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) {
// The UnsafeCASObject intrinsic is missing a read barrier, and
// therefore sometimes does not work as expected (b/25883050).
// Turn it off temporarily as a quick fix, until the read barrier is
- // implemented (see TODO in GenCAS below).
+ // implemented (see TODO in GenCAS).
//
- // TODO(rpl): Fix this issue and re-enable this intrinsic with read barriers.
+ // TODO(rpl): Implement read barrier support in GenCAS and re-enable
+ // this intrinsic.
if (kEmitCompilerReadBarrier) {
return;
}
@@ -932,6 +921,15 @@ void IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) {
GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_);
}
void IntrinsicCodeGeneratorARM::VisitUnsafeCASObject(HInvoke* invoke) {
+ // The UnsafeCASObject intrinsic is missing a read barrier, and
+ // therefore sometimes does not work as expected (b/25883050).
+ // Turn it off temporarily as a quick fix, until the read barrier is
+ // implemented (see TODO in GenCAS).
+ //
+ // TODO(rpl): Implement read barrier support in GenCAS and re-enable
+ // this intrinsic.
+ DCHECK(!kEmitCompilerReadBarrier);
+
GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_);
}
@@ -1335,6 +1333,12 @@ void IntrinsicCodeGeneratorARM::VisitStringNewStringFromString(HInvoke* invoke)
}
void IntrinsicLocationsBuilderARM::VisitSystemArrayCopy(HInvoke* invoke) {
+ // TODO(rpl): Implement read barriers in the SystemArrayCopy
+ // intrinsic and re-enable it (b/29516905).
+ if (kEmitCompilerReadBarrier) {
+ return;
+ }
+
CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke);
LocationSummary* locations = invoke->GetLocations();
if (locations == nullptr) {
@@ -1419,11 +1423,11 @@ static void CheckPosition(ArmAssembler* assembler,
}
}
-// TODO: Implement read barriers in the SystemArrayCopy intrinsic.
-// Note that this code path is not used (yet) because we do not
-// intrinsify methods that can go into the IntrinsicSlowPathARM
-// slow path.
void IntrinsicCodeGeneratorARM::VisitSystemArrayCopy(HInvoke* invoke) {
+ // TODO(rpl): Implement read barriers in the SystemArrayCopy
+ // intrinsic and re-enable it (b/29516905).
+ DCHECK(!kEmitCompilerReadBarrier);
+
ArmAssembler* assembler = GetAssembler();
LocationSummary* locations = invoke->GetLocations();
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 4da0843a76..1685cf9c3c 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -149,19 +149,6 @@ bool IntrinsicLocationsBuilderARM64::TryDispatch(HInvoke* invoke) {
if (res == nullptr) {
return false;
}
- if (kEmitCompilerReadBarrier && res->CanCall()) {
- // Generating an intrinsic for this HInvoke may produce an
- // IntrinsicSlowPathARM64 slow path. Currently this approach
- // does not work when using read barriers, as the emitted
- // calling sequence will make use of another slow path
- // (ReadBarrierForRootSlowPathARM64 for HInvokeStaticOrDirect,
- // ReadBarrierSlowPathARM64 for HInvokeVirtual). So we bail
- // out in this case.
- //
- // TODO: Find a way to have intrinsics work with read barriers.
- invoke->SetLocations(nullptr);
- return false;
- }
return res->Intrinsified();
}
@@ -791,8 +778,15 @@ static void GenUnsafeGet(HInvoke* invoke,
// UnsafeGetObject/UnsafeGetObjectVolatile with Baker's read barrier case.
UseScratchRegisterScope temps(masm);
Register temp = temps.AcquireW();
- codegen->GenerateArrayLoadWithBakerReadBarrier(
- invoke, trg_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false);
+ codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
+ trg_loc,
+ base,
+ /* offset */ 0U,
+ /* index */ offset_loc,
+ /* scale_factor */ 0U,
+ temp,
+ /* needs_null_check */ false,
+ is_volatile);
} else {
// Other cases.
MemOperand mem_op(base.X(), offset);
@@ -821,7 +815,8 @@ static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke
locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
locations->SetInAt(1, Location::RequiresRegister());
locations->SetInAt(2, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ locations->SetOut(Location::RequiresRegister(),
+ can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap);
}
void IntrinsicLocationsBuilderARM64::VisitUnsafeGet(HInvoke* invoke) {
@@ -1102,9 +1097,10 @@ void IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject(HInvoke* invoke) {
// The UnsafeCASObject intrinsic is missing a read barrier, and
// therefore sometimes does not work as expected (b/25883050).
// Turn it off temporarily as a quick fix, until the read barrier is
- // implemented (see TODO in GenCAS below).
+ // implemented (see TODO in GenCAS).
//
- // TODO(rpl): Fix this issue and re-enable this intrinsic with read barriers.
+ // TODO(rpl): Implement read barrier support in GenCAS and re-enable
+ // this intrinsic.
if (kEmitCompilerReadBarrier) {
return;
}
@@ -1119,6 +1115,15 @@ void IntrinsicCodeGeneratorARM64::VisitUnsafeCASLong(HInvoke* invoke) {
GenCas(invoke->GetLocations(), Primitive::kPrimLong, codegen_);
}
void IntrinsicCodeGeneratorARM64::VisitUnsafeCASObject(HInvoke* invoke) {
+ // The UnsafeCASObject intrinsic is missing a read barrier, and
+ // therefore sometimes does not work as expected (b/25883050).
+ // Turn it off temporarily as a quick fix, until the read barrier is
+ // implemented (see TODO in GenCAS).
+ //
+ // TODO(rpl): Implement read barrier support in GenCAS and re-enable
+ // this intrinsic.
+ DCHECK(!kEmitCompilerReadBarrier);
+
GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_);
}
@@ -2012,6 +2017,12 @@ static constexpr int32_t kSystemArrayCopyThreshold = 128;
// We want to use two temporary registers in order to reduce the register pressure in arm64.
// So we don't use the CodeGenerator::CreateSystemArrayCopyLocationSummary.
void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopy(HInvoke* invoke) {
+ // TODO(rpl): Implement read barriers in the SystemArrayCopy
+ // intrinsic and re-enable it (b/29516905).
+ if (kEmitCompilerReadBarrier) {
+ return;
+ }
+
// Check to see if we have known failures that will cause us to have to bail out
// to the runtime, and just generate the runtime call directly.
HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
@@ -2064,6 +2075,10 @@ void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopy(HInvoke* invoke) {
}
void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) {
+ // TODO(rpl): Implement read barriers in the SystemArrayCopy
+ // intrinsic and re-enable it (b/29516905).
+ DCHECK(!kEmitCompilerReadBarrier);
+
vixl::MacroAssembler* masm = GetVIXLAssembler();
LocationSummary* locations = invoke->GetLocations();
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 4988398c92..031cd1313c 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -60,19 +60,6 @@ bool IntrinsicLocationsBuilderX86::TryDispatch(HInvoke* invoke) {
if (res == nullptr) {
return false;
}
- if (kEmitCompilerReadBarrier && res->CanCall()) {
- // Generating an intrinsic for this HInvoke may produce an
- // IntrinsicSlowPathX86 slow path. Currently this approach
- // does not work when using read barriers, as the emitted
- // calling sequence will make use of another slow path
- // (ReadBarrierForRootSlowPathX86 for HInvokeStaticOrDirect,
- // ReadBarrierSlowPathX86 for HInvokeVirtual). So we bail
- // out in this case.
- //
- // TODO: Find a way to have intrinsics work with read barriers.
- invoke->SetLocations(nullptr);
- return false;
- }
return res->Intrinsified();
}
@@ -1822,8 +1809,9 @@ static void GenUnsafeGet(HInvoke* invoke,
if (kEmitCompilerReadBarrier) {
if (kUseBakerReadBarrier) {
Location temp = locations->GetTemp(0);
- codegen->GenerateArrayLoadWithBakerReadBarrier(
- invoke, output_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false);
+ Address src(base, offset, ScaleFactor::TIMES_1, 0);
+ codegen->GenerateReferenceLoadWithBakerReadBarrier(
+ invoke, output_loc, base, src, temp, /* needs_null_check */ false);
} else {
__ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
codegen->GenerateReadBarrierSlow(
@@ -1878,16 +1866,17 @@ static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
if (is_volatile) {
// Need to use XMM to read volatile.
locations->AddTemp(Location::RequiresFpuRegister());
- locations->SetOut(Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
} else {
locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
}
} else {
- locations->SetOut(Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(),
+ can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap);
}
if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
// We need a temporary register for the read barrier marking slow
- // path in InstructionCodeGeneratorX86::GenerateArrayLoadWithBakerReadBarrier.
+ // path in InstructionCodeGeneratorX86::GenerateReferenceLoadWithBakerReadBarrier.
locations->AddTemp(Location::RequiresRegister());
}
}
@@ -2109,9 +2098,9 @@ void IntrinsicLocationsBuilderX86::VisitUnsafeCASObject(HInvoke* invoke) {
// The UnsafeCASObject intrinsic is missing a read barrier, and
// therefore sometimes does not work as expected (b/25883050).
// Turn it off temporarily as a quick fix, until the read barrier is
- // implemented.
+ // implemented (see TODO in GenCAS).
//
- // TODO(rpl): Implement a read barrier in GenCAS below and re-enable
+ // TODO(rpl): Implement read barrier support in GenCAS and re-enable
// this intrinsic.
if (kEmitCompilerReadBarrier) {
return;
@@ -2236,6 +2225,15 @@ void IntrinsicCodeGeneratorX86::VisitUnsafeCASLong(HInvoke* invoke) {
}
void IntrinsicCodeGeneratorX86::VisitUnsafeCASObject(HInvoke* invoke) {
+ // The UnsafeCASObject intrinsic is missing a read barrier, and
+ // therefore sometimes does not work as expected (b/25883050).
+ // Turn it off temporarily as a quick fix, until the read barrier is
+ // implemented (see TODO in GenCAS).
+ //
+ // TODO(rpl): Implement read barrier support in GenCAS and re-enable
+ // this intrinsic.
+ DCHECK(!kEmitCompilerReadBarrier);
+
GenCAS(Primitive::kPrimNot, invoke, codegen_);
}
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 405b4c02ec..c5b44d4f5c 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -54,19 +54,6 @@ bool IntrinsicLocationsBuilderX86_64::TryDispatch(HInvoke* invoke) {
if (res == nullptr) {
return false;
}
- if (kEmitCompilerReadBarrier && res->CanCall()) {
- // Generating an intrinsic for this HInvoke may produce an
- // IntrinsicSlowPathX86_64 slow path. Currently this approach
- // does not work when using read barriers, as the emitted
- // calling sequence will make use of another slow path
- // (ReadBarrierForRootSlowPathX86_64 for HInvokeStaticOrDirect,
- // ReadBarrierSlowPathX86_64 for HInvokeVirtual). So we bail
- // out in this case.
- //
- // TODO: Find a way to have intrinsics work with read barriers.
- invoke->SetLocations(nullptr);
- return false;
- }
return res->Intrinsified();
}
@@ -1079,14 +1066,20 @@ void IntrinsicCodeGeneratorX86_64::VisitSystemArrayCopyChar(HInvoke* invoke) {
void IntrinsicLocationsBuilderX86_64::VisitSystemArrayCopy(HInvoke* invoke) {
+ // TODO(rpl): Implement read barriers in the SystemArrayCopy
+ // intrinsic and re-enable it (b/29516905).
+ if (kEmitCompilerReadBarrier) {
+ return;
+ }
+
CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke);
}
-// TODO: Implement read barriers in the SystemArrayCopy intrinsic.
-// Note that this code path is not used (yet) because we do not
-// intrinsify methods that can go into the IntrinsicSlowPathX86_64
-// slow path.
void IntrinsicCodeGeneratorX86_64::VisitSystemArrayCopy(HInvoke* invoke) {
+ // TODO(rpl): Implement read barriers in the SystemArrayCopy
+ // intrinsic and re-enable it (b/29516905).
+ DCHECK(!kEmitCompilerReadBarrier);
+
X86_64Assembler* assembler = GetAssembler();
LocationSummary* locations = invoke->GetLocations();
@@ -1910,8 +1903,9 @@ static void GenUnsafeGet(HInvoke* invoke,
if (kEmitCompilerReadBarrier) {
if (kUseBakerReadBarrier) {
Location temp = locations->GetTemp(0);
- codegen->GenerateArrayLoadWithBakerReadBarrier(
- invoke, output_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false);
+ Address src(base, offset, ScaleFactor::TIMES_1, 0);
+ codegen->GenerateReferenceLoadWithBakerReadBarrier(
+ invoke, output_loc, base, src, temp, /* needs_null_check */ false);
} else {
__ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
codegen->GenerateReadBarrierSlow(
@@ -1948,10 +1942,11 @@ static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
locations->SetInAt(1, Location::RequiresRegister());
locations->SetInAt(2, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(),
+ can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap);
if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
// We need a temporary register for the read barrier marking slow
- // path in InstructionCodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier.
+ // path in InstructionCodeGeneratorX86_64::GenerateReferenceLoadWithBakerReadBarrier.
locations->AddTemp(Location::RequiresRegister());
}
}
@@ -2135,9 +2130,9 @@ void IntrinsicLocationsBuilderX86_64::VisitUnsafeCASObject(HInvoke* invoke) {
// The UnsafeCASObject intrinsic is missing a read barrier, and
// therefore sometimes does not work as expected (b/25883050).
// Turn it off temporarily as a quick fix, until the read barrier is
- // implemented.
+ // implemented (see TODO in GenCAS).
//
- // TODO(rpl): Implement a read barrier in GenCAS below and re-enable
+ // TODO(rpl): Implement read barrier support in GenCAS and re-enable
// this intrinsic.
if (kEmitCompilerReadBarrier) {
return;
@@ -2253,6 +2248,15 @@ void IntrinsicCodeGeneratorX86_64::VisitUnsafeCASLong(HInvoke* invoke) {
}
void IntrinsicCodeGeneratorX86_64::VisitUnsafeCASObject(HInvoke* invoke) {
+ // The UnsafeCASObject intrinsic is missing a read barrier, and
+ // therefore sometimes does not work as expected (b/25883050).
+ // Turn it off temporarily as a quick fix, until the read barrier is
+ // implemented (see TODO in GenCAS).
+ //
+ // TODO(rpl): Implement read barrier support in GenCAS and re-enable
+ // this intrinsic.
+ DCHECK(!kEmitCompilerReadBarrier);
+
GenCAS(Primitive::kPrimNot, invoke, codegen_);
}
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index 63bbc2cd0a..3f27c911be 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -38,7 +38,13 @@ std::ostream& operator<<(std::ostream& os, const Location& location);
class Location : public ValueObject {
public:
enum OutputOverlap {
+ // The liveness of the output overlaps the liveness of one or
+ // several input(s); the register allocator cannot reuse an
+ // input's location for the output's location.
kOutputOverlap,
+ // The liveness of the output does not overlap the liveness of any
+ // input; the register allocator is allowed to reuse an input's
+ // location for the output's location.
kNoOutputOverlap
};
@@ -494,6 +500,10 @@ class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> {
return inputs_.size();
}
+ // Set the output location. Argument `overlaps` tells whether the
+ // output overlaps any of the inputs (if so, it cannot share the
+ // same register as one of the inputs); it is set to
+ // `Location::kOutputOverlap` by default for safety.
void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) {
DCHECK(output_.IsInvalid());
output_overlaps_ = overlaps;
diff --git a/compiler/utils/string_reference.h b/compiler/utils/string_reference.h
index 9e1058ea4d..0ab45c86e3 100644
--- a/compiler/utils/string_reference.h
+++ b/compiler/utils/string_reference.h
@@ -20,12 +20,11 @@
#include <stdint.h>
#include "base/logging.h"
+#include "dex_file-inl.h"
#include "utf-inl.h"
namespace art {
-class DexFile;
-
// A string is located by its DexFile and the string_ids_ table index into that DexFile.
struct StringReference {
StringReference(const DexFile* file, uint32_t index) : dex_file(file), string_index(index) { }
@@ -48,13 +47,13 @@ struct StringReferenceValueComparator {
sr1.string_index < sr2.string_index,
CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(
sr1.dex_file->GetStringData(sr1.dex_file->GetStringId(sr1.string_index)),
- sr1.dex_file->GetStringData(sr2.dex_file->GetStringId(sr2.string_index))) < 0);
+ sr2.dex_file->GetStringData(sr2.dex_file->GetStringId(sr2.string_index))) < 0);
return sr1.string_index < sr2.string_index;
} else {
// Cannot compare indexes, so do the string comparison.
return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(
sr1.dex_file->GetStringData(sr1.dex_file->GetStringId(sr1.string_index)),
- sr1.dex_file->GetStringData(sr2.dex_file->GetStringId(sr2.string_index))) < 0;
+ sr2.dex_file->GetStringData(sr2.dex_file->GetStringId(sr2.string_index))) < 0;
}
}
};
diff --git a/compiler/utils/string_reference_test.cc b/compiler/utils/string_reference_test.cc
new file mode 100644
index 0000000000..df5080e93e
--- /dev/null
+++ b/compiler/utils/string_reference_test.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 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 "utils/string_reference.h"
+
+#include <memory>
+
+#include "gtest/gtest.h"
+#include "utils/test_dex_file_builder.h"
+
+namespace art {
+
+TEST(StringReference, ValueComparator) {
+ // This is a regression test for the StringReferenceValueComparator using the wrong
+ // dex file to get the string data from a StringId. We construct two dex files with
+ // just a single string with the same length but different value. This creates dex
+ // files that have the same layout, so the byte offset read from the StringId in one
+ // dex file, when used in the other dex file still points to valid string data, except
+ // that it's the wrong string. Without the fix the strings would then compare equal.
+ TestDexFileBuilder builder1;
+ builder1.AddString("String1");
+ std::unique_ptr<const DexFile> dex_file1 = builder1.Build("dummy location 1");
+ ASSERT_EQ(1u, dex_file1->NumStringIds());
+ ASSERT_STREQ("String1", dex_file1->GetStringData(dex_file1->GetStringId(0)));
+ StringReference sr1(dex_file1.get(), 0);
+
+ TestDexFileBuilder builder2;
+ builder2.AddString("String2");
+ std::unique_ptr<const DexFile> dex_file2 = builder2.Build("dummy location 2");
+ ASSERT_EQ(1u, dex_file2->NumStringIds());
+ ASSERT_STREQ("String2", dex_file2->GetStringData(dex_file2->GetStringId(0)));
+ StringReference sr2(dex_file2.get(), 0);
+
+ StringReferenceValueComparator cmp;
+ EXPECT_TRUE(cmp(sr1, sr2)); // "String1" < "String2" is true.
+ EXPECT_FALSE(cmp(sr2, sr1)); // "String2" < "String1" is false.
+}
+
+TEST(StringReference, ValueComparator2) {
+ const char* const kDexFile1Strings[] = {
+ "",
+ "abc",
+ "abcxyz",
+ };
+ const char* const kDexFile2Strings[] = {
+ "a",
+ "abc",
+ "abcdef",
+ "def",
+ };
+ const bool expectedCmp12[arraysize(kDexFile1Strings)][arraysize(kDexFile2Strings)] = {
+ { true, true, true, true },
+ { false, false, true, true },
+ { false, false, false, true },
+ };
+ const bool expectedCmp21[arraysize(kDexFile2Strings)][arraysize(kDexFile1Strings)] = {
+ { false, true, true },
+ { false, false, true },
+ { false, false, true },
+ { false, false, false },
+ };
+
+ TestDexFileBuilder builder1;
+ for (const char* s : kDexFile1Strings) {
+ builder1.AddString(s);
+ }
+ std::unique_ptr<const DexFile> dex_file1 = builder1.Build("dummy location 1");
+ ASSERT_EQ(arraysize(kDexFile1Strings), dex_file1->NumStringIds());
+ for (size_t index = 0; index != arraysize(kDexFile1Strings); ++index) {
+ ASSERT_STREQ(kDexFile1Strings[index], dex_file1->GetStringData(dex_file1->GetStringId(index)));
+ }
+
+ TestDexFileBuilder builder2;
+ for (const char* s : kDexFile2Strings) {
+ builder2.AddString(s);
+ }
+ std::unique_ptr<const DexFile> dex_file2 = builder2.Build("dummy location 1");
+ ASSERT_EQ(arraysize(kDexFile2Strings), dex_file2->NumStringIds());
+ for (size_t index = 0; index != arraysize(kDexFile2Strings); ++index) {
+ ASSERT_STREQ(kDexFile2Strings[index], dex_file2->GetStringData(dex_file2->GetStringId(index)));
+ }
+
+ StringReferenceValueComparator cmp;
+ for (size_t index1 = 0; index1 != arraysize(kDexFile1Strings); ++index1) {
+ for (size_t index2 = 0; index2 != arraysize(kDexFile2Strings); ++index2) {
+ StringReference sr1(dex_file1.get(), index1);
+ StringReference sr2(dex_file2.get(), index2);
+ EXPECT_EQ(expectedCmp12[index1][index2], cmp(sr1, sr2)) << index1 << " " << index2;
+ EXPECT_EQ(expectedCmp21[index2][index1], cmp(sr2, sr1)) << index1 << " " << index2;
+ }
+ }
+}
+
+} // namespace art