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.h b/compiler/optimizing/code_generator.h
index ac4fc67..a046ade 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -168,6 +168,15 @@
void EmitParallelMoves(Location from1, Location to1, Location from2, Location to2);
+ static bool StoreNeedsWriteBarrier(Primitive::Type type, HInstruction* value) {
+ if (kIsDebugBuild) {
+ if (type == Primitive::kPrimNot && value->IsIntConstant()) {
+ CHECK(value->AsIntConstant()->GetValue() == 0);
+ }
+ }
+ return type == Primitive::kPrimNot && !value->IsIntConstant();
+ }
+
protected:
CodeGenerator(HGraph* graph,
size_t number_of_core_registers,
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 6f5a3cb..9745eda 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1918,11 +1918,12 @@
void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
- bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(instruction->GetFieldType(), instruction->GetValue());
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
// Temporary registers for the write barrier.
- if (is_object_type) {
+ if (needs_write_barrier) {
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
}
@@ -1953,7 +1954,7 @@
case Primitive::kPrimNot: {
Register value = locations->InAt(1).As<Register>();
__ StoreToOffset(kStoreWord, value, obj, offset);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
Register temp = locations->GetTemp(0).As<Register>();
Register card = locations->GetTemp(1).As<Register>();
codegen_->MarkGCCard(temp, card, obj, value);
@@ -2186,10 +2187,14 @@
void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
Primitive::Type value_type = instruction->GetComponentType();
- bool is_object = value_type == Primitive::kPrimNot;
+
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+ bool needs_runtime_call = instruction->NeedsTypeCheck();
+
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
- instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
- if (is_object) {
+ instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+ 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)));
@@ -2198,6 +2203,12 @@
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
locations->SetInAt(2, Location::RequiresRegister());
+
+ if (needs_write_barrier) {
+ // Temporary registers for the write barrier.
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
}
@@ -2206,6 +2217,9 @@
Register obj = locations->InAt(0).As<Register>();
Location index = locations->InAt(1);
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:
@@ -2236,21 +2250,29 @@
break;
}
- case Primitive::kPrimInt: {
- uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
- Register value = locations->InAt(2).As<Register>();
- if (index.IsConstant()) {
- size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
- __ StoreToOffset(kStoreWord, value, obj, offset);
- } else {
- __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
- __ StoreToOffset(kStoreWord, value, IP, data_offset);
- }
- break;
- }
-
+ case Primitive::kPrimInt:
case Primitive::kPrimNot: {
- codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
+ if (!needs_runtime_call) {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ Register value = locations->InAt(2).As<Register>();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ __ StoreToOffset(kStoreWord, value, obj, offset);
+ } else {
+ DCHECK(index.IsRegister()) << index;
+ __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4));
+ __ StoreToOffset(kStoreWord, value, IP, data_offset);
+ }
+ if (needs_write_barrier) {
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ Register temp = locations->GetTemp(0).As<Register>();
+ Register card = locations->GetTemp(1).As<Register>();
+ codegen_->MarkGCCard(temp, card, obj, value);
+ }
+ } else {
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc());
+ }
break;
}
@@ -2602,11 +2624,12 @@
void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
- bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(instruction->GetFieldType(), instruction->GetValue());
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
// Temporary registers for the write barrier.
- if (is_object_type) {
+ if (needs_write_barrier) {
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
}
@@ -2637,7 +2660,7 @@
case Primitive::kPrimNot: {
Register value = locations->InAt(1).As<Register>();
__ StoreToOffset(kStoreWord, value, cls, offset);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
Register temp = locations->GetTemp(0).As<Register>();
Register card = locations->GetTemp(1).As<Register>();
codegen_->MarkGCCard(temp, card, cls, value);
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);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 6f3b161..23b8bd7 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1825,10 +1825,11 @@
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Primitive::Type field_type = instruction->GetFieldType();
- bool is_object_type = field_type == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue());
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
- if (is_object_type) {
+ if (needs_write_barrier) {
// Temporary registers for the write barrier.
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
@@ -1860,7 +1861,7 @@
case Primitive::kPrimNot: {
CpuRegister value = locations->InAt(1).As<CpuRegister>();
__ movl(Address(obj, offset), value);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
codegen_->MarkGCCard(temp, card, obj, value);
@@ -2110,10 +2111,14 @@
void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
Primitive::Type value_type = instruction->GetComponentType();
- bool is_object = value_type == Primitive::kPrimNot;
+
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
+ bool needs_runtime_call = instruction->NeedsTypeCheck();
+
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
- instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall);
- if (is_object) {
+ instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+ 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)));
@@ -2130,6 +2135,12 @@
} else {
locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
}
+
+ if (needs_write_barrier) {
+ // Temporary registers for the write barrier.
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
}
@@ -2139,6 +2150,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:
@@ -2171,46 +2185,61 @@
if (value.IsRegister()) {
__ movw(Address(obj, offset), value.As<CpuRegister>());
} else {
+ DCHECK(value.IsConstant()) << value;
__ movw(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
}
} else {
+ DCHECK(index.IsRegister()) << index;
if (value.IsRegister()) {
__ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
value.As<CpuRegister>());
} else {
- __ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
- Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
- }
- }
- 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<CpuRegister>());
- } else {
- __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
- }
- } else {
- if (value.IsRegister()) {
- __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
- value.As<CpuRegister>());
- } else {
DCHECK(value.IsConstant()) << value;
- __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
+ __ movw(Address(obj, index.As<CpuRegister>(), TIMES_2, data_offset),
Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
}
}
break;
}
+ case Primitive::kPrimInt:
case Primitive::kPrimNot: {
- __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
- DCHECK(!codegen_->IsLeafMethod());
- codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+ 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<CpuRegister>());
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ __ movl(Address(obj, offset),
+ Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ }
+ } else {
+ DCHECK(index.IsRegister()) << index;
+ if (value.IsRegister()) {
+ __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
+ value.As<CpuRegister>());
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
+ Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ }
+ }
+
+ if (needs_write_barrier) {
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
+ CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
+ codegen_->MarkGCCard(temp, card, obj, value.As<CpuRegister>());
+ }
+ } else {
+ DCHECK_EQ(value_type, Primitive::kPrimNot);
+ __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
+ DCHECK(!codegen_->IsLeafMethod());
+ codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+ }
break;
}
@@ -2692,10 +2721,11 @@
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Primitive::Type field_type = instruction->GetFieldType();
- bool is_object_type = field_type == Primitive::kPrimNot;
+ bool needs_write_barrier =
+ CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue());
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
- if (is_object_type) {
+ if (needs_write_barrier) {
// Temporary registers for the write barrier.
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
@@ -2727,7 +2757,7 @@
case Primitive::kPrimNot: {
CpuRegister value = locations->InAt(1).As<CpuRegister>();
__ movl(Address(cls, offset), value);
- if (field_type == Primitive::kPrimNot) {
+ if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) {
CpuRegister temp = locations->GetTemp(0).As<CpuRegister>();
CpuRegister card = locations->GetTemp(1).As<CpuRegister>();
codegen_->MarkGCCard(temp, card, cls, value);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 29eabe7..3e8361e 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -55,4 +55,16 @@
}
}
+void InstructionSimplifier::VisitArraySet(HArraySet* instruction) {
+ HInstruction* value = instruction->GetValue();
+ if (value->GetType() != Primitive::kPrimNot) return;
+
+ if (value->IsArrayGet()) {
+ if (value->AsArrayGet()->GetArray() == instruction->GetArray()) {
+ // If the code is just swapping elements in the array, no need for a type check.
+ instruction->ClearNeedsTypeCheck();
+ }
+ }
+}
+
} // namespace art
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index d74b624..3844d57 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -33,6 +33,7 @@
private:
virtual void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
virtual void VisitEqual(HEqual* equal) OVERRIDE;
+ virtual void VisitArraySet(HArraySet* equal) OVERRIDE;
};
} // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 6224a11..9e79748 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2030,6 +2030,8 @@
MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+ HInstruction* GetValue() const { return InputAt(1); }
+
DECLARE_INSTRUCTION(InstanceFieldSet);
private:
@@ -2046,13 +2048,16 @@
SetRawInputAt(1, index);
}
- virtual bool CanBeMoved() const { return true; }
- virtual bool InstructionDataEquals(HInstruction* other) const {
+ bool CanBeMoved() const OVERRIDE { return true; }
+ bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
UNUSED(other);
return true;
}
void SetType(Primitive::Type type) { type_ = type; }
+ HInstruction* GetArray() const { return InputAt(0); }
+ HInstruction* GetIndex() const { return InputAt(1); }
+
DECLARE_INSTRUCTION(ArrayGet);
private:
@@ -2068,20 +2073,29 @@
uint32_t dex_pc)
: HTemplateInstruction(SideEffects::ChangesSomething()),
dex_pc_(dex_pc),
- expected_component_type_(expected_component_type) {
+ expected_component_type_(expected_component_type),
+ needs_type_check_(value->GetType() == Primitive::kPrimNot) {
SetRawInputAt(0, array);
SetRawInputAt(1, index);
SetRawInputAt(2, value);
}
- virtual bool NeedsEnvironment() const {
+ bool NeedsEnvironment() const {
// We currently always call a runtime method to catch array store
// exceptions.
- return InputAt(2)->GetType() == Primitive::kPrimNot;
+ return needs_type_check_;
}
+ void ClearNeedsTypeCheck() {
+ needs_type_check_ = false;
+ }
+
+ bool NeedsTypeCheck() const { return needs_type_check_; }
+
uint32_t GetDexPc() const { return dex_pc_; }
+ HInstruction* GetArray() const { return InputAt(0); }
+ HInstruction* GetIndex() const { return InputAt(1); }
HInstruction* GetValue() const { return InputAt(2); }
Primitive::Type GetComponentType() const {
@@ -2100,6 +2114,7 @@
private:
const uint32_t dex_pc_;
const Primitive::Type expected_component_type_;
+ bool needs_type_check_;
DISALLOW_COPY_AND_ASSIGN(HArraySet);
};
@@ -2368,6 +2383,8 @@
MemberOffset GetFieldOffset() const { return field_info_.GetFieldOffset(); }
Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
+ HInstruction* GetValue() const { return InputAt(1); }
+
DECLARE_INSTRUCTION(StaticFieldSet);
private:
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 6e3653a..ee92e89 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -286,6 +286,7 @@
InstructionSimplifier(graph).Run();
GlobalValueNumberer(graph->GetArena(), graph).Run();
visualizer.DumpGraph(kGVNPassName);
+ InstructionSimplifier(graph).Run();
PrepareForRegisterAllocation(graph).Run();
SsaLivenessAnalysis liveness(*graph, codegen);