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
diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc
index 23511e5..92b1230 100644
--- a/compiler/dex/quick_compiler_callbacks.cc
+++ b/compiler/dex/quick_compiler_callbacks.cc
@@ -44,11 +44,14 @@
// 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 45456f2..6d22f95 100644
--- a/compiler/dex/quick_compiler_callbacks.h
+++ b/compiler/dex/quick_compiler_callbacks.h
@@ -26,48 +26,50 @@
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 18b54ee..b9c0314 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2900,6 +2900,14 @@
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 @@
}
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 @@
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 @@
}
// 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::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 d08d9d7..19fae69 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -106,6 +106,7 @@
// 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 @@
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 @@
// 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 c41d8fc..14f1f0b 100644
--- a/compiler/utils/atomic_dex_ref_map-inl.h
+++ b/compiler/utils/atomic_dex_ref_map-inl.h
@@ -54,6 +54,15 @@
}
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 2da4ffa..b02c9b6 100644
--- a/compiler/utils/atomic_dex_ref_map.h
+++ b/compiler/utils/atomic_dex_ref_map.h
@@ -46,6 +46,7 @@
// 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();