diff options
Diffstat (limited to 'compiler/optimizing')
22 files changed, 509 insertions, 194 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 231017f55e..f57333741c 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -736,6 +736,46 @@ void CodeGenerator::GenerateLoadClassRuntimeCall(HLoadClass* cls) { } } +void CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary( + HLoadMethodHandle* method_handle, + Location runtime_proto_index_location, + Location runtime_return_location) { + DCHECK_EQ(method_handle->InputCount(), 1u); + LocationSummary* locations = + new (method_handle->GetBlock()->GetGraph()->GetAllocator()) LocationSummary( + method_handle, LocationSummary::kCallOnMainOnly); + locations->SetInAt(0, Location::NoLocation()); + locations->AddTemp(runtime_proto_index_location); + locations->SetOut(runtime_return_location); +} + +void CodeGenerator::GenerateLoadMethodHandleRuntimeCall(HLoadMethodHandle* method_handle) { + LocationSummary* locations = method_handle->GetLocations(); + MoveConstant(locations->GetTemp(0), method_handle->GetMethodHandleIndex()); + CheckEntrypointTypes<kQuickResolveMethodHandle, void*, uint32_t>(); + InvokeRuntime(kQuickResolveMethodHandle, method_handle, method_handle->GetDexPc()); +} + +void CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary( + HLoadMethodType* method_type, + Location runtime_proto_index_location, + Location runtime_return_location) { + DCHECK_EQ(method_type->InputCount(), 1u); + LocationSummary* locations = + new (method_type->GetBlock()->GetGraph()->GetAllocator()) LocationSummary( + method_type, LocationSummary::kCallOnMainOnly); + locations->SetInAt(0, Location::NoLocation()); + locations->AddTemp(runtime_proto_index_location); + locations->SetOut(runtime_return_location); +} + +void CodeGenerator::GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type) { + LocationSummary* locations = method_type->GetLocations(); + MoveConstant(locations->GetTemp(0), method_type->GetProtoIndex()); + CheckEntrypointTypes<kQuickResolveMethodType, void*, uint32_t>(); + InvokeRuntime(kQuickResolveMethodType, method_type, method_type->GetDexPc()); +} + static uint32_t GetBootImageOffsetImpl(const void* object, ImageHeader::ImageSections section) { Runtime* runtime = Runtime::Current(); DCHECK(runtime->IsAotCompiler()); diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index f0c4ee01cc..bcb25997f4 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -564,6 +564,16 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { Location runtime_return_location); void GenerateLoadClassRuntimeCall(HLoadClass* cls); + static void CreateLoadMethodHandleRuntimeCallLocationSummary(HLoadMethodHandle* method_handle, + Location runtime_handle_index_location, + Location runtime_return_location); + void GenerateLoadMethodHandleRuntimeCall(HLoadMethodHandle* method_handle); + + static void CreateLoadMethodTypeRuntimeCallLocationSummary(HLoadMethodType* method_type, + Location runtime_type_index_location, + Location runtime_return_location); + void GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type); + uint32_t GetBootImageOffset(HLoadClass* load_class); uint32_t GetBootImageOffset(HLoadString* load_string); uint32_t GetBootImageOffset(HInvokeStaticOrDirect* invoke); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index d4cfab82de..6f173e19f5 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -5144,6 +5144,26 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SA } } +void LocationsBuilderARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) { + InvokeRuntimeCallingConvention calling_convention; + Location location = LocationFrom(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location); +} + +void InstructionCodeGeneratorARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) { + codegen_->GenerateLoadMethodHandleRuntimeCall(load); +} + +void LocationsBuilderARM64::VisitLoadMethodType(HLoadMethodType* load) { + InvokeRuntimeCallingConvention calling_convention; + Location location = LocationFrom(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location); +} + +void InstructionCodeGeneratorARM64::VisitLoadMethodType(HLoadMethodType* load) { + codegen_->GenerateLoadMethodTypeRuntimeCall(load); +} + static MemOperand GetExceptionTlsAddress() { return MemOperand(tr, Thread::ExceptionOffset<kArm64PointerSize>().Int32Value()); } diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 58ce9aa9f0..859e1597c6 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -7527,6 +7527,26 @@ void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) NO_THREAD_ } } +void LocationsBuilderARMVIXL::VisitLoadMethodHandle(HLoadMethodHandle* load) { + InvokeRuntimeCallingConventionARMVIXL calling_convention; + Location location = LocationFrom(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location); +} + +void InstructionCodeGeneratorARMVIXL::VisitLoadMethodHandle(HLoadMethodHandle* load) { + codegen_->GenerateLoadMethodHandleRuntimeCall(load); +} + +void LocationsBuilderARMVIXL::VisitLoadMethodType(HLoadMethodType* load) { + InvokeRuntimeCallingConventionARMVIXL calling_convention; + Location location = LocationFrom(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location); +} + +void InstructionCodeGeneratorARMVIXL::VisitLoadMethodType(HLoadMethodType* load) { + codegen_->GenerateLoadMethodTypeRuntimeCall(load); +} + void LocationsBuilderARMVIXL::VisitClinitCheck(HClinitCheck* check) { LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath); diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 25e2eddbfa..7f3441fdf4 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -8226,6 +8226,26 @@ void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAF } } +void LocationsBuilderMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) { + InvokeRuntimeCallingConvention calling_convention; + Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, loc, loc); +} + +void InstructionCodeGeneratorMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) { + codegen_->GenerateLoadMethodHandleRuntimeCall(load); +} + +void LocationsBuilderMIPS::VisitLoadMethodType(HLoadMethodType* load) { + InvokeRuntimeCallingConvention calling_convention; + Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, loc, loc); +} + +void InstructionCodeGeneratorMIPS::VisitLoadMethodType(HLoadMethodType* load) { + codegen_->GenerateLoadMethodTypeRuntimeCall(load); +} + static int32_t GetExceptionTlsOffset() { return Thread::ExceptionOffset<kMipsPointerSize>().Int32Value(); } diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 5b07b55cbb..ee32b96daf 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -6262,6 +6262,26 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_S } } +void LocationsBuilderMIPS64::VisitLoadMethodHandle(HLoadMethodHandle* load) { + InvokeRuntimeCallingConvention calling_convention; + Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, loc, loc); +} + +void InstructionCodeGeneratorMIPS64::VisitLoadMethodHandle(HLoadMethodHandle* load) { + codegen_->GenerateLoadMethodHandleRuntimeCall(load); +} + +void LocationsBuilderMIPS64::VisitLoadMethodType(HLoadMethodType* load) { + InvokeRuntimeCallingConvention calling_convention; + Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, loc, loc); +} + +void InstructionCodeGeneratorMIPS64::VisitLoadMethodType(HLoadMethodType* load) { + codegen_->GenerateLoadMethodTypeRuntimeCall(load); +} + static int32_t GetExceptionTlsOffset() { return Thread::ExceptionOffset<kMips64PointerSize>().Int32Value(); } diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 82d1fda878..9e315381b1 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -6539,6 +6539,26 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFE } } +void LocationsBuilderX86::VisitLoadMethodHandle(HLoadMethodHandle* load) { + InvokeRuntimeCallingConvention calling_convention; + Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location); +} + +void InstructionCodeGeneratorX86::VisitLoadMethodHandle(HLoadMethodHandle* load) { + codegen_->GenerateLoadMethodHandleRuntimeCall(load); +} + +void LocationsBuilderX86::VisitLoadMethodType(HLoadMethodType* load) { + InvokeRuntimeCallingConvention calling_convention; + Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0)); + CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location); +} + +void InstructionCodeGeneratorX86::VisitLoadMethodType(HLoadMethodType* load) { + codegen_->GenerateLoadMethodTypeRuntimeCall(load); +} + void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) { LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 322b0cfc4c..f7397046d7 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -5908,6 +5908,26 @@ void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) { } } +void LocationsBuilderX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) { + // Custom calling convention: RAX serves as both input and output. + Location location = Location::RegisterLocation(RAX); + CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location); +} + +void InstructionCodeGeneratorX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) { + codegen_->GenerateLoadMethodHandleRuntimeCall(load); +} + +void LocationsBuilderX86_64::VisitLoadMethodType(HLoadMethodType* load) { + // Custom calling convention: RAX serves as both input and output. + Location location = Location::RegisterLocation(RAX); + CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location); +} + +void InstructionCodeGeneratorX86_64::VisitLoadMethodType(HLoadMethodType* load) { + codegen_->GenerateLoadMethodTypeRuntimeCall(load); +} + void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) { // We assume the class to not be null. SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86_64( diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 54d4644580..d65ad40565 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -386,6 +386,18 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { << load_class->NeedsAccessCheck() << std::noboolalpha; } + void VisitLoadMethodHandle(HLoadMethodHandle* load_method_handle) OVERRIDE { + StartAttributeStream("load_kind") << "RuntimeCall"; + StartAttributeStream("method_handle_index") << load_method_handle->GetMethodHandleIndex(); + } + + void VisitLoadMethodType(HLoadMethodType* load_method_type) OVERRIDE { + StartAttributeStream("load_kind") << "RuntimeCall"; + const DexFile& dex_file = load_method_type->GetDexFile(); + const DexFile::ProtoId& proto_id = dex_file.GetProtoId(load_method_type->GetProtoIndex()); + StartAttributeStream("method_type") << dex_file.GetProtoSignature(proto_id); + } + void VisitLoadString(HLoadString* load_string) OVERRIDE { StartAttributeStream("load_kind") << load_string->GetLoadKind(); } diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 9647dd5d41..35a39456a2 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -1896,6 +1896,20 @@ bool HInstructionBuilder::LoadClassNeedsAccessCheck(Handle<mirror::Class> klass) } } +void HInstructionBuilder::BuildLoadMethodHandle(uint16_t proto_idx, uint32_t dex_pc) { + const DexFile& dex_file = *dex_compilation_unit_->GetDexFile(); + HLoadMethodHandle* load_method_handle = + new (allocator_) HLoadMethodHandle(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc); + AppendInstruction(load_method_handle); +} + +void HInstructionBuilder::BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc) { + const DexFile& dex_file = *dex_compilation_unit_->GetDexFile(); + HLoadMethodType* load_method_type = + new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc); + AppendInstruction(load_method_type); +} + void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction, uint8_t destination, uint8_t reference, @@ -2927,6 +2941,20 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, break; } + case Instruction::CONST_METHOD_HANDLE: { + uint16_t method_handle_idx = instruction.VRegB_21c(); + BuildLoadMethodHandle(method_handle_idx, dex_pc); + UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction()); + break; + } + + case Instruction::CONST_METHOD_TYPE: { + uint16_t proto_idx = instruction.VRegB_21c(); + BuildLoadMethodType(proto_idx, dex_pc); + UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction()); + break; + } + case Instruction::MOVE_EXCEPTION: { AppendInstruction(new (allocator_) HLoadException(dex_pc)); UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction()); diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index f78829232d..95ffa6b054 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -45,6 +45,7 @@ class VariableSizedHandleScope; namespace mirror { class Class; +class MethodType; } // namespace mirror class HInstructionBuilder : public ValueObject { @@ -239,6 +240,12 @@ class HInstructionBuilder : public ValueObject { bool LoadClassNeedsAccessCheck(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); + // Builds a `HLoadMethodHandle` loading the given `method_handle_idx`. + void BuildLoadMethodHandle(uint16_t method_handle_idx, uint32_t dex_pc); + + // Builds a `HLoadMethodType` loading the given `proto_idx`. + void BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc); + // Returns the outer-most compiling method's class. ObjPtr<mirror::Class> GetOutermostCompilingClass() const; diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 0fe16725f3..ca84d421a7 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -2666,10 +2666,10 @@ bool InstructionSimplifierVisitor::TryHandleAssociativeAndCommutativeOperation( HConstant* const2; HBinaryOperation* y; - if (instruction->InstructionTypeEquals(left) && right->IsConstant()) { + if (instruction->GetKind() == left->GetKind() && right->IsConstant()) { const2 = right->AsConstant(); y = left->AsBinaryOperation(); - } else if (left->IsConstant() && instruction->InstructionTypeEquals(right)) { + } else if (left->IsConstant() && instruction->GetKind() == right->GetKind()) { const2 = left->AsConstant(); y = right->AsBinaryOperation(); } else { diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index f784f8f7f3..5f2833e9a6 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -1680,10 +1680,9 @@ bool HCondition::IsBeforeWhenDisregardMoves(HInstruction* instruction) const { } bool HInstruction::Equals(const HInstruction* other) const { - if (!InstructionTypeEquals(other)) return false; - DCHECK_EQ(GetKind(), other->GetKind()); - if (!InstructionDataEquals(other)) return false; + if (GetKind() != other->GetKind()) return false; if (GetType() != other->GetType()) return false; + if (!InstructionDataEquals(other)) return false; HConstInputsRef inputs = GetInputs(); HConstInputsRef other_inputs = other->GetInputs(); if (inputs.size() != other_inputs.size()) return false; @@ -1698,7 +1697,7 @@ bool HInstruction::Equals(const HInstruction* other) const { std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs) { #define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break; switch (rhs) { - FOR_EACH_INSTRUCTION(DECLARE_CASE) + FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_CASE) default: os << "Unknown instruction kind " << static_cast<int>(rhs); break; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 79d733060b..a7c2d0b125 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -41,6 +41,7 @@ #include "intrinsics_enum.h" #include "locations.h" #include "mirror/class.h" +#include "mirror/method_type.h" #include "offsets.h" #include "utils/intrusive_forward_list.h" @@ -1382,6 +1383,8 @@ class HLoopInformationOutwardIterator : public ValueObject { M(LessThanOrEqual, Condition) \ M(LoadClass, Instruction) \ M(LoadException, Instruction) \ + M(LoadMethodHandle, Instruction) \ + M(LoadMethodType, Instruction) \ M(LoadString, Instruction) \ M(LongConstant, Constant) \ M(Max, Instruction) \ @@ -1525,9 +1528,6 @@ FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) H##type& operator=(const H##type&) = delete; \ public: \ const char* DebugName() const OVERRIDE { return #type; } \ - bool InstructionTypeEquals(const HInstruction* other) const OVERRIDE { \ - return other->Is##type(); \ - } \ HInstruction* Clone(ArenaAllocator* arena) const OVERRIDE { \ DCHECK(IsClonable()); \ return new (arena) H##type(*this->As##type()); \ @@ -1537,10 +1537,7 @@ FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) #define DECLARE_ABSTRACT_INSTRUCTION(type) \ private: \ H##type& operator=(const H##type&) = delete; \ - public: \ - bool Is##type() const { return As##type() != nullptr; } \ - const H##type* As##type() const { return this; } \ - H##type* As##type() { return this; } + public: #define DEFAULT_COPY_CONSTRUCTOR(type) \ explicit H##type(const H##type& other) = default; @@ -1959,12 +1956,15 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { public: #define DECLARE_KIND(type, super) k##type, enum InstructionKind { - FOR_EACH_INSTRUCTION(DECLARE_KIND) + FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_KIND) kLastInstructionKind }; #undef DECLARE_KIND HInstruction(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc) + : HInstruction(kind, DataType::Type::kVoid, side_effects, dex_pc) {} + + HInstruction(InstructionKind kind, DataType::Type type, SideEffects side_effects, uint32_t dex_pc) : previous_(nullptr), next_(nullptr), block_(nullptr), @@ -1979,6 +1979,7 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { side_effects_(side_effects), reference_type_handle_(ReferenceTypeInfo::CreateInvalid().GetTypeHandle()) { SetPackedField<InstructionKindField>(kind); + SetPackedField<TypeField>(type); SetPackedFlag<kFlagReferenceTypeIsExact>(ReferenceTypeInfo::CreateInvalid().IsExact()); } @@ -2036,7 +2037,9 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { virtual void Accept(HGraphVisitor* visitor) = 0; virtual const char* DebugName() const = 0; - virtual DataType::Type GetType() const { return DataType::Type::kVoid; } + DataType::Type GetType() const { + return TypeField::Decode(GetPackedFields()); + } virtual bool NeedsEnvironment() const { return false; } @@ -2228,19 +2231,17 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { void MoveBeforeFirstUserAndOutOfLoops(); #define INSTRUCTION_TYPE_CHECK(type, super) \ - bool Is##type() const; \ - const H##type* As##type() const; \ - H##type* As##type(); + bool Is##type() const; - FOR_EACH_CONCRETE_INSTRUCTION(INSTRUCTION_TYPE_CHECK) + FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK) #undef INSTRUCTION_TYPE_CHECK -#define INSTRUCTION_TYPE_CHECK(type, super) \ - bool Is##type() const { return (As##type() != nullptr); } \ - virtual const H##type* As##type() const { return nullptr; } \ - virtual H##type* As##type() { return nullptr; } - FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK) -#undef INSTRUCTION_TYPE_CHECK +#define INSTRUCTION_TYPE_CAST(type, super) \ + const H##type* As##type() const; \ + H##type* As##type(); + + FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CAST) +#undef INSTRUCTION_TYPE_CAST // Return a clone of the instruction if it is clonable (shallow copy by default, custom copy // if a custom copy-constructor is provided for a particular type). If IsClonable() is false for @@ -2266,11 +2267,6 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { // meanings? split and rename? virtual bool CanBeMoved() const { return false; } - // Returns whether the two instructions are of the same kind. - virtual bool InstructionTypeEquals(const HInstruction* other ATTRIBUTE_UNUSED) const { - return false; - } - // Returns whether any data encoded in the two instructions is equal. // This method does not look at the inputs. Both instructions must be // of the same type, otherwise the method has undefined behavior. @@ -2342,13 +2338,18 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { static constexpr size_t kFieldInstructionKind = kFlagReferenceTypeIsExact + 1; static constexpr size_t kFieldInstructionKindSize = MinimumBitsToStore(static_cast<size_t>(InstructionKind::kLastInstructionKind - 1)); - static constexpr size_t kNumberOfGenericPackedBits = + static constexpr size_t kFieldType = kFieldInstructionKind + kFieldInstructionKindSize; + static constexpr size_t kFieldTypeSize = + MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast)); + static constexpr size_t kNumberOfGenericPackedBits = kFieldType + kFieldTypeSize; static constexpr size_t kMaxNumberOfPackedBits = sizeof(uint32_t) * kBitsPerByte; static_assert(kNumberOfGenericPackedBits <= kMaxNumberOfPackedBits, "Too many generic packed fields"); + using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>; + const HUserRecord<HInstruction*> InputRecordAt(size_t i) const { return GetInputRecords()[i]; } @@ -2595,6 +2596,15 @@ class HVariableInputSizeInstruction : public HInstruction { ArenaAllocKind kind) : HInstruction(inst_kind, side_effects, dex_pc), inputs_(number_of_inputs, allocator->Adapter(kind)) {} + HVariableInputSizeInstruction(InstructionKind inst_kind, + DataType::Type type, + SideEffects side_effects, + uint32_t dex_pc, + ArenaAllocator* allocator, + size_t number_of_inputs, + ArenaAllocKind kind) + : HInstruction(inst_kind, type, side_effects, dex_pc), + inputs_(number_of_inputs, allocator->Adapter(kind)) {} DEFAULT_COPY_CONSTRUCTOR(VariableInputSizeInstruction); @@ -2602,11 +2612,16 @@ class HVariableInputSizeInstruction : public HInstruction { }; template<size_t N> -class HTemplateInstruction: public HInstruction { +class HExpression : public HInstruction { public: - HTemplateInstruction<N>(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc) + HExpression<N>(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc) : HInstruction(kind, side_effects, dex_pc), inputs_() {} - virtual ~HTemplateInstruction() {} + HExpression<N>(InstructionKind kind, + DataType::Type type, + SideEffects side_effects, + uint32_t dex_pc) + : HInstruction(kind, type, side_effects, dex_pc), inputs_() {} + virtual ~HExpression() {} using HInstruction::GetInputRecords; // Keep the const version visible. ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL { @@ -2614,7 +2629,7 @@ class HTemplateInstruction: public HInstruction { } protected: - DEFAULT_COPY_CONSTRUCTOR(TemplateInstruction<N>); + DEFAULT_COPY_CONSTRUCTOR(Expression<N>); private: std::array<HUserRecord<HInstruction*>, N> inputs_; @@ -2622,14 +2637,13 @@ class HTemplateInstruction: public HInstruction { friend class SsaBuilder; }; -// HTemplateInstruction specialization for N=0. +// HExpression specialization for N=0. template<> -class HTemplateInstruction<0>: public HInstruction { +class HExpression<0> : public HInstruction { public: - explicit HTemplateInstruction<0>(InstructionKind kind, SideEffects side_effects, uint32_t dex_pc) - : HInstruction(kind, side_effects, dex_pc) {} + using HInstruction::HInstruction; - virtual ~HTemplateInstruction() {} + virtual ~HExpression() {} using HInstruction::GetInputRecords; // Keep the const version visible. ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL { @@ -2637,46 +2651,18 @@ class HTemplateInstruction<0>: public HInstruction { } protected: - DEFAULT_COPY_CONSTRUCTOR(TemplateInstruction<0>); + DEFAULT_COPY_CONSTRUCTOR(Expression<0>); private: friend class SsaBuilder; }; -template<intptr_t N> -class HExpression : public HTemplateInstruction<N> { - public: - using HInstruction::InstructionKind; - HExpression<N>(InstructionKind kind, - DataType::Type type, - SideEffects side_effects, - uint32_t dex_pc) - : HTemplateInstruction<N>(kind, side_effects, dex_pc) { - this->template SetPackedField<TypeField>(type); - } - virtual ~HExpression() {} - - DataType::Type GetType() const OVERRIDE { - return TypeField::Decode(this->GetPackedFields()); - } - - protected: - static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits; - static constexpr size_t kFieldTypeSize = - MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast)); - static constexpr size_t kNumberOfExpressionPackedBits = kFieldType + kFieldTypeSize; - static_assert(kNumberOfExpressionPackedBits <= HInstruction::kMaxNumberOfPackedBits, - "Too many packed fields."); - using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>; - DEFAULT_COPY_CONSTRUCTOR(Expression<N>); -}; - // Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow // instruction that branches to the exit block. -class HReturnVoid FINAL : public HTemplateInstruction<0> { +class HReturnVoid FINAL : public HExpression<0> { public: explicit HReturnVoid(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kReturnVoid, SideEffects::None(), dex_pc) { + : HExpression(kReturnVoid, SideEffects::None(), dex_pc) { } bool IsControlFlow() const OVERRIDE { return true; } @@ -2689,10 +2675,10 @@ class HReturnVoid FINAL : public HTemplateInstruction<0> { // Represents dex's RETURN opcodes. A HReturn is a control flow // instruction that branches to the exit block. -class HReturn FINAL : public HTemplateInstruction<1> { +class HReturn FINAL : public HExpression<1> { public: explicit HReturn(HInstruction* value, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kReturn, SideEffects::None(), dex_pc) { + : HExpression(kReturn, SideEffects::None(), dex_pc) { SetRawInputAt(0, value); } @@ -2713,13 +2699,13 @@ class HPhi FINAL : public HVariableInputSizeInstruction { uint32_t dex_pc = kNoDexPc) : HVariableInputSizeInstruction( kPhi, + ToPhiType(type), SideEffects::None(), dex_pc, allocator, number_of_inputs, kArenaAllocPhiInputs), reg_number_(reg_number) { - SetPackedField<TypeField>(ToPhiType(type)); DCHECK_NE(GetType(), DataType::Type::kVoid); // Phis are constructed live and marked dead if conflicting or unused. // Individual steps of SsaBuilder should assume that if a phi has been @@ -2737,7 +2723,6 @@ class HPhi FINAL : public HVariableInputSizeInstruction { bool IsCatchPhi() const { return GetBlock()->IsCatchBlock(); } - DataType::Type GetType() const OVERRIDE { return GetPackedField<TypeField>(); } void SetType(DataType::Type new_type) { // Make sure that only valid type changes occur. The following are allowed: // (1) int -> float/ref (primitive type propagation), @@ -2796,14 +2781,10 @@ class HPhi FINAL : public HVariableInputSizeInstruction { DEFAULT_COPY_CONSTRUCTOR(Phi); private: - static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits; - static constexpr size_t kFieldTypeSize = - MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast)); - static constexpr size_t kFlagIsLive = kFieldType + kFieldTypeSize; + static constexpr size_t kFlagIsLive = HInstruction::kNumberOfGenericPackedBits; static constexpr size_t kFlagCanBeNull = kFlagIsLive + 1; static constexpr size_t kNumberOfPhiPackedBits = kFlagCanBeNull + 1; static_assert(kNumberOfPhiPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); - using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>; const uint32_t reg_number_; }; @@ -2811,10 +2792,10 @@ class HPhi FINAL : public HVariableInputSizeInstruction { // The exit instruction is the only instruction of the exit block. // Instructions aborting the method (HThrow and HReturn) must branch to the // exit block. -class HExit FINAL : public HTemplateInstruction<0> { +class HExit FINAL : public HExpression<0> { public: explicit HExit(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kExit, SideEffects::None(), dex_pc) { + : HExpression(kExit, SideEffects::None(), dex_pc) { } bool IsControlFlow() const OVERRIDE { return true; } @@ -2826,10 +2807,10 @@ class HExit FINAL : public HTemplateInstruction<0> { }; // Jumps from one block to another. -class HGoto FINAL : public HTemplateInstruction<0> { +class HGoto FINAL : public HExpression<0> { public: explicit HGoto(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kGoto, SideEffects::None(), dex_pc) { + : HExpression(kGoto, SideEffects::None(), dex_pc) { } bool IsClonable() const OVERRIDE { return true; } @@ -3096,10 +3077,10 @@ class HDoubleConstant FINAL : public HConstant { // Conditional branch. A block ending with an HIf instruction must have // two successors. -class HIf FINAL : public HTemplateInstruction<1> { +class HIf FINAL : public HExpression<1> { public: explicit HIf(HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kIf, SideEffects::None(), dex_pc) { + : HExpression(kIf, SideEffects::None(), dex_pc) { SetRawInputAt(0, input); } @@ -3126,7 +3107,7 @@ class HIf FINAL : public HTemplateInstruction<1> { // non-exceptional control flow. // Normal-flow successor is stored at index zero, exception handlers under // higher indices in no particular order. -class HTryBoundary FINAL : public HTemplateInstruction<0> { +class HTryBoundary FINAL : public HExpression<0> { public: enum class BoundaryKind { kEntry, @@ -3135,7 +3116,7 @@ class HTryBoundary FINAL : public HTemplateInstruction<0> { }; explicit HTryBoundary(BoundaryKind kind, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kTryBoundary, SideEffects::None(), dex_pc) { + : HExpression(kTryBoundary, SideEffects::None(), dex_pc) { SetPackedField<BoundaryKindField>(kind); } @@ -3219,6 +3200,7 @@ class HDeoptimize FINAL : public HVariableInputSizeInstruction { uint32_t dex_pc) : HVariableInputSizeInstruction( kDeoptimize, + guard->GetType(), SideEffects::CanTriggerGC(), dex_pc, allocator, @@ -3242,10 +3224,6 @@ class HDeoptimize FINAL : public HVariableInputSizeInstruction { DeoptimizationKind GetDeoptimizationKind() const { return GetPackedField<DeoptimizeKindField>(); } - DataType::Type GetType() const OVERRIDE { - return GuardsAnInput() ? GuardedInput()->GetType() : DataType::Type::kVoid; - } - bool GuardsAnInput() const { return InputCount() == 2; } @@ -3288,6 +3266,7 @@ class HShouldDeoptimizeFlag FINAL : public HVariableInputSizeInstruction { // with regard to other passes. HShouldDeoptimizeFlag(ArenaAllocator* allocator, uint32_t dex_pc) : HVariableInputSizeInstruction(kShouldDeoptimizeFlag, + DataType::Type::kInt32, SideEffects::None(), dex_pc, allocator, @@ -3295,8 +3274,6 @@ class HShouldDeoptimizeFlag FINAL : public HVariableInputSizeInstruction { kArenaAllocCHA) { } - DataType::Type GetType() const OVERRIDE { return DataType::Type::kInt32; } - // We do all CHA guard elimination/motion in a single pass, after which there is no // further guard elimination/motion since a guard might have been used for justification // of the elimination of another guard. Therefore, we pretend this guard cannot be moved @@ -3360,7 +3337,7 @@ class HClassTableGet FINAL : public HExpression<1> { DEFAULT_COPY_CONSTRUCTOR(ClassTableGet); private: - static constexpr size_t kFieldTableKind = kNumberOfExpressionPackedBits; + static constexpr size_t kFieldTableKind = kNumberOfGenericPackedBits; static constexpr size_t kFieldTableKindSize = MinimumBitsToStore(static_cast<size_t>(TableKind::kLast)); static constexpr size_t kNumberOfClassTableGetPackedBits = kFieldTableKind + kFieldTableKindSize; @@ -3375,13 +3352,13 @@ class HClassTableGet FINAL : public HExpression<1> { // PackedSwitch (jump table). A block ending with a PackedSwitch instruction will // have one successor for each entry in the switch table, and the final successor // will be the block containing the next Dex opcode. -class HPackedSwitch FINAL : public HTemplateInstruction<1> { +class HPackedSwitch FINAL : public HExpression<1> { public: HPackedSwitch(int32_t start_value, uint32_t num_entries, HInstruction* input, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kPackedSwitch, SideEffects::None(), dex_pc), + : HExpression(kPackedSwitch, SideEffects::None(), dex_pc), start_value_(start_value), num_entries_(num_entries) { SetRawInputAt(0, input); @@ -3611,7 +3588,7 @@ class HCondition : public HBinaryOperation { protected: // Needed if we merge a HCompare into a HCondition. - static constexpr size_t kFieldComparisonBias = kNumberOfExpressionPackedBits; + static constexpr size_t kFieldComparisonBias = kNumberOfGenericPackedBits; static constexpr size_t kFieldComparisonBiasSize = MinimumBitsToStore(static_cast<size_t>(ComparisonBias::kLast)); static constexpr size_t kNumberOfConditionPackedBits = @@ -4131,7 +4108,7 @@ class HCompare FINAL : public HBinaryOperation { DECLARE_INSTRUCTION(Compare); protected: - static constexpr size_t kFieldComparisonBias = kNumberOfExpressionPackedBits; + static constexpr size_t kFieldComparisonBias = kNumberOfGenericPackedBits; static constexpr size_t kFieldComparisonBiasSize = MinimumBitsToStore(static_cast<size_t>(ComparisonBias::kLast)); static constexpr size_t kNumberOfComparePackedBits = @@ -4210,7 +4187,7 @@ class HNewInstance FINAL : public HExpression<1> { DEFAULT_COPY_CONSTRUCTOR(NewInstance); private: - static constexpr size_t kFlagFinalizable = kNumberOfExpressionPackedBits; + static constexpr size_t kFlagFinalizable = kNumberOfGenericPackedBits; static constexpr size_t kNumberOfNewInstancePackedBits = kFlagFinalizable + 1; static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); @@ -4251,8 +4228,6 @@ class HInvoke : public HVariableInputSizeInstruction { // inputs at the end of their list of inputs. uint32_t GetNumberOfArguments() const { return number_of_arguments_; } - DataType::Type GetType() const OVERRIDE { return GetPackedField<ReturnTypeField>(); } - uint32_t GetDexMethodIndex() const { return dex_method_index_; } InvokeType GetInvokeType() const { @@ -4305,16 +4280,11 @@ class HInvoke : public HVariableInputSizeInstruction { static constexpr size_t kFieldInvokeType = kNumberOfGenericPackedBits; static constexpr size_t kFieldInvokeTypeSize = MinimumBitsToStore(static_cast<size_t>(kMaxInvokeType)); - static constexpr size_t kFieldReturnType = - kFieldInvokeType + kFieldInvokeTypeSize; - static constexpr size_t kFieldReturnTypeSize = - MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast)); - static constexpr size_t kFlagCanThrow = kFieldReturnType + kFieldReturnTypeSize; + static constexpr size_t kFlagCanThrow = kFieldInvokeType + kFieldInvokeTypeSize; static constexpr size_t kFlagAlwaysThrows = kFlagCanThrow + 1; static constexpr size_t kNumberOfInvokePackedBits = kFlagAlwaysThrows + 1; static_assert(kNumberOfInvokePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); using InvokeTypeField = BitField<InvokeType, kFieldInvokeType, kFieldInvokeTypeSize>; - using ReturnTypeField = BitField<DataType::Type, kFieldReturnType, kFieldReturnTypeSize>; HInvoke(InstructionKind kind, ArenaAllocator* allocator, @@ -4327,6 +4297,7 @@ class HInvoke : public HVariableInputSizeInstruction { InvokeType invoke_type) : HVariableInputSizeInstruction( kind, + return_type, SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays. dex_pc, allocator, @@ -4337,7 +4308,6 @@ class HInvoke : public HVariableInputSizeInstruction { dex_method_index_(dex_method_index), intrinsic_(Intrinsics::kNone), intrinsic_optimizations_(0) { - SetPackedField<ReturnTypeField>(return_type); SetPackedField<InvokeTypeField>(invoke_type); SetPackedFlag<kFlagCanThrow>(true); } @@ -4550,7 +4520,7 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { } bool CanBeNull() const OVERRIDE { - return GetPackedField<ReturnTypeField>() == DataType::Type::kReference && !IsStringInit(); + return GetType() == DataType::Type::kReference && !IsStringInit(); } // Get the index of the special input, if any. @@ -5146,8 +5116,6 @@ class HDivZeroCheck FINAL : public HExpression<1> { SetRawInputAt(0, value); } - DataType::Type GetType() const OVERRIDE { return InputAt(0)->GetType(); } - bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { @@ -5500,7 +5468,7 @@ class HParameterValue FINAL : public HExpression<0> { private: // Whether or not the parameter value corresponds to 'this' argument. - static constexpr size_t kFlagIsThis = kNumberOfExpressionPackedBits; + static constexpr size_t kFlagIsThis = kNumberOfGenericPackedBits; static constexpr size_t kFlagCanBeNull = kFlagIsThis + 1; static constexpr size_t kNumberOfParameterValuePackedBits = kFlagCanBeNull + 1; static_assert(kNumberOfParameterValuePackedBits <= kMaxNumberOfPackedBits, @@ -5742,7 +5710,7 @@ class HInstanceFieldGet FINAL : public HExpression<1> { const FieldInfo field_info_; }; -class HInstanceFieldSet FINAL : public HTemplateInstruction<2> { +class HInstanceFieldSet FINAL : public HExpression<2> { public: HInstanceFieldSet(HInstruction* object, HInstruction* value, @@ -5754,9 +5722,9 @@ class HInstanceFieldSet FINAL : public HTemplateInstruction<2> { uint16_t declaring_class_def_index, const DexFile& dex_file, uint32_t dex_pc) - : HTemplateInstruction(kInstanceFieldSet, - SideEffects::FieldWriteOfType(field_type, is_volatile), - dex_pc), + : HExpression(kInstanceFieldSet, + SideEffects::FieldWriteOfType(field_type, is_volatile), + dex_pc), field_info_(field, field_offset, field_type, @@ -5882,13 +5850,13 @@ class HArrayGet FINAL : public HExpression<2> { // a particular HArrayGet is actually a String.charAt() by looking at the type // of the input but that requires holding the mutator lock, so we prefer to use // a flag, so that code generators don't need to do the locking. - static constexpr size_t kFlagIsStringCharAt = kNumberOfExpressionPackedBits; + static constexpr size_t kFlagIsStringCharAt = kNumberOfGenericPackedBits; static constexpr size_t kNumberOfArrayGetPackedBits = kFlagIsStringCharAt + 1; static_assert(kNumberOfArrayGetPackedBits <= HInstruction::kMaxNumberOfPackedBits, "Too many packed fields."); }; -class HArraySet FINAL : public HTemplateInstruction<3> { +class HArraySet FINAL : public HExpression<3> { public: HArraySet(HInstruction* array, HInstruction* index, @@ -5910,7 +5878,7 @@ class HArraySet FINAL : public HTemplateInstruction<3> { DataType::Type expected_component_type, SideEffects side_effects, uint32_t dex_pc) - : HTemplateInstruction(kArraySet, side_effects, dex_pc) { + : HExpression(kArraySet, side_effects, dex_pc) { SetPackedField<ExpectedComponentTypeField>(expected_component_type); SetPackedFlag<kFlagNeedsTypeCheck>(value->GetType() == DataType::Type::kReference); SetPackedFlag<kFlagValueCanBeNull>(true); @@ -6039,7 +6007,7 @@ class HArrayLength FINAL : public HExpression<1> { // determine whether a particular HArrayLength is actually a String.length() by // looking at the type of the input but that requires holding the mutator lock, so // we prefer to use a flag, so that code generators don't need to do the locking. - static constexpr size_t kFlagIsStringLength = kNumberOfExpressionPackedBits; + static constexpr size_t kFlagIsStringLength = kNumberOfGenericPackedBits; static constexpr size_t kNumberOfArrayLengthPackedBits = kFlagIsStringLength + 1; static_assert(kNumberOfArrayLengthPackedBits <= HInstruction::kMaxNumberOfPackedBits, "Too many packed fields."); @@ -6080,13 +6048,13 @@ class HBoundsCheck FINAL : public HExpression<2> { DEFAULT_COPY_CONSTRUCTOR(BoundsCheck); private: - static constexpr size_t kFlagIsStringCharAt = kNumberOfExpressionPackedBits; + static constexpr size_t kFlagIsStringCharAt = kNumberOfGenericPackedBits; }; -class HSuspendCheck FINAL : public HTemplateInstruction<0> { +class HSuspendCheck FINAL : public HExpression<0> { public: explicit HSuspendCheck(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kSuspendCheck, SideEffects::CanTriggerGC(), dex_pc), + : HExpression(kSuspendCheck, SideEffects::CanTriggerGC(), dex_pc), slow_path_(nullptr) { } @@ -6112,10 +6080,10 @@ class HSuspendCheck FINAL : public HTemplateInstruction<0> { // Pseudo-instruction which provides the native debugger with mapping information. // It ensures that we can generate line number and local variables at this point. -class HNativeDebugInfo : public HTemplateInstruction<0> { +class HNativeDebugInfo : public HExpression<0> { public: explicit HNativeDebugInfo(uint32_t dex_pc) - : HTemplateInstruction<0>(kNativeDebugInfo, SideEffects::None(), dex_pc) { + : HExpression<0>(kNativeDebugInfo, SideEffects::None(), dex_pc) { } bool NeedsEnvironment() const OVERRIDE { @@ -6174,7 +6142,10 @@ class HLoadClass FINAL : public HInstruction { bool is_referrers_class, uint32_t dex_pc, bool needs_access_check) - : HInstruction(kLoadClass, SideEffectsForArchRuntimeCalls(), dex_pc), + : HInstruction(kLoadClass, + DataType::Type::kReference, + SideEffectsForArchRuntimeCalls(), + dex_pc), special_input_(HUserRecord<HInstruction*>(current_method)), type_index_(type_index), dex_file_(dex_file), @@ -6285,10 +6256,6 @@ class HLoadClass FINAL : public HInstruction { &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u); } - DataType::Type GetType() const OVERRIDE { - return DataType::Type::kReference; - } - Handle<mirror::Class> GetClass() const { return klass_; } @@ -6399,7 +6366,10 @@ class HLoadString FINAL : public HInstruction { dex::StringIndex string_index, const DexFile& dex_file, uint32_t dex_pc) - : HInstruction(kLoadString, SideEffectsForArchRuntimeCalls(), dex_pc), + : HInstruction(kLoadString, + DataType::Type::kReference, + SideEffectsForArchRuntimeCalls(), + dex_pc), special_input_(HUserRecord<HInstruction*>(current_method)), string_index_(string_index), dex_file_(dex_file) { @@ -6474,10 +6444,6 @@ class HLoadString FINAL : public HInstruction { &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u); } - DataType::Type GetType() const OVERRIDE { - return DataType::Type::kReference; - } - DECLARE_INSTRUCTION(LoadString); protected: @@ -6535,6 +6501,94 @@ inline void HLoadString::AddSpecialInput(HInstruction* special_input) { special_input->AddUseAt(this, 0); } +class HLoadMethodHandle FINAL : public HInstruction { + public: + HLoadMethodHandle(HCurrentMethod* current_method, + uint16_t method_handle_idx, + const DexFile& dex_file, + uint32_t dex_pc) + : HInstruction(kLoadMethodHandle, + DataType::Type::kReference, + SideEffectsForArchRuntimeCalls(), + dex_pc), + special_input_(HUserRecord<HInstruction*>(current_method)), + method_handle_idx_(method_handle_idx), + dex_file_(dex_file) { + } + + using HInstruction::GetInputRecords; // Keep the const version visible. + ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL { + return ArrayRef<HUserRecord<HInstruction*>>( + &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u); + } + + bool IsClonable() const OVERRIDE { return true; } + + uint16_t GetMethodHandleIndex() const { return method_handle_idx_; } + + const DexFile& GetDexFile() const { return dex_file_; } + + static SideEffects SideEffectsForArchRuntimeCalls() { + return SideEffects::CanTriggerGC(); + } + + DECLARE_INSTRUCTION(LoadMethodHandle); + + protected: + DEFAULT_COPY_CONSTRUCTOR(LoadMethodHandle); + + private: + // The special input is the HCurrentMethod for kRuntimeCall. + HUserRecord<HInstruction*> special_input_; + + const uint16_t method_handle_idx_; + const DexFile& dex_file_; +}; + +class HLoadMethodType FINAL : public HInstruction { + public: + HLoadMethodType(HCurrentMethod* current_method, + uint16_t proto_idx, + const DexFile& dex_file, + uint32_t dex_pc) + : HInstruction(kLoadMethodType, + DataType::Type::kReference, + SideEffectsForArchRuntimeCalls(), + dex_pc), + special_input_(HUserRecord<HInstruction*>(current_method)), + proto_idx_(proto_idx), + dex_file_(dex_file) { + } + + using HInstruction::GetInputRecords; // Keep the const version visible. + ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL { + return ArrayRef<HUserRecord<HInstruction*>>( + &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u); + } + + bool IsClonable() const OVERRIDE { return true; } + + uint16_t GetProtoIndex() const { return proto_idx_; } + + const DexFile& GetDexFile() const { return dex_file_; } + + static SideEffects SideEffectsForArchRuntimeCalls() { + return SideEffects::CanTriggerGC(); + } + + DECLARE_INSTRUCTION(LoadMethodType); + + protected: + DEFAULT_COPY_CONSTRUCTOR(LoadMethodType); + + private: + // The special input is the HCurrentMethod for kRuntimeCall. + HUserRecord<HInstruction*> special_input_; + + const uint16_t proto_idx_; + const DexFile& dex_file_; +}; + /** * Performs an initialization check on its Class object input. */ @@ -6633,7 +6687,7 @@ class HStaticFieldGet FINAL : public HExpression<1> { const FieldInfo field_info_; }; -class HStaticFieldSet FINAL : public HTemplateInstruction<2> { +class HStaticFieldSet FINAL : public HExpression<2> { public: HStaticFieldSet(HInstruction* cls, HInstruction* value, @@ -6645,9 +6699,9 @@ class HStaticFieldSet FINAL : public HTemplateInstruction<2> { uint16_t declaring_class_def_index, const DexFile& dex_file, uint32_t dex_pc) - : HTemplateInstruction(kStaticFieldSet, - SideEffects::FieldWriteOfType(field_type, is_volatile), - dex_pc), + : HExpression(kStaticFieldSet, + SideEffects::FieldWriteOfType(field_type, is_volatile), + dex_pc), field_info_(field, field_offset, field_type, @@ -6714,16 +6768,14 @@ class HUnresolvedInstanceFieldGet FINAL : public HExpression<1> { const uint32_t field_index_; }; -class HUnresolvedInstanceFieldSet FINAL : public HTemplateInstruction<2> { +class HUnresolvedInstanceFieldSet FINAL : public HExpression<2> { public: HUnresolvedInstanceFieldSet(HInstruction* obj, HInstruction* value, DataType::Type field_type, uint32_t field_index, uint32_t dex_pc) - : HTemplateInstruction(kUnresolvedInstanceFieldSet, - SideEffects::AllExceptGCDependency(), - dex_pc), + : HExpression(kUnresolvedInstanceFieldSet, SideEffects::AllExceptGCDependency(), dex_pc), field_index_(field_index) { SetPackedField<FieldTypeField>(field_type); DCHECK_EQ(DataType::Kind(field_type), DataType::Kind(value->GetType())); @@ -6784,15 +6836,13 @@ class HUnresolvedStaticFieldGet FINAL : public HExpression<0> { const uint32_t field_index_; }; -class HUnresolvedStaticFieldSet FINAL : public HTemplateInstruction<1> { +class HUnresolvedStaticFieldSet FINAL : public HExpression<1> { public: HUnresolvedStaticFieldSet(HInstruction* value, DataType::Type field_type, uint32_t field_index, uint32_t dex_pc) - : HTemplateInstruction(kUnresolvedStaticFieldSet, - SideEffects::AllExceptGCDependency(), - dex_pc), + : HExpression(kUnresolvedStaticFieldSet, SideEffects::AllExceptGCDependency(), dex_pc), field_index_(field_index) { SetPackedField<FieldTypeField>(field_type); DCHECK_EQ(DataType::Kind(field_type), DataType::Kind(value->GetType())); @@ -6841,10 +6891,10 @@ class HLoadException FINAL : public HExpression<0> { // Implicit part of move-exception which clears thread-local exception storage. // Must not be removed because the runtime expects the TLS to get cleared. -class HClearException FINAL : public HTemplateInstruction<0> { +class HClearException FINAL : public HExpression<0> { public: explicit HClearException(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kClearException, SideEffects::AllWrites(), dex_pc) { + : HExpression(kClearException, SideEffects::AllWrites(), dex_pc) { } DECLARE_INSTRUCTION(ClearException); @@ -6853,10 +6903,10 @@ class HClearException FINAL : public HTemplateInstruction<0> { DEFAULT_COPY_CONSTRUCTOR(ClearException); }; -class HThrow FINAL : public HTemplateInstruction<1> { +class HThrow FINAL : public HExpression<1> { public: HThrow(HInstruction* exception, uint32_t dex_pc) - : HTemplateInstruction(kThrow, SideEffects::CanTriggerGC(), dex_pc) { + : HExpression(kThrow, SideEffects::CanTriggerGC(), dex_pc) { SetRawInputAt(0, exception); } @@ -6897,6 +6947,7 @@ std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs); class HTypeCheckInstruction : public HVariableInputSizeInstruction { public: HTypeCheckInstruction(InstructionKind kind, + DataType::Type type, HInstruction* object, HInstruction* target_class_or_null, TypeCheckKind check_kind, @@ -6908,6 +6959,7 @@ class HTypeCheckInstruction : public HVariableInputSizeInstruction { SideEffects side_effects) : HVariableInputSizeInstruction( kind, + type, side_effects, dex_pc, allocator, @@ -7010,6 +7062,7 @@ class HInstanceOf FINAL : public HTypeCheckInstruction { HIntConstant* bitstring_path_to_root, HIntConstant* bitstring_mask) : HTypeCheckInstruction(kInstanceOf, + DataType::Type::kBool, object, target_class_or_null, check_kind, @@ -7020,8 +7073,6 @@ class HInstanceOf FINAL : public HTypeCheckInstruction { bitstring_mask, SideEffectsForArchRuntimeCalls(check_kind)) {} - DataType::Type GetType() const OVERRIDE { return DataType::Type::kBool; } - bool NeedsEnvironment() const OVERRIDE { return CanCallRuntime(GetTypeCheckKind()); } @@ -7074,7 +7125,7 @@ class HBoundType FINAL : public HExpression<1> { private: // Represents the top constraint that can_be_null_ cannot exceed (i.e. if this // is false then CanBeNull() cannot be true). - static constexpr size_t kFlagUpperCanBeNull = kNumberOfExpressionPackedBits; + static constexpr size_t kFlagUpperCanBeNull = kNumberOfGenericPackedBits; static constexpr size_t kFlagCanBeNull = kFlagUpperCanBeNull + 1; static constexpr size_t kNumberOfBoundTypePackedBits = kFlagCanBeNull + 1; static_assert(kNumberOfBoundTypePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); @@ -7099,6 +7150,7 @@ class HCheckCast FINAL : public HTypeCheckInstruction { HIntConstant* bitstring_path_to_root, HIntConstant* bitstring_mask) : HTypeCheckInstruction(kCheckCast, + DataType::Type::kVoid, object, target_class_or_null, check_kind, @@ -7148,13 +7200,12 @@ enum MemBarrierKind { }; std::ostream& operator<<(std::ostream& os, const MemBarrierKind& kind); -class HMemoryBarrier FINAL : public HTemplateInstruction<0> { +class HMemoryBarrier FINAL : public HExpression<0> { public: explicit HMemoryBarrier(MemBarrierKind barrier_kind, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction( - kMemoryBarrier, - SideEffects::AllWritesAndReads(), // Assume write/read on all fields/arrays. - dex_pc) { + : HExpression(kMemoryBarrier, + SideEffects::AllWritesAndReads(), // Assume write/read on all fields/arrays. + dex_pc) { SetPackedField<BarrierKindField>(barrier_kind); } @@ -7331,7 +7382,7 @@ class HConstructorFence FINAL : public HVariableInputSizeInstruction { DEFAULT_COPY_CONSTRUCTOR(ConstructorFence); }; -class HMonitorOperation FINAL : public HTemplateInstruction<1> { +class HMonitorOperation FINAL : public HExpression<1> { public: enum class OperationKind { kEnter, @@ -7340,10 +7391,9 @@ class HMonitorOperation FINAL : public HTemplateInstruction<1> { }; HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc) - : HTemplateInstruction( - kMonitorOperation, - SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays. - dex_pc) { + : HExpression(kMonitorOperation, + SideEffects::AllExceptGCDependency(), // Assume write/read on all fields/arrays. + dex_pc) { SetPackedField<OperationKindField>(kind); SetRawInputAt(0, object); } @@ -7493,10 +7543,10 @@ std::ostream& operator<<(std::ostream& os, const MoveOperands& rhs); static constexpr size_t kDefaultNumberOfMoves = 4; -class HParallelMove FINAL : public HTemplateInstruction<0> { +class HParallelMove FINAL : public HExpression<0> { public: explicit HParallelMove(ArenaAllocator* allocator, uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(kParallelMove, SideEffects::None(), dex_pc), + : HExpression(kParallelMove, SideEffects::None(), dex_pc), moves_(allocator->Adapter(kArenaAllocMoveOperands)) { moves_.reserve(kDefaultNumberOfMoves); } @@ -7788,8 +7838,30 @@ inline bool IsZeroBitPattern(HInstruction* instruction) { return instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern(); } +// Implement HInstruction::Is##type() for concrete instructions. +#define INSTRUCTION_TYPE_CHECK(type, super) \ + inline bool HInstruction::Is##type() const { return GetKind() == k##type; } + FOR_EACH_CONCRETE_INSTRUCTION(INSTRUCTION_TYPE_CHECK) +#undef INSTRUCTION_TYPE_CHECK + +// Implement HInstruction::Is##type() for abstract instructions. +#define INSTRUCTION_TYPE_CHECK_RESULT(type, super) \ + std::is_base_of<BaseType, H##type>::value, #define INSTRUCTION_TYPE_CHECK(type, super) \ - inline bool HInstruction::Is##type() const { return GetKind() == k##type; } \ + inline bool HInstruction::Is##type() const { \ + DCHECK_LT(GetKind(), kLastInstructionKind); \ + using BaseType = H##type; \ + static constexpr bool results[] = { \ + FOR_EACH_CONCRETE_INSTRUCTION(INSTRUCTION_TYPE_CHECK_RESULT) \ + }; \ + return results[static_cast<size_t>(GetKind())]; \ + } + + FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK) +#undef INSTRUCTION_TYPE_CHECK +#undef INSTRUCTION_TYPE_CHECK_RESULT + +#define INSTRUCTION_TYPE_CAST(type, super) \ inline const H##type* HInstruction::As##type() const { \ return Is##type() ? down_cast<const H##type*>(this) : nullptr; \ } \ @@ -7797,8 +7869,9 @@ inline bool IsZeroBitPattern(HInstruction* instruction) { return Is##type() ? static_cast<H##type*>(this) : nullptr; \ } - FOR_EACH_CONCRETE_INSTRUCTION(INSTRUCTION_TYPE_CHECK) -#undef INSTRUCTION_TYPE_CHECK + FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CAST) +#undef INSTRUCTION_TYPE_CAST + // Create space in `blocks` for adding `number_of_new_blocks` entries // starting at location `at`. Blocks after `at` are moved accordingly. diff --git a/compiler/optimizing/nodes_mips.h b/compiler/optimizing/nodes_mips.h index d0e0fef946..05b27a7810 100644 --- a/compiler/optimizing/nodes_mips.h +++ b/compiler/optimizing/nodes_mips.h @@ -39,14 +39,14 @@ class HMipsComputeBaseMethodAddress : public HExpression<0> { }; // Mips version of HPackedSwitch that holds a pointer to the base method address. -class HMipsPackedSwitch FINAL : public HTemplateInstruction<2> { +class HMipsPackedSwitch FINAL : public HExpression<2> { public: HMipsPackedSwitch(int32_t start_value, int32_t num_entries, HInstruction* input, HMipsComputeBaseMethodAddress* method_base, uint32_t dex_pc) - : HTemplateInstruction(kMipsPackedSwitch, SideEffects::None(), dex_pc), + : HExpression(kMipsPackedSwitch, SideEffects::None(), dex_pc), start_value_(start_value), num_entries_(num_entries) { SetRawInputAt(0, input); diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h index 1a484e1944..c5e9a8d036 100644 --- a/compiler/optimizing/nodes_vector.h +++ b/compiler/optimizing/nodes_vector.h @@ -79,13 +79,14 @@ class HVecOperation : public HVariableInputSizeInstruction { size_t vector_length, uint32_t dex_pc) : HVariableInputSizeInstruction(kind, + kSIMDType, side_effects, dex_pc, allocator, number_of_inputs, kArenaAllocVectorNode), vector_length_(vector_length) { - SetPackedField<TypeField>(packed_type); + SetPackedField<PackedTypeField>(packed_type); DCHECK_LT(1u, vector_length); } @@ -99,14 +100,9 @@ class HVecOperation : public HVariableInputSizeInstruction { return vector_length_ * DataType::Size(GetPackedType()); } - // Returns the type of the vector operation. - DataType::Type GetType() const OVERRIDE { - return kSIMDType; - } - // Returns the true component type packed in a vector. DataType::Type GetPackedType() const { - return GetPackedField<TypeField>(); + return GetPackedField<PackedTypeField>(); } // Assumes vector nodes cannot be moved by default. Each concrete implementation @@ -185,12 +181,12 @@ class HVecOperation : public HVariableInputSizeInstruction { protected: // Additional packed bits. - static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits; - static constexpr size_t kFieldTypeSize = + static constexpr size_t kFieldPackedType = HInstruction::kNumberOfGenericPackedBits; + static constexpr size_t kFieldPackedTypeSize = MinimumBitsToStore(static_cast<size_t>(DataType::Type::kLast)); - static constexpr size_t kNumberOfVectorOpPackedBits = kFieldType + kFieldTypeSize; + static constexpr size_t kNumberOfVectorOpPackedBits = kFieldPackedType + kFieldPackedTypeSize; static_assert(kNumberOfVectorOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); - using TypeField = BitField<DataType::Type, kFieldType, kFieldTypeSize>; + using PackedTypeField = BitField<DataType::Type, kFieldPackedType, kFieldPackedTypeSize>; DEFAULT_COPY_CONSTRUCTOR(VecOperation); @@ -358,11 +354,9 @@ class HVecExtractScalar FINAL : public HVecUnaryOperation { DCHECK(HasConsistentPackedTypes(input, packed_type)); DCHECK_LT(index, vector_length); DCHECK_EQ(index, 0u); - } - - // Yields a single component in the vector. - DataType::Type GetType() const OVERRIDE { - return GetPackedType(); + // Yields a single component in the vector. + // Overrides the kSIMDType set by the VecOperation constructor. + SetPackedField<TypeField>(packed_type); } // An extract needs to stay in place, since SIMD registers are not diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h index 4c32be7d15..d1e7f68edb 100644 --- a/compiler/optimizing/nodes_x86.h +++ b/compiler/optimizing/nodes_x86.h @@ -89,14 +89,14 @@ class HX86FPNeg FINAL : public HExpression<2> { }; // X86 version of HPackedSwitch that holds a pointer to the base method address. -class HX86PackedSwitch FINAL : public HTemplateInstruction<2> { +class HX86PackedSwitch FINAL : public HExpression<2> { public: HX86PackedSwitch(int32_t start_value, int32_t num_entries, HInstruction* input, HX86ComputeBaseMethodAddress* method_base, uint32_t dex_pc) - : HTemplateInstruction(kX86PackedSwitch, SideEffects::None(), dex_pc), + : HExpression(kX86PackedSwitch, SideEffects::None(), dex_pc), start_value_(start_value), num_entries_(num_entries) { SetRawInputAt(0, input); diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 6e2c99444c..c4977decd9 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -109,7 +109,7 @@ class PassObserver : public ValueObject { : graph_(graph), last_seen_graph_size_(0), cached_method_name_(), - timing_logger_enabled_(compiler_driver->GetCompilerOptions().GetDumpTimings()), + timing_logger_enabled_(compiler_driver->GetCompilerOptions().GetDumpPassTimings()), timing_logger_(timing_logger_enabled_ ? GetMethodName() : "", true, true), disasm_info_(graph->GetAllocator()), visualizer_oss_(), diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc index 59733397bf..831bccc90a 100644 --- a/compiler/optimizing/prepare_for_register_allocation.cc +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -17,7 +17,7 @@ #include "prepare_for_register_allocation.h" #include "dex/dex_file_types.h" -#include "jni_internal.h" +#include "jni/jni_internal.h" #include "optimizing_compiler_stats.h" #include "well_known_classes.h" diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index c47c69af67..ecfa790b91 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -59,6 +59,18 @@ ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetClassCla return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_); } +ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodHandleClassHandle() { + return GetRootHandle(handles_, + ClassLinker::kJavaLangInvokeMethodHandleImpl, + &method_handle_class_handle_); +} + +ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodTypeClassHandle() { + return GetRootHandle(handles_, + ClassLinker::kJavaLangInvokeMethodType, + &method_type_class_handle_); +} + ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() { return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_); } @@ -89,6 +101,8 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { void VisitLoadClass(HLoadClass* load_class) OVERRIDE; void VisitInstanceOf(HInstanceOf* load_class) OVERRIDE; void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE; + void VisitLoadMethodHandle(HLoadMethodHandle* instr) OVERRIDE; + void VisitLoadMethodType(HLoadMethodType* instr) OVERRIDE; void VisitLoadString(HLoadString* instr) OVERRIDE; void VisitLoadException(HLoadException* instr) OVERRIDE; void VisitNewArray(HNewArray* instr) OVERRIDE; @@ -668,6 +682,17 @@ void ReferenceTypePropagation::RTPVisitor::VisitClinitCheck(HClinitCheck* instr) instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo()); } +void ReferenceTypePropagation::RTPVisitor::VisitLoadMethodHandle(HLoadMethodHandle* instr) { + instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create( + handle_cache_->GetMethodHandleClassHandle(), + /* is_exact */ true)); +} + +void ReferenceTypePropagation::RTPVisitor::VisitLoadMethodType(HLoadMethodType* instr) { + instr->SetReferenceTypeInfo( + ReferenceTypeInfo::Create(handle_cache_->GetMethodTypeClassHandle(), /* is_exact */ true)); +} + void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) { instr->SetReferenceTypeInfo( ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true)); diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h index 400852f4dc..d36d592708 100644 --- a/compiler/optimizing/reference_type_propagation.h +++ b/compiler/optimizing/reference_type_propagation.h @@ -75,6 +75,8 @@ class ReferenceTypePropagation : public HOptimization { ReferenceTypeInfo::TypeHandle GetObjectClassHandle(); ReferenceTypeInfo::TypeHandle GetClassClassHandle(); + ReferenceTypeInfo::TypeHandle GetMethodHandleClassHandle(); + ReferenceTypeInfo::TypeHandle GetMethodTypeClassHandle(); ReferenceTypeInfo::TypeHandle GetStringClassHandle(); ReferenceTypeInfo::TypeHandle GetThrowableClassHandle(); @@ -83,6 +85,8 @@ class ReferenceTypePropagation : public HOptimization { ReferenceTypeInfo::TypeHandle object_class_handle_; ReferenceTypeInfo::TypeHandle class_class_handle_; + ReferenceTypeInfo::TypeHandle method_handle_class_handle_; + ReferenceTypeInfo::TypeHandle method_type_class_handle_; ReferenceTypeInfo::TypeHandle string_class_handle_; ReferenceTypeInfo::TypeHandle throwable_class_handle_; }; diff --git a/compiler/optimizing/scheduler_arm64.h b/compiler/optimizing/scheduler_arm64.h index f71cb5b784..4f394d5e16 100644 --- a/compiler/optimizing/scheduler_arm64.h +++ b/compiler/optimizing/scheduler_arm64.h @@ -68,12 +68,10 @@ class SchedulingLatencyVisitorARM64 : public SchedulingLatencyVisitor { M(ArrayGet , unused) \ M(ArrayLength , unused) \ M(ArraySet , unused) \ - M(BinaryOperation , unused) \ M(BoundsCheck , unused) \ M(Div , unused) \ M(InstanceFieldGet , unused) \ M(InstanceOf , unused) \ - M(Invoke , unused) \ M(LoadString , unused) \ M(Mul , unused) \ M(NewArray , unused) \ @@ -108,6 +106,10 @@ class SchedulingLatencyVisitorARM64 : public SchedulingLatencyVisitor { M(VecLoad , unused) \ M(VecStore , unused) +#define FOR_EACH_SCHEDULED_ABSTRACT_INSTRUCTION(M) \ + M(BinaryOperation , unused) \ + M(Invoke , unused) + #define FOR_EACH_SCHEDULED_SHARED_INSTRUCTION(M) \ M(BitwiseNegatedRight, unused) \ M(MultiplyAccumulate, unused) \ @@ -119,6 +121,7 @@ class SchedulingLatencyVisitorARM64 : public SchedulingLatencyVisitor { void Visit##type(H##type* instruction) OVERRIDE; FOR_EACH_SCHEDULED_COMMON_INSTRUCTION(DECLARE_VISIT_INSTRUCTION) + FOR_EACH_SCHEDULED_ABSTRACT_INSTRUCTION(DECLARE_VISIT_INSTRUCTION) FOR_EACH_SCHEDULED_SHARED_INSTRUCTION(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION) |