Minor object store optimizations.
- Avoid emitting write barrier when the value is null.
- Do not do a typecheck on an arraystore when storing something that
was loaded from the same array.
Change-Id: I902492928692e4553b5af0fc99cce3c2186c442a
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 100f380..b8518f1 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -42,6 +42,9 @@
static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { };
static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
+// Marker for places that can be updated once we don't follow the quick ABI.
+static constexpr bool kFollowsQuickABI = true;
+
class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> {
public:
InvokeRuntimeCallingConvention()
@@ -427,6 +430,7 @@
blocked_core_registers_[ESP] = true;
// TODO: We currently don't use Quick's callee saved registers.
+ DCHECK(kFollowsQuickABI);
blocked_core_registers_[EBP] = true;
blocked_core_registers_[ESI] = true;
blocked_core_registers_[EDI] = true;
@@ -1931,7 +1935,9 @@
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
Primitive::Type field_type = instruction->GetFieldType();
- bool is_object_type = field_type == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
+
bool is_byte_type = (field_type == Primitive::kPrimBoolean)
|| (field_type == Primitive::kPrimByte);
// The register allocator does not support multiple
@@ -1943,7 +1949,7 @@
locations->SetInAt(1, Location::RequiresRegister());
}
// Temporary registers for the write barrier.
- if (is_object_type) {
+ if (needs_write_barrier) {
locations->AddTemp(Location::RequiresRegister());
// Ensure the card is in a byte register.
locations->AddTemp(Location::RegisterLocation(ECX));
@@ -1976,7 +1982,7 @@
Register value = locations->InAt(1).As<Register>();
__ movl(Address(obj, offset), value);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Register temp = locations->GetTemp(0).As<Register>();
Register card = locations->GetTemp(1).As<Register>();
codegen_->MarkGCCard(temp, card, obj, value);
@@ -2222,11 +2228,20 @@
void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Primitive::Type value_type = instruction->GetComponentType();
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+
+ DCHECK(kFollowsQuickABI);
+ bool not_enough_registers = needs_write_barrier
+ && !instruction->GetValue()->IsConstant()
+ && !instruction->GetIndex()->IsConstant();
+ bool needs_runtime_call = instruction->NeedsTypeCheck() || not_enough_registers;
+
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
instruction,
- value_type == Primitive::kPrimNot ? LocationSummary::kCall : LocationSummary::kNoCall);
+ needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
- if (value_type == Primitive::kPrimNot) {
+ if (needs_runtime_call) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
@@ -2245,6 +2260,12 @@
} else {
locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
}
+ // Temporary registers for the write barrier.
+ if (needs_write_barrier) {
+ locations->AddTemp(Location::RequiresRegister());
+ // Ensure the card is in a byte register.
+ locations->AddTemp(Location::RegisterLocation(ECX));
+ }
}
}
@@ -2254,6 +2275,9 @@
Location index = locations->InAt(1);
Location value = locations->InAt(2);
Primitive::Type value_type = instruction->GetComponentType();
+ bool needs_runtime_call = locations->WillCall();
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
switch (value_type) {
case Primitive::kPrimBoolean:
@@ -2302,34 +2326,45 @@
break;
}
- case Primitive::kPrimInt: {
- uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
- if (index.IsConstant()) {
- size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- if (value.IsRegister()) {
- __ movl(Address(obj, offset), value.As<Register>());
+ case Primitive::kPrimInt:
+ case Primitive::kPrimNot: {
+ if (!needs_runtime_call) {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ if (value.IsRegister()) {
+ __ movl(Address(obj, offset), value.As<Register>());
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ __ movl(Address(obj, offset),
+ Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ }
} else {
- __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ DCHECK(index.IsRegister()) << index;
+ if (value.IsRegister()) {
+ __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
+ value.As<Register>());
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
+ Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ }
+ }
+
+ if (needs_write_barrier) {
+ Register temp = locations->GetTemp(0).As<Register>();
+ Register card = locations->GetTemp(1).As<Register>();
+ codegen_->MarkGCCard(temp, card, obj, value.As<Register>());
}
} else {
- if (value.IsRegister()) {
- __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
- value.As<Register>());
- } else {
- __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
- Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
- }
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ DCHECK(!codegen_->IsLeafMethod());
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
}
break;
}
- case Primitive::kPrimNot: {
- DCHECK(!codegen_->IsLeafMethod());
- __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
- codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
- break;
- }
-
case Primitive::kPrimLong: {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
if (index.IsConstant()) {
@@ -2694,7 +2729,8 @@
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
Primitive::Type field_type = instruction->GetFieldType();
- bool is_object_type = field_type == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
bool is_byte_type = (field_type == Primitive::kPrimBoolean)
|| (field_type == Primitive::kPrimByte);
// The register allocator does not support multiple
@@ -2706,7 +2742,7 @@
locations->SetInAt(1, Location::RequiresRegister());
}
// Temporary registers for the write barrier.
- if (is_object_type) {
+ if (needs_write_barrier) {
locations->AddTemp(Location::RequiresRegister());
// Ensure the card is in a byte register.
locations->AddTemp(Location::RegisterLocation(ECX));
@@ -2739,7 +2775,7 @@
Register value = locations->InAt(1).As<Register>();
__ movl(Address(cls, offset), value);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Register temp = locations->GetTemp(0).As<Register>();
Register card = locations->GetTemp(1).As<Register>();
codegen_->MarkGCCard(temp, card, cls, value);