Optimize OatWriter when we don't compile any method.
- Don't write any quickening info.
- Don't visit methods.
Saves ~20% of compilation times.
Test: test-art-host
Change-Id: Ib18fd06c0ca42308e1d81401de0ee3e6297de0ce
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index ec1642e..dfd04e3 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -423,7 +423,7 @@
// Compile:
// 1) Compile all classes and methods enabled for compilation. May fall back to dex-to-dex
// compilation.
- if (!GetCompilerOptions().VerifyAtRuntime() && !GetCompilerOptions().VerifyOnlyProfile()) {
+ if (GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
Compile(class_loader, dex_files, timings);
}
if (dump_stats_) {
@@ -494,11 +494,15 @@
// TODO: we unquicken unconditionnally, as we don't know
// if the boot image has changed. How exactly we'll know is under
// experimentation.
- TimingLogger::ScopedTiming t("Unquicken", timings);
- // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
- // optimization does not depend on the boot image (the optimization relies on not
- // having final fields in a class, which does not change for an app).
- Unquicken(dex_files, vdex_file->GetQuickeningInfo(), /* decompile_return_instruction */ false);
+ if (vdex_file->GetQuickeningInfo().size() != 0) {
+ TimingLogger::ScopedTiming t("Unquicken", timings);
+ // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
+ // optimization does not depend on the boot image (the optimization relies on not
+ // having final fields in a class, which does not change for an app).
+ Unquicken(dex_files,
+ vdex_file->GetQuickeningInfo(),
+ /* decompile_return_instruction */ false);
+ }
Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
new verifier::VerifierDeps(dex_files, vdex_file->GetVerifierDepsData()));
}
@@ -510,10 +514,7 @@
const DexFile& dex_file, const DexFile::ClassDef& class_def)
REQUIRES_SHARED(Locks::mutator_lock_) {
auto* const runtime = Runtime::Current();
- if (runtime->UseJitCompilation() || driver.GetCompilerOptions().VerifyAtRuntime()) {
- // Verify at runtime shouldn't dex to dex since we didn't resolve of verify.
- return optimizer::DexToDexCompilationLevel::kDontDexToDexCompile;
- }
+ DCHECK(driver.GetCompilerOptions().IsAnyMethodCompilationEnabled());
const char* descriptor = dex_file.GetClassDescriptor(class_def);
ClassLinker* class_linker = runtime->GetClassLinker();
mirror::Class* klass = class_linker->FindClass(self, descriptor, class_loader);
@@ -954,24 +955,17 @@
LoadImageClasses(timings);
VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false);
- const bool verification_enabled = compiler_options_->IsVerificationEnabled();
- const bool never_verify = compiler_options_->NeverVerify();
- const bool verify_only_profile = compiler_options_->VerifyOnlyProfile();
-
- // We need to resolve for never_verify since it needs to run dex to dex to add the
- // RETURN_VOID_NO_BARRIER.
- // Let the verifier resolve as needed for the verify_only_profile case.
- if ((never_verify || verification_enabled) && !verify_only_profile) {
+ if (compiler_options_->IsAnyMethodCompilationEnabled()) {
Resolve(class_loader, dex_files, timings);
VLOG(compiler) << "Resolve: " << GetMemoryUsageString(false);
}
- if (never_verify) {
+ if (compiler_options_->AssumeClassesAreVerified()) {
VLOG(compiler) << "Verify none mode specified, skipping verification.";
SetVerified(class_loader, dex_files, timings);
}
- if (!verification_enabled) {
+ if (!compiler_options_->IsVerificationEnabled()) {
return;
}
@@ -989,7 +983,7 @@
<< "situations. Please check the log.";
}
- if (!verify_only_profile) {
+ if (compiler_options_->IsAnyMethodCompilationEnabled()) {
InitializeClasses(class_loader, dex_files, timings);
VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
}
@@ -2069,7 +2063,7 @@
for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
if (set.find(class_def.class_idx_) == set.end()) {
- if (GetCompilerOptions().VerifyOnlyProfile()) {
+ if (!GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
// Just update the compiled_classes_ map. The compiler doesn't need to resolve
// the type.
compiled_classes_.Overwrite(
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 9c62f80..6894cd5 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -109,7 +109,7 @@
return CompilerFilter::IsVerificationEnabled(compiler_filter_);
}
- bool NeverVerify() const {
+ bool AssumeClassesAreVerified() const {
return compiler_filter_ == CompilerFilter::kVerifyNone;
}
@@ -117,6 +117,10 @@
return compiler_filter_ == CompilerFilter::kVerifyProfile;
}
+ bool IsAnyMethodCompilationEnabled() const {
+ return CompilerFilter::IsAnyMethodCompilationEnabled(compiler_filter_);
+ }
+
size_t GetHugeMethodThreshold() const {
return huge_method_threshold_;
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index bebd5f5..2d4bbce 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -1468,30 +1468,32 @@
if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
return false;
}
- const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
- const uint8_t* class_data = dex_file->GetClassData(class_def);
- if (class_data != nullptr) { // ie not an empty class, such as a marker interface
- ClassDataItemIterator it(*dex_file, class_data);
- while (it.HasNextStaticField()) {
- it.Next();
- }
- while (it.HasNextInstanceField()) {
- it.Next();
- }
- size_t class_def_method_index = 0u;
- while (it.HasNextDirectMethod()) {
- if (!visitor->VisitMethod(class_def_method_index, it)) {
- return false;
+ if (compiler_driver_->GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+ const uint8_t* class_data = dex_file->GetClassData(class_def);
+ if (class_data != nullptr) { // ie not an empty class, such as a marker interface
+ ClassDataItemIterator it(*dex_file, class_data);
+ while (it.HasNextStaticField()) {
+ it.Next();
}
- ++class_def_method_index;
- it.Next();
- }
- while (it.HasNextVirtualMethod()) {
- if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
- return false;
+ while (it.HasNextInstanceField()) {
+ it.Next();
}
- ++class_def_method_index;
- it.Next();
+ size_t class_def_method_index = 0u;
+ while (it.HasNextDirectMethod()) {
+ if (!visitor->VisitMethod(class_def_method_index, it)) {
+ return false;
+ }
+ ++class_def_method_index;
+ it.Next();
+ }
+ while (it.HasNextVirtualMethod()) {
+ if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
+ return false;
+ }
+ ++class_def_method_index;
+ it.Next();
+ }
}
}
if (UNLIKELY(!visitor->EndClass())) {
@@ -1548,6 +1550,9 @@
}
size_t OatWriter::InitOatMaps(size_t offset) {
+ if (!compiler_driver_->GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+ return offset;
+ }
InitMapMethodVisitor visitor(this, offset);
bool success = VisitDexMethods(&visitor);
DCHECK(success);
@@ -1594,6 +1599,9 @@
}
size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
+ if (!compiler_driver_->GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+ return offset;
+ }
InitCodeMethodVisitor code_visitor(this, offset, vdex_quickening_info_offset_);
bool success = VisitDexMethods(&code_visitor);
DCHECK(success);
@@ -1745,19 +1753,24 @@
return false;
}
- WriteQuickeningInfoMethodVisitor visitor(this, vdex_out, start_offset);
- if (!VisitDexMethods(&visitor)) {
- PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
- return false;
+ if (compiler_driver_->GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+ WriteQuickeningInfoMethodVisitor visitor(this, vdex_out, start_offset);
+ if (!VisitDexMethods(&visitor)) {
+ PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
+ return false;
+ }
+
+ if (!vdex_out->Flush()) {
+ PLOG(ERROR) << "Failed to flush stream after writing quickening info."
+ << " File: " << vdex_out->GetLocation();
+ return false;
+ }
+ size_quickening_info_ = visitor.GetNumberOfWrittenBytes();
+ } else {
+ // We know we did not quicken.
+ size_quickening_info_ = 0;
}
- if (!vdex_out->Flush()) {
- PLOG(ERROR) << "Failed to flush stream after writing quickening info."
- << " File: " << vdex_out->GetLocation();
- return false;
- }
-
- size_quickening_info_ = visitor.GetNumberOfWrittenBytes();
vdex_size_ += size_quickening_info_;
return true;
}