diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/optimizing/builder.cc | 138 | ||||
-rw-r--r-- | compiler/optimizing/builder.h | 41 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 23 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 32 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 32 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 25 |
6 files changed, 284 insertions, 7 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 2f1a092ea8..1188ec0948 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -171,6 +171,7 @@ HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { const uint16_t* code_ptr = code_item.insns_; const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_; + code_start_ = code_ptr; // Setup the graph with the entry block and exit block. graph_ = new (arena_) HGraph(arena_); @@ -416,6 +417,7 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, DCHECK_EQ(argument_index, number_of_arguments); current_block_->AddInstruction(invoke); + latest_result_ = invoke; return true; } @@ -503,6 +505,62 @@ void HGraphBuilder::BuildArrayAccess(const Instruction& instruction, } } +void HGraphBuilder::BuildFilledNewArray(uint32_t dex_offset, + uint32_t type_index, + uint32_t number_of_vreg_arguments, + bool is_range, + uint32_t* args, + uint32_t register_index) { + HInstruction* length = GetIntConstant(number_of_vreg_arguments); + HInstruction* object = new (arena_) HNewArray(length, dex_offset, type_index); + current_block_->AddInstruction(object); + + const char* descriptor = dex_file_->StringByTypeIdx(type_index); + DCHECK_EQ(descriptor[0], '[') << descriptor; + char primitive = descriptor[1]; + DCHECK(primitive == 'I' + || primitive == 'L' + || primitive == '[') << descriptor; + bool is_reference_array = (primitive == 'L') || (primitive == '['); + Primitive::Type type = is_reference_array ? Primitive::kPrimNot : Primitive::kPrimInt; + + Temporaries temps(graph_, 1); + temps.Add(object); + for (size_t i = 0; i < number_of_vreg_arguments; ++i) { + HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type); + HInstruction* index = GetIntConstant(i); + current_block_->AddInstruction( + new (arena_) HArraySet(object, index, value, type, dex_offset)); + } + latest_result_ = object; +} + +template <typename T> +void HGraphBuilder::BuildFillArrayData(HInstruction* object, + const T* data, + uint32_t element_count, + Primitive::Type anticipated_type, + uint32_t dex_offset) { + for (uint32_t i = 0; i < element_count; ++i) { + HInstruction* index = GetIntConstant(i); + HInstruction* value = GetIntConstant(data[i]); + current_block_->AddInstruction(new (arena_) HArraySet( + object, index, value, anticipated_type, dex_offset)); + } +} + +void HGraphBuilder::BuildFillWideArrayData(HInstruction* object, + const uint64_t* data, + uint32_t element_count, + uint32_t dex_offset) { + for (uint32_t i = 0; i < element_count; ++i) { + HInstruction* index = GetIntConstant(i); + HInstruction* value = GetLongConstant(data[i]); + current_block_->AddInstruction(new (arena_) HArraySet( + object, index, value, Primitive::kPrimLong, dex_offset)); + } +} + void HGraphBuilder::PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_offset) { if (target_offset <= 0) { // Unconditionnally add a suspend check to backward branches. We can remove @@ -807,10 +865,88 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::NEW_ARRAY: { + HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt); + current_block_->AddInstruction( + new (arena_) HNewArray(length, dex_offset, instruction.VRegC_22c())); + UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction()); + break; + } + + case Instruction::FILLED_NEW_ARRAY: { + uint32_t number_of_vreg_arguments = instruction.VRegA_35c(); + uint32_t type_index = instruction.VRegB_35c(); + uint32_t args[5]; + instruction.GetVarArgs(args); + BuildFilledNewArray(dex_offset, type_index, number_of_vreg_arguments, false, args, 0); + break; + } + + case Instruction::FILLED_NEW_ARRAY_RANGE: { + uint32_t number_of_vreg_arguments = instruction.VRegA_3rc(); + uint32_t type_index = instruction.VRegB_3rc(); + uint32_t register_index = instruction.VRegC_3rc(); + BuildFilledNewArray( + dex_offset, type_index, number_of_vreg_arguments, true, nullptr, register_index); + break; + } + + case Instruction::FILL_ARRAY_DATA: { + Temporaries temps(graph_, 1); + HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot); + HNullCheck* null_check = new (arena_) HNullCheck(array, dex_offset); + current_block_->AddInstruction(null_check); + temps.Add(null_check); + + HInstruction* length = new (arena_) HArrayLength(null_check); + current_block_->AddInstruction(length); + + int32_t payload_offset = instruction.VRegB_31t() + dex_offset; + const Instruction::ArrayDataPayload* payload = + reinterpret_cast<const Instruction::ArrayDataPayload*>(code_start_ + payload_offset); + const uint8_t* data = payload->data; + uint32_t element_count = payload->element_count; + + // Implementation of this DEX instruction seems to be that the bounds check is + // done before doing any stores. + HInstruction* last_index = GetIntConstant(payload->element_count - 1); + current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_offset)); + + switch (payload->element_width) { + case 1: + BuildFillArrayData(null_check, data, element_count, Primitive::kPrimByte, dex_offset); + break; + case 2: + BuildFillArrayData(null_check, + reinterpret_cast<const uint16_t*>(data), + element_count, + Primitive::kPrimShort, + dex_offset); + break; + case 4: + BuildFillArrayData(null_check, + reinterpret_cast<const uint32_t*>(data), + element_count, + Primitive::kPrimInt, + dex_offset); + break; + case 8: + BuildFillWideArrayData(null_check, + reinterpret_cast<const uint64_t*>(data), + element_count, + dex_offset); + break; + default: + LOG(FATAL) << "Unknown element width for " << payload->element_width; + } + break; + } + case Instruction::MOVE_RESULT: case Instruction::MOVE_RESULT_WIDE: case Instruction::MOVE_RESULT_OBJECT: - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); + UpdateLocal(instruction.VRegA(), latest_result_); + latest_result_ = nullptr; break; case Instruction::CMP_LONG: { diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 90e50ad951..c5e02db88c 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -48,7 +48,9 @@ class HGraphBuilder : public ValueObject { dex_file_(dex_file), dex_compilation_unit_(dex_compilation_unit), compiler_driver_(driver), - return_type_(Primitive::GetType(dex_compilation_unit_->GetShorty()[0])) {} + return_type_(Primitive::GetType(dex_compilation_unit_->GetShorty()[0])), + code_start_(nullptr), + latest_result_(nullptr) {} // Only for unit testing. HGraphBuilder(ArenaAllocator* arena, Primitive::Type return_type = Primitive::kPrimInt) @@ -64,7 +66,9 @@ class HGraphBuilder : public ValueObject { dex_file_(nullptr), dex_compilation_unit_(nullptr), compiler_driver_(nullptr), - return_type_(return_type) {} + return_type_(return_type), + code_start_(nullptr), + latest_result_(nullptr) {} HGraph* BuildGraph(const DexFile::CodeItem& code); @@ -129,6 +133,31 @@ class HGraphBuilder : public ValueObject { uint32_t* args, uint32_t register_index); + // Builds a new array node and the instructions that fill it. + void BuildFilledNewArray(uint32_t dex_offset, + uint32_t type_index, + uint32_t number_of_vreg_arguments, + bool is_range, + uint32_t* args, + uint32_t register_index); + + // Fills the given object with data as specified in the fill-array-data + // instruction. Currently only used for non-reference and non-floating point + // arrays. + template <typename T> + void BuildFillArrayData(HInstruction* object, + const T* data, + uint32_t element_count, + Primitive::Type anticipated_type, + uint32_t dex_offset); + + // Fills the given object with data as specified in the fill-array-data + // instruction. The data must be for long and double arrays. + void BuildFillWideArrayData(HInstruction* object, + const uint64_t* data, + uint32_t element_count, + uint32_t dex_offset); + ArenaAllocator* const arena_; // A list of the size of the dex code holding block information for @@ -151,6 +180,14 @@ class HGraphBuilder : public ValueObject { CompilerDriver* const compiler_driver_; const Primitive::Type return_type_; + // The pointer in the dex file where the instructions of the code item + // being currently compiled start. + const uint16_t* code_start_; + + // The last invoke or fill-new-array being built. Only to be + // used by move-result instructions. + HInstruction* latest_result_; + DISALLOW_COPY_AND_ASSIGN(HGraphBuilder); }; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index f07cb30a64..792ff45cf5 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1305,6 +1305,29 @@ void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { DCHECK(!codegen_->IsLeafMethod()); } +void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); + InvokeRuntimeCallingConvention calling_convention; + locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + locations->SetOut(Location::RegisterLocation(R0)); + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); +} + +void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) { + InvokeRuntimeCallingConvention calling_convention; + LoadCurrentMethod(calling_convention.GetRegisterAt(1)); + __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); + + int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocArrayWithAccessCheck).Int32Value(); + __ LoadFromOffset(kLoadWord, LR, TR, offset); + __ blx(LR); + + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); + DCHECK(!codegen_->IsLeafMethod()); +} + void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 2550518db1..acf410367b 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -491,17 +491,23 @@ void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstr Immediate imm(instruction->AsIntConstant()->GetValue()); if (location.IsRegister()) { __ movl(location.As<Register>(), imm); - } else { + } else if (location.IsStackSlot()) { __ movl(Address(ESP, location.GetStackIndex()), imm); + } else { + DCHECK(location.IsConstant()); + DCHECK_EQ(location.GetConstant(), instruction); } } else if (instruction->IsLongConstant()) { int64_t value = instruction->AsLongConstant()->GetValue(); if (location.IsRegister()) { __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value))); __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value))); - } else { + } else if (location.IsDoubleStackSlot()) { __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value))); __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value))); + } else { + DCHECK(location.IsConstant()); + DCHECK_EQ(location.GetConstant(), instruction); } } else if (instruction->IsLoadLocal()) { int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); @@ -1310,6 +1316,28 @@ void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) { DCHECK(!codegen_->IsLeafMethod()); } +void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); + locations->SetOut(Location::RegisterLocation(EAX)); + InvokeRuntimeCallingConvention calling_convention; + locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); +} + +void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) { + InvokeRuntimeCallingConvention calling_convention; + LoadCurrentMethod(calling_convention.GetRegisterAt(1)); + __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex())); + + __ fs()->call( + Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocArrayWithAccessCheck))); + + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); + DCHECK(!codegen_->IsLeafMethod()); +} + void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 6174ac6be0..58dda16d2d 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -407,16 +407,22 @@ void CodeGeneratorX86_64::Move(HInstruction* instruction, Immediate imm(instruction->AsIntConstant()->GetValue()); if (location.IsRegister()) { __ movl(location.As<CpuRegister>(), imm); - } else { + } else if (location.IsStackSlot()) { __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm); + } else { + DCHECK(location.IsConstant()); + DCHECK_EQ(location.GetConstant(), instruction); } } else if (instruction->IsLongConstant()) { int64_t value = instruction->AsLongConstant()->GetValue(); if (location.IsRegister()) { __ movq(location.As<CpuRegister>(), Immediate(value)); - } else { + } else if (location.IsDoubleStackSlot()) { __ movq(CpuRegister(TMP), Immediate(value)); __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP)); + } else { + DCHECK(location.IsConstant()); + DCHECK_EQ(location.GetConstant(), instruction); } } else if (instruction->IsLoadLocal()) { switch (instruction->GetType()) { @@ -1229,6 +1235,28 @@ void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); } +void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); + InvokeRuntimeCallingConvention calling_convention; + locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + locations->SetOut(Location::RegisterLocation(RAX)); + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); +} + +void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) { + InvokeRuntimeCallingConvention calling_convention; + LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1))); + __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex())); + + __ gs()->call(Address::Absolute( + QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocArrayWithAccessCheck), true)); + + DCHECK(!codegen_->IsLeafMethod()); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); +} + void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 7c933aa4f1..9b7ff88b68 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -507,6 +507,7 @@ class HBasicBlock : public ArenaObject { M(Neg, UnaryOperation) \ M(FloatConstant, Constant) \ M(DoubleConstant, Constant) \ + M(NewArray, Instruction) \ #define FOR_EACH_INSTRUCTION(M) \ FOR_EACH_CONCRETE_INSTRUCTION(M) \ @@ -1608,6 +1609,30 @@ class HNeg : public HUnaryOperation { DISALLOW_COPY_AND_ASSIGN(HNeg); }; +class HNewArray : public HExpression<1> { + public: + HNewArray(HInstruction* length, uint32_t dex_pc, uint16_t type_index) + : HExpression(Primitive::kPrimNot, SideEffects::None()), + dex_pc_(dex_pc), + type_index_(type_index) { + SetRawInputAt(0, length); + } + + uint32_t GetDexPc() const { return dex_pc_; } + uint16_t GetTypeIndex() const { return type_index_; } + + // Calls runtime so needs an environment. + virtual bool NeedsEnvironment() const { return true; } + + DECLARE_INSTRUCTION(NewArray); + + private: + const uint32_t dex_pc_; + const uint16_t type_index_; + + DISALLOW_COPY_AND_ASSIGN(HNewArray); +}; + class HAdd : public HBinaryOperation { public: HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right) |