summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/code_generator.cc40
-rw-r--r--compiler/optimizing/code_generator.h10
-rw-r--r--compiler/optimizing/code_generator_arm64.cc20
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc20
-rw-r--r--compiler/optimizing/code_generator_mips.cc20
-rw-r--r--compiler/optimizing/code_generator_mips64.cc20
-rw-r--r--compiler/optimizing/code_generator_x86.cc20
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc20
-rw-r--r--compiler/optimizing/data_type.h15
-rw-r--r--compiler/optimizing/graph_checker.cc24
-rw-r--r--compiler/optimizing/graph_checker.h12
-rw-r--r--compiler/optimizing/graph_visualizer.cc12
-rw-r--r--compiler/optimizing/instruction_builder.cc44
-rw-r--r--compiler/optimizing/instruction_builder.h9
-rw-r--r--compiler/optimizing/instruction_simplifier.cc4
-rw-r--r--compiler/optimizing/load_store_analysis.h59
-rw-r--r--compiler/optimizing/load_store_analysis_test.cc119
-rw-r--r--compiler/optimizing/load_store_elimination.cc119
-rw-r--r--compiler/optimizing/loop_optimization.cc1
-rw-r--r--compiler/optimizing/nodes.cc7
-rw-r--r--compiler/optimizing/nodes.h401
-rw-r--r--compiler/optimizing/nodes_mips.h4
-rw-r--r--compiler/optimizing/nodes_vector.h26
-rw-r--r--compiler/optimizing/nodes_x86.h4
-rw-r--r--compiler/optimizing/optimizing_compiler.cc22
-rw-r--r--compiler/optimizing/optimizing_compiler_stats.h1
-rw-r--r--compiler/optimizing/prepare_for_register_allocation.cc2
-rw-r--r--compiler/optimizing/reference_type_propagation.cc25
-rw-r--r--compiler/optimizing/reference_type_propagation.h4
-rw-r--r--compiler/optimizing/scheduler.cc20
-rw-r--r--compiler/optimizing/scheduler.h8
-rw-r--r--compiler/optimizing/scheduler_arm64.h7
-rw-r--r--compiler/optimizing/scheduler_test.cc24
-rw-r--r--compiler/optimizing/stack_map_stream.cc12
34 files changed, 749 insertions, 406 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 231017f55e..fb556f435a 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().index_);
+ 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/data_type.h b/compiler/optimizing/data_type.h
index be26e67af3..5ac6e46003 100644
--- a/compiler/optimizing/data_type.h
+++ b/compiler/optimizing/data_type.h
@@ -216,6 +216,21 @@ class DataType {
Size(result_type) > Size(input_type);
}
+ static Type ToSigned(Type type) {
+ switch (type) {
+ case Type::kUint8:
+ return Type::kInt8;
+ case Type::kUint16:
+ return Type::kInt16;
+ case Type::kUint32:
+ return Type::kInt32;
+ case Type::kUint64:
+ return Type::kInt64;
+ default:
+ return type;
+ }
+ }
+
static const char* PrettyDescriptor(Type type);
private:
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index fbcbe3608e..a689f35e0f 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -58,6 +58,30 @@ static bool IsExitTryBoundaryIntoExitBlock(HBasicBlock* block) {
!boundary->IsEntry();
}
+
+size_t GraphChecker::Run(bool pass_change, size_t last_size) {
+ size_t current_size = GetGraph()->GetReversePostOrder().size();
+ if (!pass_change) {
+ // Nothing changed for certain. Do a quick sanity check on that assertion
+ // for anything other than the first call (when last size was still 0).
+ if (last_size != 0) {
+ if (current_size != last_size) {
+ AddError(StringPrintf("Incorrect no-change assertion, "
+ "last graph size %zu vs current graph size %zu",
+ last_size, current_size));
+ }
+ }
+ // TODO: if we would trust the "false" value of the flag completely, we
+ // could skip checking the graph at this point.
+ }
+
+ // VisitReversePostOrder is used instead of VisitInsertionOrder,
+ // as the latter might visit dead blocks removed by the dominator
+ // computation.
+ VisitReversePostOrder();
+ return current_size;
+}
+
void GraphChecker::VisitBasicBlock(HBasicBlock* block) {
current_block_ = block;
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index dbedc40518..3a2bb7a00c 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -38,13 +38,11 @@ class GraphChecker : public HGraphDelegateVisitor {
seen_ids_.ClearAllBits();
}
- // Check the whole graph (in reverse post-order).
- void Run() {
- // VisitReversePostOrder is used instead of VisitInsertionOrder,
- // as the latter might visit dead blocks removed by the dominator
- // computation.
- VisitReversePostOrder();
- }
+ // Check the whole graph. The pass_change parameter indicates whether changes
+ // may have occurred during the just executed pass. The default value is
+ // conservatively "true" (something may have changed). The last_size parameter
+ // and return value pass along the observed graph sizes.
+ size_t Run(bool pass_change = true, size_t last_size = 0);
void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
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..42031f9e25 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1055,7 +1055,7 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction,
bool HInstructionBuilder::BuildInvokePolymorphic(const Instruction& instruction ATTRIBUTE_UNUSED,
uint32_t dex_pc,
uint32_t method_idx,
- uint32_t proto_idx,
+ dex::ProtoIndex proto_idx,
uint32_t number_of_vreg_arguments,
bool is_range,
uint32_t* args,
@@ -1360,9 +1360,15 @@ bool HInstructionBuilder::HandleStringInit(HInvoke* invoke,
if (arg_this->IsNewInstance()) {
ssa_builder_->AddUninitializedString(arg_this->AsNewInstance());
} else {
+ // The only reason a HPhi can flow in a String.<init> is when there is an
+ // irreducible loop, which will create HPhi for all dex registers at loop entry.
DCHECK(arg_this->IsPhi());
- // NewInstance is not the direct input of the StringFactory call. It might
- // be redundant but optimizing this case is not worth the effort.
+ DCHECK(graph_->HasIrreducibleLoops());
+ // Don't bother compiling a method in that situation. While we could look at all
+ // phis related to the HNewInstance, it's not worth the trouble.
+ MaybeRecordStat(compilation_stats_,
+ MethodCompilationStat::kNotCompiledIrreducibleAndStringInit);
+ return false;
}
// Walk over all vregs and replace any occurrence of `arg_this` with `invoke`.
@@ -1896,6 +1902,20 @@ bool HInstructionBuilder::LoadClassNeedsAccessCheck(Handle<mirror::Class> klass)
}
}
+void HInstructionBuilder::BuildLoadMethodHandle(uint16_t method_handle_index, uint32_t dex_pc) {
+ const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
+ HLoadMethodHandle* load_method_handle = new (allocator_) HLoadMethodHandle(
+ graph_->GetCurrentMethod(), method_handle_index, dex_file, dex_pc);
+ AppendInstruction(load_method_handle);
+}
+
+void HInstructionBuilder::BuildLoadMethodType(dex::ProtoIndex proto_index, uint32_t dex_pc) {
+ const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
+ HLoadMethodType* load_method_type =
+ new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_index, dex_file, dex_pc);
+ AppendInstruction(load_method_type);
+}
+
void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
uint8_t destination,
uint8_t reference,
@@ -2175,7 +2195,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
case Instruction::INVOKE_POLYMORPHIC: {
uint16_t method_idx = instruction.VRegB_45cc();
- uint16_t proto_idx = instruction.VRegH_45cc();
+ dex::ProtoIndex proto_idx(instruction.VRegH_45cc());
uint32_t number_of_vreg_arguments = instruction.VRegA_45cc();
uint32_t args[5];
instruction.GetVarArgs(args);
@@ -2191,7 +2211,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
case Instruction::INVOKE_POLYMORPHIC_RANGE: {
uint16_t method_idx = instruction.VRegB_4rcc();
- uint16_t proto_idx = instruction.VRegH_4rcc();
+ dex::ProtoIndex proto_idx(instruction.VRegH_4rcc());
uint32_t number_of_vreg_arguments = instruction.VRegA_4rcc();
uint32_t register_index = instruction.VRegC_4rcc();
return BuildInvokePolymorphic(instruction,
@@ -2927,6 +2947,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: {
+ dex::ProtoIndex 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..9d886a8ef2 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 {
@@ -177,7 +178,7 @@ class HInstructionBuilder : public ValueObject {
bool BuildInvokePolymorphic(const Instruction& instruction,
uint32_t dex_pc,
uint32_t method_idx,
- uint32_t proto_idx,
+ dex::ProtoIndex proto_idx,
uint32_t number_of_vreg_arguments,
bool is_range,
uint32_t* args,
@@ -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_index`.
+ void BuildLoadMethodHandle(uint16_t method_handle_idx, uint32_t dex_pc);
+
+ // Builds a `HLoadMethodType` loading the given `proto_index`.
+ void BuildLoadMethodType(dex::ProtoIndex proto_index, 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/load_store_analysis.h b/compiler/optimizing/load_store_analysis.h
index f84846d1b0..769a3f1b59 100644
--- a/compiler/optimizing/load_store_analysis.h
+++ b/compiler/optimizing/load_store_analysis.h
@@ -94,11 +94,13 @@ class HeapLocation : public ArenaObject<kArenaAllocLSA> {
static constexpr int16_t kDeclaringClassDefIndexForArrays = -1;
HeapLocation(ReferenceInfo* ref_info,
+ DataType::Type type,
size_t offset,
HInstruction* index,
size_t vector_length,
int16_t declaring_class_def_index)
: ref_info_(ref_info),
+ type_(DataType::ToSigned(type)),
offset_(offset),
index_(index),
vector_length_(vector_length),
@@ -116,6 +118,7 @@ class HeapLocation : public ArenaObject<kArenaAllocLSA> {
}
ReferenceInfo* GetReferenceInfo() const { return ref_info_; }
+ DataType::Type GetType() const { return type_; }
size_t GetOffset() const { return offset_; }
HInstruction* GetIndex() const { return index_; }
size_t GetVectorLength() const { return vector_length_; }
@@ -149,6 +152,10 @@ class HeapLocation : public ArenaObject<kArenaAllocLSA> {
private:
// Reference for instance/static field, array element or vector data.
ReferenceInfo* const ref_info_;
+ // Type of data residing at HeapLocation (always signed for integral
+ // data since e.g. a[i] and a[i] & 0xff are represented by differently
+ // signed types; char vs short are disambiguated through the reference).
+ const DataType::Type type_;
// Offset of static/instance field.
// Invalid when this HeapLocation is not field.
const size_t offset_;
@@ -237,19 +244,31 @@ class HeapLocationCollector : public HGraphVisitor {
DCHECK(object != nullptr);
DCHECK(field != nullptr);
return FindHeapLocationIndex(FindReferenceInfoOf(HuntForOriginalReference(object)),
+ field->GetFieldType(),
field->GetFieldOffset().SizeValue(),
nullptr,
HeapLocation::kScalar,
field->GetDeclaringClassDefIndex());
}
- size_t GetArrayHeapLocation(HInstruction* array,
- HInstruction* index,
- size_t vector_length = HeapLocation::kScalar) const {
- DCHECK(array != nullptr);
- DCHECK(index != nullptr);
- DCHECK_GE(vector_length, HeapLocation::kScalar);
+ size_t GetArrayHeapLocation(HInstruction* instruction) const {
+ DCHECK(instruction != nullptr);
+ HInstruction* array = instruction->InputAt(0);
+ HInstruction* index = instruction->InputAt(1);
+ DataType::Type type = instruction->GetType();
+ size_t vector_length = HeapLocation::kScalar;
+ if (instruction->IsArraySet()) {
+ type = instruction->AsArraySet()->GetComponentType();
+ } else if (instruction->IsVecStore() ||
+ instruction->IsVecLoad()) {
+ HVecOperation* vec_op = instruction->AsVecOperation();
+ type = vec_op->GetPackedType();
+ vector_length = vec_op->GetVectorLength();
+ } else {
+ DCHECK(instruction->IsArrayGet());
+ }
return FindHeapLocationIndex(FindReferenceInfoOf(HuntForOriginalReference(array)),
+ type,
HeapLocation::kInvalidFieldOffset,
index,
vector_length,
@@ -279,13 +298,16 @@ class HeapLocationCollector : public HGraphVisitor {
// In later analysis, ComputeMayAlias() and MayAlias() compute and tell whether
// these indexes alias.
size_t FindHeapLocationIndex(ReferenceInfo* ref_info,
+ DataType::Type type,
size_t offset,
HInstruction* index,
size_t vector_length,
int16_t declaring_class_def_index) const {
+ DataType::Type lookup_type = DataType::ToSigned(type);
for (size_t i = 0; i < heap_locations_.size(); i++) {
HeapLocation* loc = heap_locations_[i];
if (loc->GetReferenceInfo() == ref_info &&
+ loc->GetType() == lookup_type &&
loc->GetOffset() == offset &&
loc->GetIndex() == index &&
loc->GetVectorLength() == vector_length &&
@@ -425,6 +447,7 @@ class HeapLocationCollector : public HGraphVisitor {
}
HeapLocation* GetOrCreateHeapLocation(HInstruction* ref,
+ DataType::Type type,
size_t offset,
HInstruction* index,
size_t vector_length,
@@ -432,10 +455,10 @@ class HeapLocationCollector : public HGraphVisitor {
HInstruction* original_ref = HuntForOriginalReference(ref);
ReferenceInfo* ref_info = GetOrCreateReferenceInfo(original_ref);
size_t heap_location_idx = FindHeapLocationIndex(
- ref_info, offset, index, vector_length, declaring_class_def_index);
+ ref_info, type, offset, index, vector_length, declaring_class_def_index);
if (heap_location_idx == kHeapLocationNotFound) {
HeapLocation* heap_loc = new (GetGraph()->GetAllocator())
- HeapLocation(ref_info, offset, index, vector_length, declaring_class_def_index);
+ HeapLocation(ref_info, type, offset, index, vector_length, declaring_class_def_index);
heap_locations_.push_back(heap_loc);
return heap_loc;
}
@@ -446,17 +469,23 @@ class HeapLocationCollector : public HGraphVisitor {
if (field_info.IsVolatile()) {
has_volatile_ = true;
}
+ DataType::Type type = field_info.GetFieldType();
const uint16_t declaring_class_def_index = field_info.GetDeclaringClassDefIndex();
const size_t offset = field_info.GetFieldOffset().SizeValue();
return GetOrCreateHeapLocation(ref,
+ type,
offset,
nullptr,
HeapLocation::kScalar,
declaring_class_def_index);
}
- void VisitArrayAccess(HInstruction* array, HInstruction* index, size_t vector_length) {
+ void VisitArrayAccess(HInstruction* array,
+ HInstruction* index,
+ DataType::Type type,
+ size_t vector_length) {
GetOrCreateHeapLocation(array,
+ type,
HeapLocation::kInvalidFieldOffset,
index,
vector_length,
@@ -510,28 +539,32 @@ class HeapLocationCollector : public HGraphVisitor {
void VisitArrayGet(HArrayGet* instruction) OVERRIDE {
HInstruction* array = instruction->InputAt(0);
HInstruction* index = instruction->InputAt(1);
- VisitArrayAccess(array, index, HeapLocation::kScalar);
+ DataType::Type type = instruction->GetType();
+ VisitArrayAccess(array, index, type, HeapLocation::kScalar);
CreateReferenceInfoForReferenceType(instruction);
}
void VisitArraySet(HArraySet* instruction) OVERRIDE {
HInstruction* array = instruction->InputAt(0);
HInstruction* index = instruction->InputAt(1);
- VisitArrayAccess(array, index, HeapLocation::kScalar);
+ DataType::Type type = instruction->GetComponentType();
+ VisitArrayAccess(array, index, type, HeapLocation::kScalar);
has_heap_stores_ = true;
}
void VisitVecLoad(HVecLoad* instruction) OVERRIDE {
HInstruction* array = instruction->InputAt(0);
HInstruction* index = instruction->InputAt(1);
- VisitArrayAccess(array, index, instruction->GetVectorLength());
+ DataType::Type type = instruction->GetPackedType();
+ VisitArrayAccess(array, index, type, instruction->GetVectorLength());
CreateReferenceInfoForReferenceType(instruction);
}
void VisitVecStore(HVecStore* instruction) OVERRIDE {
HInstruction* array = instruction->InputAt(0);
HInstruction* index = instruction->InputAt(1);
- VisitArrayAccess(array, index, instruction->GetVectorLength());
+ DataType::Type type = instruction->GetPackedType();
+ VisitArrayAccess(array, index, type, instruction->GetVectorLength());
has_heap_stores_ = true;
}
diff --git a/compiler/optimizing/load_store_analysis_test.cc b/compiler/optimizing/load_store_analysis_test.cc
index 56361a8c90..bfe7a4f72f 100644
--- a/compiler/optimizing/load_store_analysis_test.cc
+++ b/compiler/optimizing/load_store_analysis_test.cc
@@ -78,12 +78,16 @@ TEST_F(LoadStoreAnalysisTest, ArrayHeapLocations) {
// Test queries on HeapLocationCollector's ref info and index records.
ReferenceInfo* ref = heap_location_collector.FindReferenceInfoOf(array);
+ DataType::Type type = DataType::Type::kInt32;
size_t field = HeapLocation::kInvalidFieldOffset;
size_t vec = HeapLocation::kScalar;
size_t class_def = HeapLocation::kDeclaringClassDefIndexForArrays;
- size_t loc1 = heap_location_collector.FindHeapLocationIndex(ref, field, c1, vec, class_def);
- size_t loc2 = heap_location_collector.FindHeapLocationIndex(ref, field, c2, vec, class_def);
- size_t loc3 = heap_location_collector.FindHeapLocationIndex(ref, field, index, vec, class_def);
+ size_t loc1 = heap_location_collector.FindHeapLocationIndex(
+ ref, type, field, c1, vec, class_def);
+ size_t loc2 = heap_location_collector.FindHeapLocationIndex(
+ ref, type, field, c2, vec, class_def);
+ size_t loc3 = heap_location_collector.FindHeapLocationIndex(
+ ref, type, field, index, vec, class_def);
// must find this reference info for array in HeapLocationCollector.
ASSERT_TRUE(ref != nullptr);
// must find these heap locations;
@@ -246,28 +250,28 @@ TEST_F(LoadStoreAnalysisTest, ArrayIndexAliasingTest) {
size_t loc2 = HeapLocationCollector::kHeapLocationNotFound;
// Test alias: array[0] and array[1]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, c0);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, c1);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set1);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set2);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+0] and array[i-0]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, add0);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, sub0);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set3);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set5);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+1] and array[i-1]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, add1);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, sub1);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set4);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set6);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+1] and array[1-i]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, add1);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, rev_sub1);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set4);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set7);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+1] and array[i-(-1)]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, add1);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_neg1);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set4);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set8);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
}
@@ -409,70 +413,75 @@ TEST_F(LoadStoreAnalysisTest, ArrayAliasingTest) {
size_t loc1, loc2;
// Test alias: array[0] and array[0,1,2,3]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, c0);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, c0, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_0);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
+ // Test alias: array[0] and array[1,2,3,4]
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_1);
+ ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
+
// Test alias: array[0] and array[8,9,10,11]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, c0);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, c8, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_8);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[1] and array[8,9,10,11]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, c1);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, c8, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_1);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_8);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[1] and array[0,1,2,3]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, c1);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, c0, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_1);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_0);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[0,1,2,3] and array[8,9,10,11]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, c0, 4);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, c8, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(vstore_0);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_8);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[0,1,2,3] and array[1,2,3,4]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, c1, 4);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, c0, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(vstore_0);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_1);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[0] and array[i,i+1,i+2,i+3]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, c0);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, index, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i] and array[0,1,2,3]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, index);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, c0, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_0);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i] and array[i,i+1,i+2,i+3]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, index);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, index, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i] and array[i+8,i+9,i+10,i+11]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, index);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, i_add8, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i_add8);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+6,i+7,i+8,i+9] and array[i+8,i+9,i+10,i+11]
// Test partial overlap.
- loc1 = heap_location_collector.GetArrayHeapLocation(array, i_add6, 4);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, i_add8, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(vstore_i_add6);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i_add8);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+6,i+7] and array[i,i+1,i+2,i+3]
// Test different vector lengths.
- loc1 = heap_location_collector.GetArrayHeapLocation(array, i_add6, 2);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, index, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(vstore_i_add6_vlen2);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+6,i+7] and array[i+8,i+9,i+10,i+11]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, i_add6, 2);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, i_add8, 4);
+ loc1 = heap_location_collector.GetArrayHeapLocation(vstore_i_add6_vlen2);
+ loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i_add8);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
}
@@ -563,33 +572,33 @@ TEST_F(LoadStoreAnalysisTest, ArrayIndexCalculationOverflowTest) {
size_t loc2 = HeapLocationCollector::kHeapLocationNotFound;
// Test alias: array[i+0x80000000] and array[i-0x80000000]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0x80000000);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000000);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_1);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_2);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+0x10] and array[i-0xFFFFFFF0]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0x10);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0xFFFFFFF0);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_3);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_4);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+0x7FFFFFFF] and array[i-0x80000001]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0x7FFFFFFF);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000001);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_5);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_6);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Test alias: array[i+0] and array[i-0]
- loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_7);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_8);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
// Should not alias:
- loc1 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000000);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000001);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_2);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_6);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
// Should not alias:
- loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0);
- loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000000);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_7);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_2);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
}
@@ -647,10 +656,10 @@ TEST_F(LoadStoreAnalysisTest, TestHuntOriginalRef) {
// times the original reference has been transformed by BoundType,
// NullCheck, IntermediateAddress, etc.
ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 1U);
- size_t loc1 = heap_location_collector.GetArrayHeapLocation(array, c1);
- size_t loc2 = heap_location_collector.GetArrayHeapLocation(bound_type, c1);
- size_t loc3 = heap_location_collector.GetArrayHeapLocation(null_check, c1);
- size_t loc4 = heap_location_collector.GetArrayHeapLocation(inter_addr, c1);
+ size_t loc1 = heap_location_collector.GetArrayHeapLocation(array_get1);
+ size_t loc2 = heap_location_collector.GetArrayHeapLocation(array_get2);
+ size_t loc3 = heap_location_collector.GetArrayHeapLocation(array_get3);
+ size_t loc4 = heap_location_collector.GetArrayHeapLocation(array_get4);
ASSERT_TRUE(loc1 != HeapLocationCollector::kHeapLocationNotFound);
ASSERT_EQ(loc1, loc2);
ASSERT_EQ(loc1, loc3);
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index d598ff592d..35e64f75b9 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -160,7 +160,7 @@ class LSEVisitor : public HGraphDelegateVisitor {
// Scan the list of removed loads to see if we can reuse `type_conversion`, if
// the other removed load has the same substitute and type and is dominated
- // by `type_conversioni`.
+ // by `type_conversion`.
void TryToReuseTypeConversion(HInstruction* type_conversion, size_t index) {
size_t size = removed_loads_.size();
HInstruction* load = removed_loads_[index];
@@ -542,16 +542,7 @@ class LSEVisitor : public HGraphDelegateVisitor {
}
}
- void VisitGetLocation(HInstruction* instruction,
- HInstruction* ref,
- size_t offset,
- HInstruction* index,
- size_t vector_length,
- int16_t declaring_class_def_index) {
- HInstruction* original_ref = heap_location_collector_.HuntForOriginalReference(ref);
- ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(original_ref);
- size_t idx = heap_location_collector_.FindHeapLocationIndex(
- ref_info, offset, index, vector_length, declaring_class_def_index);
+ void VisitGetLocation(HInstruction* instruction, size_t idx) {
DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
ScopedArenaVector<HInstruction*>& heap_values =
heap_values_for_[instruction->GetBlock()->GetBlockId()];
@@ -569,23 +560,7 @@ class LSEVisitor : public HGraphDelegateVisitor {
heap_values[idx] = instruction;
KeepStoresIfAliasedToLocation(heap_values, idx);
} else {
- if (DataType::Kind(heap_value->GetType()) != DataType::Kind(instruction->GetType())) {
- // The only situation where the same heap location has different type is when
- // we do an array get on an instruction that originates from the null constant
- // (the null could be behind a field access, an array access, a null check or
- // a bound type).
- // In order to stay properly typed on primitive types, we do not eliminate
- // the array gets.
- if (kIsDebugBuild) {
- DCHECK(heap_value->IsArrayGet()) << heap_value->DebugName();
- DCHECK(instruction->IsArrayGet()) << instruction->DebugName();
- }
- // Load isn't eliminated. Put the load as the value into the HeapLocation.
- // This acts like GVN but with better aliasing analysis.
- heap_values[idx] = instruction;
- KeepStoresIfAliasedToLocation(heap_values, idx);
- return;
- }
+ // Load is eliminated.
AddRemovedLoad(instruction, heap_value);
TryRemovingNullCheck(instruction);
}
@@ -610,21 +585,11 @@ class LSEVisitor : public HGraphDelegateVisitor {
return false;
}
- void VisitSetLocation(HInstruction* instruction,
- HInstruction* ref,
- size_t offset,
- HInstruction* index,
- size_t vector_length,
- int16_t declaring_class_def_index,
- HInstruction* value) {
+ void VisitSetLocation(HInstruction* instruction, size_t idx, HInstruction* value) {
+ DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
DCHECK(!IsStore(value)) << value->DebugName();
// value may already have a substitute.
value = FindSubstitute(value);
- HInstruction* original_ref = heap_location_collector_.HuntForOriginalReference(ref);
- ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(original_ref);
- size_t idx = heap_location_collector_.FindHeapLocationIndex(
- ref_info, offset, index, vector_length, declaring_class_def_index);
- DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound);
ScopedArenaVector<HInstruction*>& heap_values =
heap_values_for_[instruction->GetBlock()->GetBlockId()];
HInstruction* heap_value = heap_values[idx];
@@ -644,7 +609,8 @@ class LSEVisitor : public HGraphDelegateVisitor {
} else if (!loop_info->IsIrreducible()) {
// instruction is a store in the loop so the loop must do write.
DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite());
- if (ref_info->IsSingleton() && !loop_info->IsDefinedOutOfTheLoop(original_ref)) {
+ ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(idx)->GetReferenceInfo();
+ if (ref_info->IsSingleton() && !loop_info->IsDefinedOutOfTheLoop(ref_info->GetReference())) {
// original_ref is created inside the loop. Value stored to it isn't needed at
// the loop header. This is true for outer loops also.
possibly_redundant = true;
@@ -686,79 +652,39 @@ class LSEVisitor : public HGraphDelegateVisitor {
}
void VisitInstanceFieldGet(HInstanceFieldGet* instruction) OVERRIDE {
- HInstruction* obj = instruction->InputAt(0);
- size_t offset = instruction->GetFieldInfo().GetFieldOffset().SizeValue();
- int16_t declaring_class_def_index = instruction->GetFieldInfo().GetDeclaringClassDefIndex();
- VisitGetLocation(instruction,
- obj,
- offset,
- nullptr,
- HeapLocation::kScalar,
- declaring_class_def_index);
+ HInstruction* object = instruction->InputAt(0);
+ const FieldInfo& field = instruction->GetFieldInfo();
+ VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(object, &field));
}
void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE {
- HInstruction* obj = instruction->InputAt(0);
- size_t offset = instruction->GetFieldInfo().GetFieldOffset().SizeValue();
- int16_t declaring_class_def_index = instruction->GetFieldInfo().GetDeclaringClassDefIndex();
+ HInstruction* object = instruction->InputAt(0);
+ const FieldInfo& field = instruction->GetFieldInfo();
HInstruction* value = instruction->InputAt(1);
- VisitSetLocation(instruction,
- obj,
- offset,
- nullptr,
- HeapLocation::kScalar,
- declaring_class_def_index,
- value);
+ size_t idx = heap_location_collector_.GetFieldHeapLocation(object, &field);
+ VisitSetLocation(instruction, idx, value);
}
void VisitStaticFieldGet(HStaticFieldGet* instruction) OVERRIDE {
HInstruction* cls = instruction->InputAt(0);
- size_t offset = instruction->GetFieldInfo().GetFieldOffset().SizeValue();
- int16_t declaring_class_def_index = instruction->GetFieldInfo().GetDeclaringClassDefIndex();
- VisitGetLocation(instruction,
- cls,
- offset,
- nullptr,
- HeapLocation::kScalar,
- declaring_class_def_index);
+ const FieldInfo& field = instruction->GetFieldInfo();
+ VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(cls, &field));
}
void VisitStaticFieldSet(HStaticFieldSet* instruction) OVERRIDE {
HInstruction* cls = instruction->InputAt(0);
- size_t offset = instruction->GetFieldInfo().GetFieldOffset().SizeValue();
- int16_t declaring_class_def_index = instruction->GetFieldInfo().GetDeclaringClassDefIndex();
- HInstruction* value = instruction->InputAt(1);
- VisitSetLocation(instruction,
- cls,
- offset,
- nullptr,
- HeapLocation::kScalar,
- declaring_class_def_index,
- value);
+ const FieldInfo& field = instruction->GetFieldInfo();
+ size_t idx = heap_location_collector_.GetFieldHeapLocation(cls, &field);
+ VisitSetLocation(instruction, idx, instruction->InputAt(1));
}
void VisitArrayGet(HArrayGet* instruction) OVERRIDE {
- HInstruction* array = instruction->InputAt(0);
- HInstruction* index = instruction->InputAt(1);
- VisitGetLocation(instruction,
- array,
- HeapLocation::kInvalidFieldOffset,
- index,
- HeapLocation::kScalar,
- HeapLocation::kDeclaringClassDefIndexForArrays);
+ VisitGetLocation(instruction, heap_location_collector_.GetArrayHeapLocation(instruction));
}
void VisitArraySet(HArraySet* instruction) OVERRIDE {
- HInstruction* array = instruction->InputAt(0);
- HInstruction* index = instruction->InputAt(1);
- HInstruction* value = instruction->InputAt(2);
- VisitSetLocation(instruction,
- array,
- HeapLocation::kInvalidFieldOffset,
- index,
- HeapLocation::kScalar,
- HeapLocation::kDeclaringClassDefIndexForArrays,
- value);
+ size_t idx = heap_location_collector_.GetArrayHeapLocation(instruction);
+ VisitSetLocation(instruction, idx, instruction->InputAt(2));
}
void VisitDeoptimize(HDeoptimize* instruction) {
@@ -971,6 +897,7 @@ bool LoadStoreElimination::Run() {
lse_visitor.VisitBasicBlock(block);
}
lse_visitor.RemoveInstructions();
+
return true;
}
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 0d85c2fbf5..1ce3524bd6 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -589,6 +589,7 @@ bool HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) {
// loop if the induction of any inner loop has changed.
if (TraverseLoopsInnerToOuter(node->inner)) {
induction_range_.ReVisit(node->loop_info);
+ changed = true;
}
// Repeat simplifications in the loop-body until no more changes occur.
// Note that since each simplification consists of eliminating code (without
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..e786502dee 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,
+ dex::ProtoIndex proto_index,
+ const DexFile& dex_file,
+ uint32_t dex_pc)
+ : HInstruction(kLoadMethodType,
+ DataType::Type::kReference,
+ SideEffectsForArchRuntimeCalls(),
+ dex_pc),
+ special_input_(HUserRecord<HInstruction*>(current_method)),
+ proto_index_(proto_index),
+ 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; }
+
+ dex::ProtoIndex GetProtoIndex() const { return proto_index_; }
+
+ 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 dex::ProtoIndex proto_index_;
+ 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 a6163a7fcf..c4977decd9 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -107,8 +107,9 @@ class PassObserver : public ValueObject {
CompilerDriver* compiler_driver,
Mutex& dump_mutex)
: 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_(),
@@ -174,7 +175,7 @@ class PassObserver : public ValueObject {
visualizer_oss_.clear();
}
- void EndPass(const char* pass_name) REQUIRES(!visualizer_dump_mutex_) {
+ void EndPass(const char* pass_name, bool pass_change) REQUIRES(!visualizer_dump_mutex_) {
// Pause timer first, then dump graph.
if (timing_logger_enabled_) {
timing_logger_.EndTiming();
@@ -188,7 +189,7 @@ class PassObserver : public ValueObject {
if (kIsDebugBuild) {
if (!graph_in_bad_state_) {
GraphChecker checker(graph_);
- checker.Run();
+ last_seen_graph_size_ = checker.Run(pass_change, last_seen_graph_size_);
if (!checker.IsValid()) {
LOG(FATAL) << "Error after " << pass_name << ": " << Dumpable<GraphChecker>(checker);
}
@@ -214,6 +215,7 @@ class PassObserver : public ValueObject {
}
HGraph* const graph_;
+ size_t last_seen_graph_size_;
std::string cached_method_name_;
@@ -241,16 +243,22 @@ class PassScope : public ValueObject {
public:
PassScope(const char *pass_name, PassObserver* pass_observer)
: pass_name_(pass_name),
+ pass_change_(true), // assume change
pass_observer_(pass_observer) {
pass_observer_->StartPass(pass_name_);
}
+ void SetPassNotChanged() {
+ pass_change_ = false;
+ }
+
~PassScope() {
- pass_observer_->EndPass(pass_name_);
+ pass_observer_->EndPass(pass_name_, pass_change_);
}
private:
const char* const pass_name_;
+ bool pass_change_;
PassObserver* const pass_observer_;
};
@@ -324,7 +332,11 @@ class OptimizingCompiler FINAL : public Compiler {
PassScope scope(optimizations[i]->GetPassName(), pass_observer);
bool pass_change = optimizations[i]->Run();
pass_changes[static_cast<size_t>(definitions[i].pass)] = pass_change;
- change |= pass_change;
+ if (pass_change) {
+ change = true;
+ } else {
+ scope.SetPassNotChanged();
+ }
} else {
// Skip the pass and record that nothing changed.
pass_changes[static_cast<size_t>(definitions[i].pass)] = false;
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index 9a26f2f6c4..f246228074 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -50,6 +50,7 @@ enum class MethodCompilationStat {
kNotCompiledThrowCatchLoop,
kNotCompiledAmbiguousArrayOp,
kNotCompiledHugeMethod,
+ kNotCompiledIrreducibleAndStringInit,
kNotCompiledLargeMethodNoBranches,
kNotCompiledMalformedOpcode,
kNotCompiledNoCodegen,
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.cc b/compiler/optimizing/scheduler.cc
index e014efaf5c..588ea03d69 100644
--- a/compiler/optimizing/scheduler.cc
+++ b/compiler/optimizing/scheduler.cc
@@ -70,19 +70,19 @@ static bool MayHaveReorderingDependency(SideEffects node, SideEffects other) {
return false;
}
-size_t SchedulingGraph::ArrayAccessHeapLocation(HInstruction* array, HInstruction* index) const {
+size_t SchedulingGraph::ArrayAccessHeapLocation(HInstruction* instruction) const {
DCHECK(heap_location_collector_ != nullptr);
- size_t heap_loc = heap_location_collector_->GetArrayHeapLocation(array, index);
+ size_t heap_loc = heap_location_collector_->GetArrayHeapLocation(instruction);
// This array access should be analyzed and added to HeapLocationCollector before.
DCHECK(heap_loc != HeapLocationCollector::kHeapLocationNotFound);
return heap_loc;
}
-bool SchedulingGraph::ArrayAccessMayAlias(const HInstruction* node,
- const HInstruction* other) const {
+bool SchedulingGraph::ArrayAccessMayAlias(HInstruction* node,
+ HInstruction* other) const {
DCHECK(heap_location_collector_ != nullptr);
- size_t node_heap_loc = ArrayAccessHeapLocation(node->InputAt(0), node->InputAt(1));
- size_t other_heap_loc = ArrayAccessHeapLocation(other->InputAt(0), other->InputAt(1));
+ size_t node_heap_loc = ArrayAccessHeapLocation(node);
+ size_t other_heap_loc = ArrayAccessHeapLocation(other);
// For example: arr[0] and arr[0]
if (node_heap_loc == other_heap_loc) {
@@ -194,8 +194,8 @@ bool SchedulingGraph::FieldAccessMayAlias(const HInstruction* node,
return true;
}
-bool SchedulingGraph::HasMemoryDependency(const HInstruction* node,
- const HInstruction* other) const {
+bool SchedulingGraph::HasMemoryDependency(HInstruction* node,
+ HInstruction* other) const {
if (!MayHaveReorderingDependency(node->GetSideEffects(), other->GetSideEffects())) {
return false;
}
@@ -264,8 +264,8 @@ bool SchedulingGraph::HasExceptionDependency(const HInstruction* node,
// Check whether `node` depends on `other`, taking into account `SideEffect`
// information and `CanThrow` information.
-bool SchedulingGraph::HasSideEffectDependency(const HInstruction* node,
- const HInstruction* other) const {
+bool SchedulingGraph::HasSideEffectDependency(HInstruction* node,
+ HInstruction* other) const {
if (HasMemoryDependency(node, other)) {
return true;
}
diff --git a/compiler/optimizing/scheduler.h b/compiler/optimizing/scheduler.h
index 51cd20aea9..8e98f192d8 100644
--- a/compiler/optimizing/scheduler.h
+++ b/compiler/optimizing/scheduler.h
@@ -310,12 +310,12 @@ class SchedulingGraph : public ValueObject {
void AddOtherDependency(SchedulingNode* node, SchedulingNode* dependency) {
AddDependency(node, dependency, /*is_data_dependency*/false);
}
- bool HasMemoryDependency(const HInstruction* node, const HInstruction* other) const;
+ bool HasMemoryDependency(HInstruction* node, HInstruction* other) const;
bool HasExceptionDependency(const HInstruction* node, const HInstruction* other) const;
- bool HasSideEffectDependency(const HInstruction* node, const HInstruction* other) const;
- bool ArrayAccessMayAlias(const HInstruction* node, const HInstruction* other) const;
+ bool HasSideEffectDependency(HInstruction* node, HInstruction* other) const;
+ bool ArrayAccessMayAlias(HInstruction* node, HInstruction* other) const;
bool FieldAccessMayAlias(const HInstruction* node, const HInstruction* other) const;
- size_t ArrayAccessHeapLocation(HInstruction* array, HInstruction* index) const;
+ size_t ArrayAccessHeapLocation(HInstruction* instruction) const;
size_t FieldAccessHeapLocation(HInstruction* obj, const FieldInfo* field) const;
// Add dependencies nodes for the given `HInstruction`: inputs, environments, and side-effects.
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)
diff --git a/compiler/optimizing/scheduler_test.cc b/compiler/optimizing/scheduler_test.cc
index fb15fc8975..d4cae72c7e 100644
--- a/compiler/optimizing/scheduler_test.cc
+++ b/compiler/optimizing/scheduler_test.cc
@@ -296,38 +296,38 @@ class SchedulerTest : public OptimizingUnitTest {
size_t loc2 = HeapLocationCollector::kHeapLocationNotFound;
// Test side effect dependency: array[0] and array[1]
- loc1 = heap_location_collector.GetArrayHeapLocation(arr, c0);
- loc2 = heap_location_collector.GetArrayHeapLocation(arr, c1);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_1);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_1, arr_set_0));
// Test side effect dependency based on LSA analysis: array[i] and array[j]
- loc1 = heap_location_collector.GetArrayHeapLocation(arr, i);
- loc2 = heap_location_collector.GetArrayHeapLocation(arr, j);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_j);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_j, arr_set_i));
// Test side effect dependency based on LSA analysis: array[i] and array[i+0]
- loc1 = heap_location_collector.GetArrayHeapLocation(arr, i);
- loc2 = heap_location_collector.GetArrayHeapLocation(arr, add0);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_add0);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_add0, arr_set_i));
// Test side effect dependency based on LSA analysis: array[i] and array[i-0]
- loc1 = heap_location_collector.GetArrayHeapLocation(arr, i);
- loc2 = heap_location_collector.GetArrayHeapLocation(arr, sub0);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_sub0);
ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_sub0, arr_set_i));
// Test side effect dependency based on LSA analysis: array[i] and array[i+1]
- loc1 = heap_location_collector.GetArrayHeapLocation(arr, i);
- loc2 = heap_location_collector.GetArrayHeapLocation(arr, add1);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_add1);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_add1, arr_set_i));
// Test side effect dependency based on LSA analysis: array[i+1] and array[i-1]
- loc1 = heap_location_collector.GetArrayHeapLocation(arr, add1);
- loc2 = heap_location_collector.GetArrayHeapLocation(arr, sub1);
+ loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_add1);
+ loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_sub1);
ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_sub1, arr_set_add1));
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index 7010e3f380..bf7c5542ef 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -427,10 +427,11 @@ void StackMapStream::FillInCodeInfo(MemoryRegion region) {
if (stack_mask_bits > 0) {
size_t stack_mask_bytes = RoundUp(stack_mask_bits, kBitsPerByte) / kBitsPerByte;
for (size_t i = 0; i < encoding.stack_mask.num_entries; ++i) {
- MemoryRegion source(&stack_masks_[i * stack_mask_bytes], stack_mask_bytes);
- BitMemoryRegion stack_mask = code_info.GetStackMask(i, encoding);
- for (size_t bit_index = 0; bit_index < stack_mask_bits; ++bit_index) {
- stack_mask.StoreBit(bit_index, source.LoadBit(bit_index));
+ BitMemoryRegion src(MemoryRegion(&stack_masks_[i * stack_mask_bytes], stack_mask_bytes));
+ BitMemoryRegion dst = code_info.GetStackMask(i, encoding);
+ for (size_t bit_index = 0; bit_index < stack_mask_bits; bit_index += BitSizeOf<uint32_t>()) {
+ size_t num_bits = std::min<size_t>(stack_mask_bits - bit_index, BitSizeOf<uint32_t>());
+ dst.StoreBits(bit_index, src.LoadBits(bit_index, num_bits), num_bits);
}
}
}
@@ -600,8 +601,9 @@ size_t StackMapStream::PrepareStackMasks(size_t entry_size_in_bits) {
for (StackMapEntry& stack_map : stack_maps_) {
size_t index = dedup.size();
MemoryRegion stack_mask(stack_masks_.data() + index * byte_entry_size, byte_entry_size);
+ BitMemoryRegion stack_mask_bits(stack_mask);
for (size_t i = 0; i < entry_size_in_bits; i++) {
- stack_mask.StoreBit(i, stack_map.sp_mask != nullptr && stack_map.sp_mask->IsBitSet(i));
+ stack_mask_bits.StoreBit(i, stack_map.sp_mask != nullptr && stack_map.sp_mask->IsBitSet(i));
}
stack_map.stack_mask_index = dedup.emplace(stack_mask, index).first->second;
}