diff options
author | 2017-09-11 14:15:52 +0100 | |
---|---|---|
committer | 2017-09-15 12:45:28 +0100 | |
commit | 486dda03900a215650f71a9068759978aa77c699 (patch) | |
tree | 1f2a1331d3ec474c979db5f9a35dd11f453abc25 | |
parent | b072ec25f8a71420ee77b068a28a2669420f6150 (diff) |
Add support for registering classpath classes status.
By doing class unloading after each dex file compilation, we are loosing
away verification done on classpath classes.
This change introduces a new table for keeping around class status of
classpath classes.
Multidex quickening compilation improved by ~5% by not re-verifying classpath
classes.
Bug: 63467744
test: test.py
test: golem successfully compiles FB
Change-Id: I629c0a7d86519bbc516f5e59f7cd92ca6ca842eb
-rw-r--r-- | compiler/dex/quick_compiler_callbacks.cc | 11 | ||||
-rw-r--r-- | compiler/dex/quick_compiler_callbacks.h | 66 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 34 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 3 | ||||
-rw-r--r-- | compiler/utils/atomic_dex_ref_map-inl.h | 9 | ||||
-rw-r--r-- | compiler/utils/atomic_dex_ref_map.h | 1 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 24 | ||||
-rw-r--r-- | runtime/class_linker.cc | 6 | ||||
-rw-r--r-- | runtime/compiler_callbacks.h | 3 |
9 files changed, 90 insertions, 67 deletions
diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc index 23511e55fc..92b123013d 100644 --- a/compiler/dex/quick_compiler_callbacks.cc +++ b/compiler/dex/quick_compiler_callbacks.cc @@ -44,11 +44,14 @@ ClassStatus QuickCompilerCallbacks::GetPreviousClassState(ClassReference ref) { // In the case of the quicken filter: avoiding verification of quickened instructions, which the // verifier doesn't currently support. // In the case of the verify filter, avoiding verifiying twice. - ClassStatus status; - if (!compiler_driver_->GetCompiledClass(ref, &status)) { - return ClassStatus::kStatusNotReady; + return compiler_driver_->GetClassStatus(ref); +} + +void QuickCompilerCallbacks::UpdateClassState(ClassReference ref, ClassStatus status) { + // Driver is null when bootstrapping the runtime. + if (compiler_driver_ != nullptr) { + compiler_driver_->RecordClassStatus(ref, status); } - return status; } } // namespace art diff --git a/compiler/dex/quick_compiler_callbacks.h b/compiler/dex/quick_compiler_callbacks.h index 45456f2a1c..6d22f955a3 100644 --- a/compiler/dex/quick_compiler_callbacks.h +++ b/compiler/dex/quick_compiler_callbacks.h @@ -26,48 +26,50 @@ class CompilerDriver; class VerificationResults; class QuickCompilerCallbacks FINAL : public CompilerCallbacks { - public: - explicit QuickCompilerCallbacks(CompilerCallbacks::CallbackMode mode) - : CompilerCallbacks(mode) {} + public: + explicit QuickCompilerCallbacks(CompilerCallbacks::CallbackMode mode) + : CompilerCallbacks(mode) {} - ~QuickCompilerCallbacks() { } + ~QuickCompilerCallbacks() { } - void MethodVerified(verifier::MethodVerifier* verifier) - REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE; + void MethodVerified(verifier::MethodVerifier* verifier) + REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE; - void ClassRejected(ClassReference ref) OVERRIDE; + void ClassRejected(ClassReference ref) OVERRIDE; - // We are running in an environment where we can call patchoat safely so we should. - bool IsRelocationPossible() OVERRIDE { - return true; - } + // We are running in an environment where we can call patchoat safely so we should. + bool IsRelocationPossible() OVERRIDE { + return true; + } - verifier::VerifierDeps* GetVerifierDeps() const OVERRIDE { - return verifier_deps_.get(); - } + verifier::VerifierDeps* GetVerifierDeps() const OVERRIDE { + return verifier_deps_.get(); + } - void SetVerifierDeps(verifier::VerifierDeps* deps) OVERRIDE { - verifier_deps_.reset(deps); - } + void SetVerifierDeps(verifier::VerifierDeps* deps) OVERRIDE { + verifier_deps_.reset(deps); + } - void SetVerificationResults(VerificationResults* verification_results) { - verification_results_ = verification_results; - } + void SetVerificationResults(VerificationResults* verification_results) { + verification_results_ = verification_results; + } - ClassStatus GetPreviousClassState(ClassReference ref) OVERRIDE; + ClassStatus GetPreviousClassState(ClassReference ref) OVERRIDE; - void SetDoesClassUnloading(bool does_class_unloading, CompilerDriver* compiler_driver) - OVERRIDE { - does_class_unloading_ = does_class_unloading; - compiler_driver_ = compiler_driver; - DCHECK(!does_class_unloading || compiler_driver_ != nullptr); - } + void SetDoesClassUnloading(bool does_class_unloading, CompilerDriver* compiler_driver) + OVERRIDE { + does_class_unloading_ = does_class_unloading; + compiler_driver_ = compiler_driver; + DCHECK(!does_class_unloading || compiler_driver_ != nullptr); + } - private: - VerificationResults* verification_results_ = nullptr; - bool does_class_unloading_ = false; - CompilerDriver* compiler_driver_ = nullptr; - std::unique_ptr<verifier::VerifierDeps> verifier_deps_; + void UpdateClassState(ClassReference ref, ClassStatus state) OVERRIDE; + + private: + VerificationResults* verification_results_ = nullptr; + bool does_class_unloading_ = false; + CompilerDriver* compiler_driver_ = nullptr; + std::unique_ptr<verifier::VerifierDeps> verifier_deps_; }; } // namespace art diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 18b54eefba..b9c0314cb1 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2900,6 +2900,14 @@ bool CompilerDriver::GetCompiledClass(ClassReference ref, mirror::Class::Status* return true; } +mirror::Class::Status CompilerDriver::GetClassStatus(ClassReference ref) const { + mirror::Class::Status status = ClassStatus::kStatusNotReady; + if (!GetCompiledClass(ref, &status)) { + classpath_classes_.Get(DexFileReference(ref.first, ref.second), &status); + } + return status; +} + void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status status) { switch (status) { case mirror::Class::kStatusErrorResolved: @@ -2918,11 +2926,12 @@ void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status } ClassStateTable::InsertResult result; + ClassStateTable* table = &compiled_classes_; do { DexFileReference dex_ref(ref.first, ref.second); mirror::Class::Status existing = mirror::Class::kStatusNotReady; - if (!compiled_classes_.Get(dex_ref, &existing)) { - // Probably a uses library class, bail. + if (!table->Get(dex_ref, &existing)) { + // A classpath class. if (kIsDebugBuild) { // Check to make sure it's not a dex file for an oat file we are compiling since these // should always succeed. These do not include classes in for used libraries. @@ -2930,7 +2939,12 @@ void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status CHECK_NE(dex_ref.dex_file, dex_file) << dex_ref.dex_file->GetLocation(); } } - return; + if (!classpath_classes_.HaveDexFile(ref.first)) { + // Boot classpath dex file. + return; + } + table = &classpath_classes_; + table->Get(dex_ref, &existing); } if (existing >= status) { // Existing status is already better than we expect, break. @@ -2938,8 +2952,8 @@ void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status } // Update the status if we now have a greater one. This happens with vdex, // which records a class is verified, but does not resolve it. - result = compiled_classes_.Insert(dex_ref, existing, status); - CHECK(result != ClassStateTable::kInsertResultInvalidDexFile); + result = table->Insert(dex_ref, existing, status); + CHECK(result != ClassStateTable::kInsertResultInvalidDexFile) << ref.first->GetLocation(); } while (result != ClassStateTable::kInsertResultSuccess); } @@ -3046,11 +3060,11 @@ void CompilerDriver::FreeThreadPools() { void CompilerDriver::SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files) { dex_files_for_oat_file_ = dex_files; - for (const DexFile* dex_file : dex_files) { - if (!compiled_classes_.HaveDexFile(dex_file)) { - compiled_classes_.AddDexFile(dex_file, dex_file->NumClassDefs()); - } - } + compiled_classes_.AddDexFiles(dex_files); +} + +void CompilerDriver::SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files) { + classpath_classes_.AddDexFiles(dex_files); } } // namespace art diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index d08d9d7940..19fae695b5 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -106,6 +106,7 @@ class CompilerDriver { // Set dex files that will be stored in the oat file after being compiled. void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files); + void SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files); // Get dex file that will be stored in the oat file after being compiled. ArrayRef<const DexFile* const> GetDexFilesForOatFile() const { @@ -152,6 +153,7 @@ class CompilerDriver { std::unique_ptr<const std::vector<uint8_t>> CreateQuickToInterpreterBridge() const; bool GetCompiledClass(ClassReference ref, mirror::Class::Status* status) const; + mirror::Class::Status GetClassStatus(ClassReference ref) const; CompiledMethod* GetCompiledMethod(MethodReference ref) const; size_t GetNonRelativeLinkerPatchCount() const; @@ -488,6 +490,7 @@ class CompilerDriver { // All class references that this compiler has compiled. Indexed by class defs. using ClassStateTable = AtomicDexRefMap<mirror::Class::Status>; ClassStateTable compiled_classes_; + ClassStateTable classpath_classes_; typedef AtomicDexRefMap<CompiledMethod*> MethodTable; diff --git a/compiler/utils/atomic_dex_ref_map-inl.h b/compiler/utils/atomic_dex_ref_map-inl.h index c41d8fc071..14f1f0b981 100644 --- a/compiler/utils/atomic_dex_ref_map-inl.h +++ b/compiler/utils/atomic_dex_ref_map-inl.h @@ -54,6 +54,15 @@ inline void AtomicDexRefMap<T>::AddDexFile(const DexFile* dex_file, size_t max_i } template <typename T> +inline void AtomicDexRefMap<T>::AddDexFiles(const std::vector<const DexFile*>& dex_files) { + for (const DexFile* dex_file : dex_files) { + if (!HaveDexFile(dex_file)) { + AddDexFile(dex_file, dex_file->NumClassDefs()); + } + } +} + +template <typename T> inline typename AtomicDexRefMap<T>::ElementArray* AtomicDexRefMap<T>::GetArray( const DexFile* dex_file) { auto it = arrays_.find(dex_file); diff --git a/compiler/utils/atomic_dex_ref_map.h b/compiler/utils/atomic_dex_ref_map.h index 2da4ffa27b..b02c9b634e 100644 --- a/compiler/utils/atomic_dex_ref_map.h +++ b/compiler/utils/atomic_dex_ref_map.h @@ -46,6 +46,7 @@ class AtomicDexRefMap { // Dex files must be added before method references belonging to them can be used as keys. Not // thread safe. void AddDexFile(const DexFile* dex_file, size_t max_index); + void AddDexFiles(const std::vector<const DexFile*>& dex_files); bool HaveDexFile(const DexFile* dex_file) const { return arrays_.find(dex_file) != arrays_.end(); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 7ba165e2cb..4ecb04389f 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1865,6 +1865,9 @@ class Dex2Oat FINAL { swap_fd_, profile_compilation_info_.get())); driver_->SetDexFilesForOatFile(dex_files_); + if (!IsBootImage()) { + driver_->SetClasspathDexFiles(class_loader_context_->FlattenOpenedDexFiles()); + } const bool compile_individually = ShouldCompileDexFilesIndividually(); if (compile_individually) { @@ -2363,27 +2366,6 @@ class Dex2Oat FINAL { return dex_files_size >= very_large_threshold_; } - std::vector<std::string> GetClassPathLocations(const std::string& class_path) { - // This function is used only for apps and for an app we have exactly one oat file. - DCHECK(!IsBootImage()); - DCHECK_EQ(oat_writers_.size(), 1u); - std::vector<std::string> dex_files_canonical_locations; - for (const std::string& location : oat_writers_[0]->GetSourceLocations()) { - dex_files_canonical_locations.push_back(DexFile::GetDexCanonicalLocation(location.c_str())); - } - - std::vector<std::string> parsed; - Split(class_path, ':', &parsed); - auto kept_it = std::remove_if(parsed.begin(), - parsed.end(), - [dex_files_canonical_locations](const std::string& location) { - return ContainsElement(dex_files_canonical_locations, - DexFile::GetDexCanonicalLocation(location.c_str())); - }); - parsed.erase(kept_it, parsed.end()); - return parsed; - } - bool PrepareImageClasses() { // If --image-classes was specified, calculate the full list of classes to include in the image. if (image_classes_filename_ != nullptr) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index f95b493abb..c48fccaaa9 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4309,6 +4309,12 @@ verifier::FailureKind ClassLinker::VerifyClass( EnsureSkipAccessChecksMethods(klass, image_pointer_size_); } } + // Done verifying. Notify the compiler about the verification status, in case the class + // was verified implicitly (eg super class of a compiled class). + if (Runtime::Current()->IsAotCompiler()) { + Runtime::Current()->GetCompilerCallbacks()->UpdateClassState( + ClassReference(&klass->GetDexFile(), klass->GetDexClassDefIndex()), klass->GetStatus()); + } return verifier_failure; } diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h index 9b227141e0..9041df94b9 100644 --- a/runtime/compiler_callbacks.h +++ b/runtime/compiler_callbacks.h @@ -65,6 +65,9 @@ class CompilerCallbacks { return mode_ == CallbackMode::kCompileBootImage; } + virtual void UpdateClassState(ClassReference ref ATTRIBUTE_UNUSED, + ClassStatus state ATTRIBUTE_UNUSED) {} + protected: explicit CompilerCallbacks(CallbackMode mode) : mode_(mode) { } |