From eb0ebed72432b3c6b8c7b38f8937d7ba736f4567 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Wed, 10 Jan 2018 18:26:38 +0000 Subject: Compiler changes for bitstring based type checks. We guard the use of this feature with a compile-time flag, set to true in this CL. Boot image size for aosp_taimen-userdebug in AOSP master: - before: arm boot*.oat: 63604740 arm64 boot*.oat: 74237864 - after: arm boot*.oat: 63531172 (-72KiB, -0.1%) arm64 boot*.oat: 74135008 (-100KiB, -0.1%) The new TypeCheckBenchmark yields the following changes using the little cores of taimen fixed at 1.4016GHz: 32-bit 64-bit timeCheckCastLevel1ToLevel1 11.48->15.80 11.47->15.78 timeCheckCastLevel2ToLevel1 15.08->15.79 15.08->15.79 timeCheckCastLevel3ToLevel1 19.01->15.82 17.94->15.81 timeCheckCastLevel9ToLevel1 42.55->15.79 42.63->15.81 timeCheckCastLevel9ToLevel2 39.70->14.36 39.70->14.35 timeInstanceOfLevel1ToLevel1 13.74->17.93 13.76->17.95 timeInstanceOfLevel2ToLevel1 17.02->17.95 16.99->17.93 timeInstanceOfLevel3ToLevel1 24.03->17.95 24.45->17.95 timeInstanceOfLevel9ToLevel1 47.13->17.95 47.14->18.00 timeInstanceOfLevel9ToLevel2 44.19->16.52 44.27->16.51 This suggests that the bitstring typecheck should not be used for exact type checks which would be equivalent to the "Level1ToLevel1" benchmark. Whether the implementation is a beneficial replacement for the kClassHierarchyCheck and kAbstractClassCheck on average depends on how many levels from the target class (or Object for a negative result) is a typical object's class. Test: m test-art-host-gtest Test: testrunner.py --host --optimizing --jit Test: testrunner.py --host -t 670-bitstring-type-check Test: Pixel 2 XL boots. Test: testrunner.py --target --optimizing --jit Test: testrunner.py --target -t 670-bitstring-type-check Bug: 64692057 Bug: 71853552 Bug: 26687569 Change-Id: I538d7e036b5a8ae2cc3fe77662a5903d74854562 --- compiler/optimizing/graph_visualizer.cc | 45 +++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 13 deletions(-) (limited to 'compiler/optimizing/graph_visualizer.cc') diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 12c69889ab..55191214a6 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -389,16 +389,23 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { StartAttributeStream("load_kind") << load_string->GetLoadKind(); } - void VisitCheckCast(HCheckCast* check_cast) OVERRIDE { - StartAttributeStream("check_kind") << check_cast->GetTypeCheckKind(); + void HandleTypeCheckInstruction(HTypeCheckInstruction* check) { + StartAttributeStream("check_kind") << check->GetTypeCheckKind(); StartAttributeStream("must_do_null_check") << std::boolalpha - << check_cast->MustDoNullCheck() << std::noboolalpha; + << check->MustDoNullCheck() << std::noboolalpha; + if (check->GetTypeCheckKind() == TypeCheckKind::kBitstringCheck) { + StartAttributeStream("path_to_root") << std::hex + << "0x" << check->GetBitstringPathToRoot() << std::dec; + StartAttributeStream("mask") << std::hex << "0x" << check->GetBitstringMask() << std::dec; + } + } + + void VisitCheckCast(HCheckCast* check_cast) OVERRIDE { + HandleTypeCheckInstruction(check_cast); } void VisitInstanceOf(HInstanceOf* instance_of) OVERRIDE { - StartAttributeStream("check_kind") << instance_of->GetTypeCheckKind(); - StartAttributeStream("must_do_null_check") << std::boolalpha - << instance_of->MustDoNullCheck() << std::noboolalpha; + HandleTypeCheckInstruction(instance_of); } void VisitArrayLength(HArrayLength* array_length) OVERRIDE { @@ -648,20 +655,32 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { << std::boolalpha << loop_info->IsIrreducible() << std::noboolalpha; } + // For the builder and the inliner, we want to add extra information on HInstructions + // that have reference types, and also HInstanceOf/HCheckcast. if ((IsPass(HGraphBuilder::kBuilderPassName) || IsPass(HInliner::kInlinerPassName)) - && (instruction->GetType() == DataType::Type::kReference)) { - ReferenceTypeInfo info = instruction->IsLoadClass() - ? instruction->AsLoadClass()->GetLoadedClassRTI() - : instruction->GetReferenceTypeInfo(); + && (instruction->GetType() == DataType::Type::kReference || + instruction->IsInstanceOf() || + instruction->IsCheckCast())) { + ReferenceTypeInfo info = (instruction->GetType() == DataType::Type::kReference) + ? instruction->IsLoadClass() + ? instruction->AsLoadClass()->GetLoadedClassRTI() + : instruction->GetReferenceTypeInfo() + : instruction->IsInstanceOf() + ? instruction->AsInstanceOf()->GetTargetClassRTI() + : instruction->AsCheckCast()->GetTargetClassRTI(); ScopedObjectAccess soa(Thread::Current()); if (info.IsValid()) { StartAttributeStream("klass") << mirror::Class::PrettyDescriptor(info.GetTypeHandle().Get()); - StartAttributeStream("can_be_null") - << std::boolalpha << instruction->CanBeNull() << std::noboolalpha; + if (instruction->GetType() == DataType::Type::kReference) { + StartAttributeStream("can_be_null") + << std::boolalpha << instruction->CanBeNull() << std::noboolalpha; + } StartAttributeStream("exact") << std::boolalpha << info.IsExact() << std::noboolalpha; - } else if (instruction->IsLoadClass()) { + } else if (instruction->IsLoadClass() || + instruction->IsInstanceOf() || + instruction->IsCheckCast()) { StartAttributeStream("klass") << "unresolved"; } else { // The NullConstant may be added to the graph during other passes that happen between -- cgit v1.2.3