summaryrefslogtreecommitdiffstats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/optimizing/builder.cc53
-rw-r--r--compiler/optimizing/builder.h4
-rw-r--r--compiler/optimizing/code_generator_arm.cc329
-rw-r--r--compiler/optimizing/code_generator_arm.h5
-rw-r--r--compiler/optimizing/code_generator_x86.cc335
-rw-r--r--compiler/optimizing/code_generator_x86.h5
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc325
-rw-r--r--compiler/optimizing/code_generator_x86_64.h5
-rw-r--r--compiler/optimizing/nodes.h78
-rw-r--r--compiler/utils/arm/assembler_thumb2.cc4
-rw-r--r--compiler/utils/assembler_thumb_test.cc6
-rw-r--r--compiler/utils/assembler_thumb_test_expected.cc.inc4
12 files changed, 1047 insertions, 106 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 1f0b3613e7..43e6b830e9 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -425,6 +425,41 @@ bool HGraphBuilder::BuildFieldAccess(const Instruction& instruction,
return true;
}
+void HGraphBuilder::BuildArrayAccess(const Instruction& instruction,
+ uint32_t dex_offset,
+ bool is_put,
+ Primitive::Type anticipated_type) {
+ uint8_t source_or_dest_reg = instruction.VRegA_23x();
+ uint8_t array_reg = instruction.VRegB_23x();
+ uint8_t index_reg = instruction.VRegC_23x();
+
+ DCHECK(IsTypeSupported(anticipated_type));
+
+ // We need one temporary for the null check, one for the index, and one for the length.
+ Temporaries temps(graph_, 3);
+
+ HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot);
+ object = new (arena_) HNullCheck(object, dex_offset);
+ current_block_->AddInstruction(object);
+ temps.Add(object);
+
+ HInstruction* length = new (arena_) HArrayLength(object);
+ current_block_->AddInstruction(length);
+ temps.Add(length);
+ HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt);
+ index = new (arena_) HBoundsCheck(index, length, dex_offset);
+ current_block_->AddInstruction(index);
+ temps.Add(index);
+ if (is_put) {
+ HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type);
+ // TODO: Insert a type check node if the type is Object.
+ current_block_->AddInstruction(new (arena_) HArraySet(object, index, value, dex_offset));
+ } else {
+ current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type));
+ UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
+ }
+}
+
bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
if (current_block_ == nullptr) {
return true; // Dead code
@@ -697,6 +732,24 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_
break;
}
+#define ARRAY_XX(kind, anticipated_type) \
+ case Instruction::AGET##kind: { \
+ BuildArrayAccess(instruction, dex_offset, false, anticipated_type); \
+ break; \
+ } \
+ case Instruction::APUT##kind: { \
+ BuildArrayAccess(instruction, dex_offset, true, anticipated_type); \
+ break; \
+ }
+
+ ARRAY_XX(, Primitive::kPrimInt);
+ ARRAY_XX(_WIDE, Primitive::kPrimLong);
+ ARRAY_XX(_OBJECT, Primitive::kPrimNot);
+ ARRAY_XX(_BOOLEAN, Primitive::kPrimBoolean);
+ ARRAY_XX(_BYTE, Primitive::kPrimByte);
+ ARRAY_XX(_CHAR, Primitive::kPrimChar);
+ ARRAY_XX(_SHORT, Primitive::kPrimShort);
+
default:
return false;
}
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index f94b8e810a..170c42761a 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -93,6 +93,10 @@ class HGraphBuilder : public ValueObject {
void BuildReturn(const Instruction& instruction, Primitive::Type type);
bool BuildFieldAccess(const Instruction& instruction, uint32_t dex_offset, bool is_get);
+ void BuildArrayAccess(const Instruction& instruction,
+ uint32_t dex_offset,
+ bool is_get,
+ Primitive::Type anticipated_type);
// Builds an invocation node and returns whether the instruction is supported.
bool BuildInvoke(const Instruction& instruction,
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 90ec6cfdbd..eccc970042 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -39,6 +39,24 @@ static constexpr bool kExplicitStackOverflowCheck = false;
static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7
static constexpr int kCurrentMethodStackOffset = 0;
+static Location ArmCoreLocation(Register reg) {
+ return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
+}
+
+static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 };
+static constexpr size_t kRuntimeParameterCoreRegistersLength =
+ arraysize(kRuntimeParameterCoreRegisters);
+
+class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
+ public:
+ InvokeRuntimeCallingConvention()
+ : CallingConvention(kRuntimeParameterCoreRegisters,
+ kRuntimeParameterCoreRegistersLength) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
+};
+
#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
class NullCheckSlowPathARM : public SlowPathCode {
@@ -72,6 +90,33 @@ class StackOverflowCheckSlowPathARM : public SlowPathCode {
DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
};
+class BoundsCheckSlowPathARM : public SlowPathCode {
+ public:
+ explicit BoundsCheckSlowPathARM(uint32_t dex_pc,
+ Location index_location,
+ Location length_location)
+ : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
+ __ Bind(GetEntryLabel());
+ InvokeRuntimeCallingConvention calling_convention;
+ arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_);
+ arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_);
+ int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value();
+ __ ldr(LR, Address(TR, offset));
+ __ blx(LR);
+ codegen->RecordPcInfo(dex_pc_);
+ }
+
+ private:
+ const uint32_t dex_pc_;
+ const Location index_location_;
+ const Location length_location_;
+
+ DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM);
+};
+
#undef __
#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
@@ -214,10 +259,6 @@ size_t CodeGeneratorARM::GetNumberOfRegisters() const {
return kNumberOfRegIds;
}
-static Location ArmCoreLocation(Register reg) {
- return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg));
-}
-
InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
: HGraphVisitor(graph),
assembler_(codegen->GetAssembler()),
@@ -943,20 +984,6 @@ void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
}
}
-static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 };
-static constexpr size_t kRuntimeParameterCoreRegistersLength =
- arraysize(kRuntimeParameterCoreRegisters);
-
-class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
- public:
- InvokeRuntimeCallingConvention()
- : CallingConvention(kRuntimeParameterCoreRegisters,
- kRuntimeParameterCoreRegistersLength) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
-};
-
void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
codegen_->MarkNotLeaf();
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
@@ -1099,24 +1126,15 @@ void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instr
break;
}
- case Primitive::kPrimInt: {
- Register value = locations->InAt(1).AsArm().AsCoreRegister();
- __ StoreToOffset(kStoreWord, value, obj, offset);
- break;
- }
-
+ case Primitive::kPrimInt:
case Primitive::kPrimNot: {
Register value = locations->InAt(1).AsArm().AsCoreRegister();
__ StoreToOffset(kStoreWord, value, obj, offset);
-
- Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
- Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
- Label is_null;
- __ CompareAndBranchIfZero(value, &is_null);
- __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
- __ Lsr(temp, obj, gc::accounting::CardTable::kCardShift);
- __ strb(card, Address(card, temp));
- __ Bind(&is_null);
+ if (field_type == Primitive::kPrimNot) {
+ Register temp = locations->GetTemp(0).AsArm().AsCoreRegister();
+ Register card = locations->GetTemp(1).AsArm().AsCoreRegister();
+ codegen_->MarkGCCard(temp, card, obj, value);
+ }
break;
}
@@ -1218,6 +1236,251 @@ void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
__ b(slow_path->GetEntryLabel(), EQ);
}
+void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister());
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Register obj = locations->InAt(0).AsArm().AsCoreRegister();
+ Location index = locations->InAt(1);
+
+ switch (instruction->GetType()) {
+ case Primitive::kPrimBoolean: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
+ Register out = locations->Out().AsArm().AsCoreRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
+ __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
+ __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimByte: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
+ Register out = locations->Out().AsArm().AsCoreRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
+ __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
+ __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimShort: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
+ Register out = locations->Out().AsArm().AsCoreRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+ __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
+ __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimChar: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
+ Register out = locations->Out().AsArm().AsCoreRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+ __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
+ __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimInt:
+ case Primitive::kPrimNot: {
+ DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ Register out = locations->Out().AsArm().AsCoreRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ __ LoadFromOffset(kLoadWord, out, obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4));
+ __ LoadFromOffset(kLoadWord, out, IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimLong: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
+ ArmManagedRegister out = locations->Out().AsArm();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+ __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
+ __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable type " << instruction->GetType();
+ }
+}
+
+void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ Primitive::Type value_type = instruction->InputAt(2)->GetType();
+ if (value_type == Primitive::kPrimNot) {
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0)));
+ locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1)));
+ locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2)));
+ codegen_->MarkNotLeaf();
+ } else {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ locations->SetInAt(2, Location::RequiresRegister());
+ }
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Register obj = locations->InAt(0).AsArm().AsCoreRegister();
+ Location index = locations->InAt(1);
+ Primitive::Type value_type = instruction->InputAt(2)->GetType();
+
+ switch (value_type) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
+ Register value = locations->InAt(2).AsArm().AsCoreRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
+ __ StoreToOffset(kStoreByte, value, obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister()));
+ __ StoreToOffset(kStoreByte, value, IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimShort:
+ case Primitive::kPrimChar: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
+ Register value = locations->InAt(2).AsArm().AsCoreRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+ __ StoreToOffset(kStoreHalfword, value, obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2));
+ __ StoreToOffset(kStoreHalfword, value, IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimInt: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ Register value = locations->InAt(2).AsArm().AsCoreRegister();
+ 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.AsArm().AsCoreRegister(), LSL, TIMES_4));
+ __ StoreToOffset(kStoreWord, value, IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimNot: {
+ int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value();
+ __ ldr(LR, Address(TR, offset));
+ __ blx(LR);
+ codegen_->RecordPcInfo(instruction->GetDexPc());
+ DCHECK(!codegen_->IsLeafMethod());
+ break;
+ }
+
+ case Primitive::kPrimLong: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
+ ArmManagedRegister value = locations->InAt(2).AsArm();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+ __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset);
+ } else {
+ __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8));
+ __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset);
+ }
+ break;
+ }
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable type " << instruction->GetType();
+ }
+}
+
+void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister());
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
+ Register obj = locations->InAt(0).AsArm().AsCoreRegister();
+ Register out = locations->Out().AsArm().AsCoreRegister();
+ __ LoadFromOffset(kLoadWord, out, obj, offset);
+}
+
+void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ // TODO: Have a normalization phase that makes this instruction never used.
+ locations->SetOut(Location::SameAsFirstInput());
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
+ instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
+ codegen_->AddSlowPath(slow_path);
+
+ Register index = locations->InAt(0).AsArm().AsCoreRegister();
+ Register length = locations->InAt(1).AsArm().AsCoreRegister();
+
+ __ cmp(index, ShifterOperand(length));
+ __ b(slow_path->GetEntryLabel(), CS);
+}
+
+void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
+ Label is_null;
+ __ CompareAndBranchIfZero(value, &is_null);
+ __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
+ __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
+ __ strb(card, Address(card, temp));
+ __ Bind(&is_null);
+}
+
void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
temp->SetLocations(nullptr);
}
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 85ab22b178..610625c50b 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -175,12 +175,15 @@ class CodeGeneratorARM : public CodeGenerator {
return InstructionSet::kThumb2;
}
- private:
// Helper method to move a 32bits value between two locations.
void Move32(Location destination, Location source);
// Helper method to move a 64bits value between two locations.
void Move64(Location destination, Location source);
+ // Emit a write barrier.
+ void MarkGCCard(Register temp, Register card, Register object, Register value);
+
+ private:
LocationsBuilderARM location_builder_;
InstructionCodeGeneratorARM instruction_visitor_;
ParallelMoveResolverARM move_resolver_;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 251a2adf61..2264638110 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -39,6 +39,24 @@ static constexpr bool kExplicitStackOverflowCheck = false;
static constexpr int kNumberOfPushedRegistersAtEntry = 1;
static constexpr int kCurrentMethodStackOffset = 0;
+static Location X86CpuLocation(Register reg) {
+ return Location::RegisterLocation(X86ManagedRegister::FromCpuRegister(reg));
+}
+
+static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX };
+static constexpr size_t kRuntimeParameterCoreRegistersLength =
+ arraysize(kRuntimeParameterCoreRegisters);
+
+class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
+ public:
+ InvokeRuntimeCallingConvention()
+ : CallingConvention(kRuntimeParameterCoreRegisters,
+ kRuntimeParameterCoreRegistersLength) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
+};
+
#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
class NullCheckSlowPathX86 : public SlowPathCode {
@@ -71,6 +89,31 @@ class StackOverflowCheckSlowPathX86 : public SlowPathCode {
DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86);
};
+class BoundsCheckSlowPathX86 : public SlowPathCode {
+ public:
+ explicit BoundsCheckSlowPathX86(uint32_t dex_pc,
+ Location index_location,
+ Location length_location)
+ : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ CodeGeneratorX86* x86_codegen = reinterpret_cast<CodeGeneratorX86*>(codegen);
+ __ Bind(GetEntryLabel());
+ InvokeRuntimeCallingConvention calling_convention;
+ x86_codegen->Move32(X86CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
+ x86_codegen->Move32(X86CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
+ codegen->RecordPcInfo(dex_pc_);
+ }
+
+ private:
+ const uint32_t dex_pc_;
+ const Location index_location_;
+ const Location length_location_;
+
+ DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
+};
+
#undef __
#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
@@ -188,10 +231,6 @@ size_t CodeGeneratorX86::GetNumberOfRegisters() const {
return kNumberOfRegIds;
}
-static Location X86CpuLocation(Register reg) {
- return Location::RegisterLocation(X86ManagedRegister::FromCpuRegister(reg));
-}
-
InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
: HGraphVisitor(graph),
assembler_(codegen->GetAssembler()),
@@ -260,20 +299,6 @@ Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
return Location();
}
-static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX };
-static constexpr size_t kRuntimeParameterCoreRegistersLength =
- arraysize(kRuntimeParameterCoreRegisters);
-
-class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
- public:
- InvokeRuntimeCallingConvention()
- : CallingConvention(kRuntimeParameterCoreRegisters,
- kRuntimeParameterCoreRegistersLength) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
-};
-
Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
switch (type) {
case Primitive::kPrimBoolean:
@@ -1048,7 +1073,7 @@ void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction)
locations->SetInAt(1, Location::RequiresRegister());
}
// Temporary registers for the write barrier.
- if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
+ if (field_type == Primitive::kPrimNot) {
locations->AddTemp(Location::RequiresRegister());
// Ensure the card is in a byte register.
locations->AddTemp(X86CpuLocation(ECX));
@@ -1077,25 +1102,16 @@ void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instr
break;
}
- case Primitive::kPrimInt: {
- Register value = locations->InAt(1).AsX86().AsCpuRegister();
- __ movl(Address(obj, offset), value);
- break;
- }
-
+ case Primitive::kPrimInt:
case Primitive::kPrimNot: {
Register value = locations->InAt(1).AsX86().AsCpuRegister();
__ movl(Address(obj, offset), value);
- Label is_null;
- Register temp = locations->GetTemp(0).AsX86().AsCpuRegister();
- Register card = locations->GetTemp(1).AsX86().AsCpuRegister();
- __ testl(value, value);
- __ j(kEqual, &is_null);
- __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
- __ movl(temp, obj);
- __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
- __ movb(Address(temp, card, TIMES_1, 0), locations->GetTemp(1).AsX86().AsByteRegister());
- __ Bind(&is_null);
+
+ if (field_type == Primitive::kPrimNot) {
+ Register temp = locations->GetTemp(0).AsX86().AsCpuRegister();
+ Register card = locations->GetTemp(1).AsX86().AsCpuRegister();
+ codegen_->MarkGCCard(temp, card, obj, value);
+ }
break;
}
@@ -1115,6 +1131,18 @@ void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instr
}
}
+void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
+ Label is_null;
+ __ testl(value, value);
+ __ j(kEqual, &is_null);
+ __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
+ __ movl(temp, object);
+ __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
+ __ movb(Address(temp, card, TIMES_1, 0),
+ X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
+ __ Bind(&is_null);
+}
+
void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
locations->SetInAt(0, Location::RequiresRegister());
@@ -1202,6 +1230,243 @@ void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
__ j(kEqual, slow_path->GetEntryLabel());
}
+void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister());
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Register obj = locations->InAt(0).AsX86().AsCpuRegister();
+ Location index = locations->InAt(1);
+
+ switch (instruction->GetType()) {
+ case Primitive::kPrimBoolean: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
+ Register out = locations->Out().AsX86().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movzxb(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
+ } else {
+ __ movzxb(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimByte: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
+ Register out = locations->Out().AsX86().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movsxb(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
+ } else {
+ __ movsxb(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimShort: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
+ Register out = locations->Out().AsX86().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movsxw(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
+ } else {
+ __ movsxw(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimChar: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
+ Register out = locations->Out().AsX86().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movzxw(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
+ } else {
+ __ movzxw(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimInt:
+ case Primitive::kPrimNot: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ Register out = locations->Out().AsX86().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movl(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
+ } else {
+ __ movl(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_4, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimLong: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
+ X86ManagedRegister out = locations->Out().AsX86();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+ __ movl(out.AsRegisterPairLow(), Address(obj, offset));
+ __ movl(out.AsRegisterPairHigh(), Address(obj, offset + kX86WordSize));
+ } else {
+ __ movl(out.AsRegisterPairLow(),
+ Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset));
+ __ movl(out.AsRegisterPairHigh(),
+ Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset + kX86WordSize));
+ }
+ break;
+ }
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable type " << instruction->GetType();
+ }
+}
+
+void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ Primitive::Type value_type = instruction->InputAt(2)->GetType();
+ if (value_type == Primitive::kPrimNot) {
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, X86CpuLocation(calling_convention.GetRegisterAt(0)));
+ locations->SetInAt(1, X86CpuLocation(calling_convention.GetRegisterAt(1)));
+ locations->SetInAt(2, X86CpuLocation(calling_convention.GetRegisterAt(2)));
+ codegen_->MarkNotLeaf();
+ } else {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ if (value_type == Primitive::kPrimBoolean || value_type == Primitive::kPrimByte) {
+ // Ensure the value is in a byte register.
+ locations->SetInAt(2, X86CpuLocation(EAX));
+ } else {
+ locations->SetInAt(2, Location::RequiresRegister());
+ }
+ }
+
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Register obj = locations->InAt(0).AsX86().AsCpuRegister();
+ Location index = locations->InAt(1);
+ Primitive::Type value_type = instruction->InputAt(2)->GetType();
+
+ switch (value_type) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
+ ByteRegister value = locations->InAt(2).AsX86().AsByteRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
+ __ movb(Address(obj, offset), value);
+ } else {
+ __ movb(Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset), value);
+ }
+ break;
+ }
+
+ case Primitive::kPrimShort:
+ case Primitive::kPrimChar: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
+ Register value = locations->InAt(2).AsX86().AsCpuRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+ __ movw(Address(obj, offset), value);
+ } else {
+ __ movw(Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset), value);
+ }
+ break;
+ }
+
+ case Primitive::kPrimInt: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ Register value = locations->InAt(2).AsX86().AsCpuRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ __ movl(Address(obj, offset), value);
+ } else {
+ __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_4, data_offset), value);
+ }
+ break;
+ }
+
+ case Primitive::kPrimNot: {
+ DCHECK(!codegen_->IsLeafMethod());
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
+ codegen_->RecordPcInfo(instruction->GetDexPc());
+ break;
+ }
+
+ case Primitive::kPrimLong: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
+ X86ManagedRegister value = locations->InAt(2).AsX86();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+ __ movl(Address(obj, offset), value.AsRegisterPairLow());
+ __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh());
+ } else {
+ __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset),
+ value.AsRegisterPairLow());
+ __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset + kX86WordSize),
+ value.AsRegisterPairHigh());
+ }
+ break;
+ }
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable type " << instruction->GetType();
+ }
+}
+
+void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister());
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
+ Register obj = locations->InAt(0).AsX86().AsCpuRegister();
+ Register out = locations->Out().AsX86().AsCpuRegister();
+ __ movl(out, Address(obj, offset));
+}
+
+void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ // TODO: Have a normalization phase that makes this instruction never used.
+ locations->SetOut(Location::SameAsFirstInput());
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(
+ instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
+ codegen_->AddSlowPath(slow_path);
+
+ Register index = locations->InAt(0).AsX86().AsCpuRegister();
+ Register length = locations->InAt(1).AsX86().AsCpuRegister();
+
+ __ cmpl(index, length);
+ __ j(kAboveEqual, slow_path->GetEntryLabel());
+}
+
void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
temp->SetLocations(nullptr);
}
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index b7c2ad8319..7c502049d8 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -177,12 +177,15 @@ class CodeGeneratorX86 : public CodeGenerator {
return InstructionSet::kX86;
}
- private:
// Helper method to move a 32bits value between two locations.
void Move32(Location destination, Location source);
// Helper method to move a 64bits value between two locations.
void Move64(Location destination, Location source);
+ // Emit a write barrier.
+ void MarkGCCard(Register temp, Register card, Register object, Register value);
+
+ private:
LocationsBuilderX86 location_builder_;
InstructionCodeGeneratorX86 instruction_visitor_;
ParallelMoveResolverX86 move_resolver_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 641e8e178b..2ff2a1710e 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -43,6 +43,23 @@ static constexpr Register TMP = R11;
static constexpr int kNumberOfPushedRegistersAtEntry = 1;
static constexpr int kCurrentMethodStackOffset = 0;
+static Location X86_64CpuLocation(Register reg) {
+ return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
+}
+
+static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
+static constexpr size_t kRuntimeParameterCoreRegistersLength =
+ arraysize(kRuntimeParameterCoreRegisters);
+
+class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
+ public:
+ InvokeRuntimeCallingConvention()
+ : CallingConvention(kRuntimeParameterCoreRegisters,
+ kRuntimeParameterCoreRegistersLength) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
+};
#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
@@ -78,6 +95,32 @@ class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
};
+class BoundsCheckSlowPathX86_64 : public SlowPathCode {
+ public:
+ explicit BoundsCheckSlowPathX86_64(uint32_t dex_pc,
+ Location index_location,
+ Location length_location)
+ : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
+ __ Bind(GetEntryLabel());
+ InvokeRuntimeCallingConvention calling_convention;
+ x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
+ x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
+ __ gs()->call(Address::Absolute(
+ QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
+ codegen->RecordPcInfo(dex_pc_);
+ }
+
+ private:
+ const uint32_t dex_pc_;
+ const Location index_location_;
+ const Location length_location_;
+
+ DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
+};
+
#undef __
#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
@@ -103,10 +146,6 @@ void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int re
stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
}
-static Location X86_64CpuLocation(Register reg) {
- return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
-}
-
CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
: CodeGenerator(graph, kNumberOfRegIds),
location_builder_(graph, this),
@@ -117,7 +156,8 @@ size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
}
-InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen)
+InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
+ CodeGeneratorX86_64* codegen)
: HGraphVisitor(graph),
assembler_(codegen->GetAssembler()),
codegen_(codegen) {}
@@ -603,20 +643,6 @@ void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
__ ret();
}
-static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
-static constexpr size_t kRuntimeParameterCoreRegistersLength =
- arraysize(kRuntimeParameterCoreRegisters);
-
-class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
- public:
- InvokeRuntimeCallingConvention()
- : CallingConvention(kRuntimeParameterCoreRegisters,
- kRuntimeParameterCoreRegistersLength) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
-};
-
Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
switch (type) {
case Primitive::kPrimBoolean:
@@ -944,24 +970,14 @@ void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* in
break;
}
- case Primitive::kPrimInt: {
- __ movl(Address(obj, offset), value);
- break;
- }
-
+ case Primitive::kPrimInt:
case Primitive::kPrimNot: {
__ movl(Address(obj, offset), value);
- Label is_null;
- CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
- CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
- __ testl(value, value);
- __ j(kEqual, &is_null);
- __ gs()->movq(card, Address::Absolute(
- Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
- __ movq(temp, obj);
- __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
- __ movb(Address(temp, card, TIMES_1, 0), card);
- __ Bind(&is_null);
+ if (field_type == Primitive::kPrimNot) {
+ CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
+ CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
+ codegen_->MarkGCCard(temp, card, obj, value);
+ }
break;
}
@@ -1059,6 +1075,245 @@ void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
__ j(kEqual, slow_path->GetEntryLabel());
}
+void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister());
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
+ Location index = locations->InAt(1);
+
+ switch (instruction->GetType()) {
+ case Primitive::kPrimBoolean: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
+ CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movzxb(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
+ } else {
+ __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimByte: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
+ CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movsxb(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
+ } else {
+ __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimShort: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
+ CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movsxw(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
+ } else {
+ __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimChar: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
+ CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movzxw(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
+ } else {
+ __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimInt:
+ case Primitive::kPrimNot: {
+ DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movl(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
+ } else {
+ __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimLong: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
+ CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ __ movq(out, Address(obj,
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
+ } else {
+ __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
+ }
+ break;
+ }
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable type " << instruction->GetType();
+ }
+}
+
+void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ Primitive::Type value_type = instruction->InputAt(2)->GetType();
+ if (value_type == Primitive::kPrimNot) {
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
+ locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
+ locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
+ codegen_->MarkNotLeaf();
+ } else {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ locations->SetInAt(2, Location::RequiresRegister());
+ }
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
+ Location index = locations->InAt(1);
+ Primitive::Type value_type = instruction->InputAt(2)->GetType();
+
+ switch (value_type) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
+ CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
+ __ movb(Address(obj, offset), value);
+ } else {
+ __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
+ }
+ break;
+ }
+
+ case Primitive::kPrimShort:
+ case Primitive::kPrimChar: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
+ CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+ __ movw(Address(obj, offset), value);
+ } else {
+ __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
+ }
+ break;
+ }
+
+ case Primitive::kPrimInt: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
+ CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+ __ movl(Address(obj, offset), value);
+ } else {
+ __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
+ }
+ break;
+ }
+
+ case Primitive::kPrimNot: {
+ __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
+ DCHECK(!codegen_->IsLeafMethod());
+ codegen_->RecordPcInfo(instruction->GetDexPc());
+ break;
+ }
+
+ case Primitive::kPrimLong: {
+ uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
+ CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
+ if (index.IsConstant()) {
+ size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+ __ movq(Address(obj, offset), value);
+ } else {
+ __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
+ }
+ break;
+ }
+
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
+
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable type " << instruction->GetType();
+ }
+}
+
+void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister());
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
+ CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
+ CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
+ __ movl(out, Address(obj, offset));
+}
+
+void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ // TODO: Have a normalization phase that makes this instruction never used.
+ locations->SetOut(Location::SameAsFirstInput());
+ instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
+ instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
+ codegen_->AddSlowPath(slow_path);
+
+ CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
+ CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
+
+ __ cmpl(index, length);
+ __ j(kAboveEqual, slow_path->GetEntryLabel());
+}
+
+void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
+ CpuRegister card,
+ CpuRegister object,
+ CpuRegister value) {
+ Label is_null;
+ __ testl(value, value);
+ __ j(kEqual, &is_null);
+ __ gs()->movq(card, Address::Absolute(
+ Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
+ __ movq(temp, object);
+ __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
+ __ movb(Address(temp, card, TIMES_1, 0), card);
+ __ Bind(&is_null);
+}
+
void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
temp->SetLocations(nullptr);
}
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index a20ca3f260..44552ea465 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -176,10 +176,13 @@ class CodeGeneratorX86_64 : public CodeGenerator {
return InstructionSet::kX86_64;
}
- private:
+ // Emit a write barrier.
+ void MarkGCCard(CpuRegister temp, CpuRegister card, CpuRegister object, CpuRegister value);
+
// Helper method to move a value between two locations.
void Move(Location destination, Location source);
+ private:
LocationsBuilderX86_64 location_builder_;
InstructionCodeGeneratorX86_64 instruction_visitor_;
ParallelMoveResolverX86_64 move_resolver_;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 61a6f6b1b6..cb3dd0f69f 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -437,6 +437,10 @@ class HBasicBlock : public ArenaObject {
M(Compare) \
M(InstanceFieldGet) \
M(InstanceFieldSet) \
+ M(ArrayGet) \
+ M(ArraySet) \
+ M(ArrayLength) \
+ M(BoundsCheck) \
M(NullCheck) \
M(Temporary) \
@@ -1367,6 +1371,80 @@ class HInstanceFieldSet : public HTemplateInstruction<2> {
DISALLOW_COPY_AND_ASSIGN(HInstanceFieldSet);
};
+class HArrayGet : public HExpression<2> {
+ public:
+ HArrayGet(HInstruction* array, HInstruction* index, Primitive::Type type)
+ : HExpression(type) {
+ SetRawInputAt(0, array);
+ SetRawInputAt(1, index);
+ }
+
+ DECLARE_INSTRUCTION(ArrayGet);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HArrayGet);
+};
+
+class HArraySet : public HTemplateInstruction<3> {
+ public:
+ HArraySet(HInstruction* array,
+ HInstruction* index,
+ HInstruction* value,
+ uint32_t dex_pc) : dex_pc_(dex_pc) {
+ SetRawInputAt(0, array);
+ SetRawInputAt(1, index);
+ SetRawInputAt(2, value);
+ }
+
+ virtual bool NeedsEnvironment() const {
+ // We currently always call a runtime method to catch array store
+ // exceptions.
+ return InputAt(2)->GetType() == Primitive::kPrimNot;
+ }
+
+ uint32_t GetDexPc() const { return dex_pc_; }
+
+ DECLARE_INSTRUCTION(ArraySet);
+
+ private:
+ const uint32_t dex_pc_;
+
+ DISALLOW_COPY_AND_ASSIGN(HArraySet);
+};
+
+class HArrayLength : public HExpression<1> {
+ public:
+ explicit HArrayLength(HInstruction* array) : HExpression(Primitive::kPrimInt) {
+ SetRawInputAt(0, array);
+ }
+
+ DECLARE_INSTRUCTION(ArrayLength);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HArrayLength);
+};
+
+class HBoundsCheck : public HExpression<2> {
+ public:
+ HBoundsCheck(HInstruction* index, HInstruction* length, uint32_t dex_pc)
+ : HExpression(index->GetType()), dex_pc_(dex_pc) {
+ DCHECK(index->GetType() == Primitive::kPrimInt);
+ SetRawInputAt(0, index);
+ SetRawInputAt(1, length);
+ }
+
+ virtual bool NeedsEnvironment() const { return true; }
+
+ uint32_t GetDexPc() const { return dex_pc_; }
+
+ DECLARE_INSTRUCTION(BoundsCheck);
+
+ private:
+ const uint32_t dex_pc_;
+
+ DISALLOW_COPY_AND_ASSIGN(HBoundsCheck);
+};
+
/**
* Some DEX instructions are folded into multiple HInstructions that need
* to stay live until the last HInstruction. This class
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 78ff31a061..4904428489 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -659,6 +659,10 @@ bool Thumb2Assembler::Is32BitDataProcessing(Condition cond,
if (so.IsImmediate()) {
return true;
}
+
+ if (!can_contain_high_register) {
+ return true;
+ }
}
if (so.IsRegister() && IsHighRegister(so.GetRegister()) && !can_contain_high_register) {
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index 3312f8f21a..891a287666 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -312,6 +312,9 @@ TEST(Thumb2AssemblerTest, DataProcessingRegister) {
__ movs(R0, ShifterOperand(R1));
__ mvns(R0, ShifterOperand(R1));
+ // 32 bit variants.
+ __ add(R12, R1, ShifterOperand(R0));
+
size_t cs = __ CodeSize();
std::vector<uint8_t> managed_code(cs);
MemoryRegion code(&managed_code[0], managed_code.size());
@@ -868,6 +871,9 @@ TEST(Thumb2AssemblerTest, StoreToOffset) {
__ StoreToOffset(kStoreWord, R2, R4, 12); // Simple
__ StoreToOffset(kStoreWord, R2, R4, 0x2000); // Offset too big.
+ __ StoreToOffset(kStoreWord, R0, R12, 12);
+ __ StoreToOffset(kStoreHalfword, R0, R12, 12);
+ __ StoreToOffset(kStoreByte, R2, R12, 12);
size_t cs = __ CodeSize();
std::vector<uint8_t> managed_code(cs);
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 18035f391c..3f2641c76f 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -43,6 +43,7 @@ const char* DataProcessingRegisterResults[] = {
" 3e: 42c8 cmn r0, r1\n",
" 40: 0008 movs r0, r1\n",
" 42: 43c8 mvns r0, r1\n",
+ " 44: eb01 0c00 add.w ip, r1, r0\n",
nullptr
};
const char* DataProcessingImmediateResults[] = {
@@ -355,6 +356,9 @@ const char* StoreToOffsetResults[] = {
" 2: f44f 5c00 mov.w ip, #8192 ; 0x2000\n",
" 6: 44a4 add ip, r4\n",
" 8: f8cc 2000 str.w r2, [ip]\n",
+ " c: f8cc 000c str.w r0, [ip, #12]\n",
+ " 10: f8ac 000c strh.w r0, [ip, #12]\n",
+ " 14: f88c 200c strb.w r2, [ip, #12]\n",
nullptr
};
const char* IfThenResults[] = {