diff options
author | 2016-02-11 21:39:41 +0000 | |
---|---|---|
committer | 2016-02-11 21:39:41 +0000 | |
commit | d3caabd4f85f86dd744da432993e12935d843a83 (patch) | |
tree | b7fb9f36c2725e78e0ba7f61fc8ff14c60666077 /compiler/optimizing | |
parent | d3df33e6c24e3cd62991b2a65833f16dc05a17b8 (diff) | |
parent | 86503785cd6414b8692e5c83cadaa2972b6a099b (diff) |
Merge "Fix x86-64 Baker's read barrier fast path for CheckCast."
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 75 | ||||
-rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 22 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 2 |
4 files changed, 90 insertions, 11 deletions
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 99396cd983..4f0f5f0ff8 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -5840,19 +5840,20 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { is_type_check_slow_path_fatal); codegen_->AddSlowPath(type_check_slow_path); - NearLabel done; - // Avoid null check if we know obj is not null. - if (instruction->MustDoNullCheck()) { - __ testl(obj, obj); - __ j(kEqual, &done); - } - - // /* HeapReference<Class> */ temp = obj->klass_ - GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc); - switch (type_check_kind) { case TypeCheckKind::kExactCheck: case TypeCheckKind::kArrayCheck: { + NearLabel done; + // Avoid null check if we know obj is not null. + if (instruction->MustDoNullCheck()) { + __ testl(obj, obj); + __ j(kEqual, &done); + } + + // /* HeapReference<Class> */ temp = obj->klass_ + GenerateReferenceLoadTwoRegisters( + instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc); + if (cls.IsRegister()) { __ cmpl(temp, cls.AsRegister<CpuRegister>()); } else { @@ -5862,10 +5863,22 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { // Jump to slow path for throwing the exception or doing a // more involved array check. __ j(kNotEqual, type_check_slow_path->GetEntryLabel()); + __ Bind(&done); break; } case TypeCheckKind::kAbstractClassCheck: { + NearLabel done; + // Avoid null check if we know obj is not null. + if (instruction->MustDoNullCheck()) { + __ testl(obj, obj); + __ j(kEqual, &done); + } + + // /* HeapReference<Class> */ temp = obj->klass_ + GenerateReferenceLoadTwoRegisters( + instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc); + // If the class is abstract, we eagerly fetch the super class of the // object to avoid doing a comparison we know will fail. NearLabel loop, compare_classes; @@ -5896,10 +5909,22 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex())); } __ j(kNotEqual, &loop); + __ Bind(&done); break; } case TypeCheckKind::kClassHierarchyCheck: { + NearLabel done; + // Avoid null check if we know obj is not null. + if (instruction->MustDoNullCheck()) { + __ testl(obj, obj); + __ j(kEqual, &done); + } + + // /* HeapReference<Class> */ temp = obj->klass_ + GenerateReferenceLoadTwoRegisters( + instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc); + // Walk over the class hierarchy to find a match. NearLabel loop; __ Bind(&loop); @@ -5927,10 +5952,26 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { GenerateReferenceLoadTwoRegisters( instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc); __ jmp(type_check_slow_path->GetEntryLabel()); + __ Bind(&done); break; } case TypeCheckKind::kArrayObjectCheck: { + // We cannot use a NearLabel here, as its range might be too + // short in some cases when read barriers are enabled. This has + // been observed for instance when the code emitted for this + // case uses high x86-64 registers (R8-R15). + Label done; + // Avoid null check if we know obj is not null. + if (instruction->MustDoNullCheck()) { + __ testl(obj, obj); + __ j(kEqual, &done); + } + + // /* HeapReference<Class> */ temp = obj->klass_ + GenerateReferenceLoadTwoRegisters( + instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc); + // Do an exact check. NearLabel check_non_primitive_component_type; if (cls.IsRegister()) { @@ -5969,11 +6010,23 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { GenerateReferenceLoadTwoRegisters( instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc); __ jmp(type_check_slow_path->GetEntryLabel()); + __ Bind(&done); break; } case TypeCheckKind::kUnresolvedCheck: case TypeCheckKind::kInterfaceCheck: + NearLabel done; + // Avoid null check if we know obj is not null. + if (instruction->MustDoNullCheck()) { + __ testl(obj, obj); + __ j(kEqual, &done); + } + + // /* HeapReference<Class> */ temp = obj->klass_ + GenerateReferenceLoadTwoRegisters( + instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc); + // We always go into the type check slow path for the unresolved // and interface check cases. // @@ -5992,9 +6045,9 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { // call to the runtime not using a type checking slow path). // This should also be beneficial for the other cases above. __ jmp(type_check_slow_path->GetEntryLabel()); + __ Bind(&done); break; } - __ Bind(&done); __ Bind(type_check_slow_path->GetExitLabel()); } diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 9d796c1004..63b8fd05c0 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -368,11 +368,13 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { } void VisitCheckCast(HCheckCast* check_cast) OVERRIDE { + StartAttributeStream("check_kind") << check_cast->GetTypeCheckKind(); StartAttributeStream("must_do_null_check") << std::boolalpha << check_cast->MustDoNullCheck() << std::noboolalpha; } void VisitInstanceOf(HInstanceOf* instance_of) OVERRIDE { + StartAttributeStream("check_kind") << instance_of->GetTypeCheckKind(); StartAttributeStream("must_do_null_check") << std::boolalpha << instance_of->MustDoNullCheck() << std::noboolalpha; } diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index f269885907..453571451c 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2387,4 +2387,26 @@ std::ostream& operator<<(std::ostream& os, const MoveOperands& rhs) { return os; } +std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs) { + switch (rhs) { + case TypeCheckKind::kUnresolvedCheck: + return os << "unresolved_check"; + case TypeCheckKind::kExactCheck: + return os << "exact_check"; + case TypeCheckKind::kClassHierarchyCheck: + return os << "class_hierarchy_check"; + case TypeCheckKind::kAbstractClassCheck: + return os << "abstract_class_check"; + case TypeCheckKind::kInterfaceCheck: + return os << "interface_check"; + case TypeCheckKind::kArrayObjectCheck: + return os << "array_object_check"; + case TypeCheckKind::kArrayCheck: + return os << "array_check"; + default: + LOG(FATAL) << "Unknown TypeCheckKind: " << static_cast<int>(rhs); + UNREACHABLE(); + } +} + } // namespace art diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index daec096f3e..7f463a36e9 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -5451,6 +5451,8 @@ enum class TypeCheckKind { kArrayCheck // No optimization yet when checking against a generic array. }; +std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs); + class HInstanceOf : public HExpression<2> { public: HInstanceOf(HInstruction* object, |