ART: Skip compiling redefined classes in apps
If for an app a class is defined in more than one dex file, skip
all classes after the first.
Bug: 16057120
Change-Id: Ifd71e6f462fd691ee23724a001190e9175988069
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index ed126ad..ba60743 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -597,7 +597,7 @@
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != nullptr);
- ResolveDexFile(class_loader, *dex_file, thread_pool, timings);
+ ResolveDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
}
}
@@ -1357,12 +1357,14 @@
jobject class_loader,
CompilerDriver* compiler,
const DexFile* dex_file,
+ const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool)
: index_(0),
class_linker_(class_linker),
class_loader_(class_loader),
compiler_(compiler),
dex_file_(dex_file),
+ dex_files_(dex_files),
thread_pool_(thread_pool) {}
ClassLinker* GetClassLinker() const {
@@ -1384,6 +1386,10 @@
return dex_file_;
}
+ const std::vector<const DexFile*>& GetDexFiles() const {
+ return dex_files_;
+ }
+
void ForAll(size_t begin, size_t end, Callback callback, size_t work_units) {
Thread* self = Thread::Current();
self->AssertNoPendingException();
@@ -1441,11 +1447,24 @@
const jobject class_loader_;
CompilerDriver* const compiler_;
const DexFile* const dex_file_;
+ const std::vector<const DexFile*>& dex_files_;
ThreadPool* const thread_pool_;
DISALLOW_COPY_AND_ASSIGN(ParallelCompilationManager);
};
+static bool SkipClassCheckClassPath(const char* descriptor, const DexFile& dex_file,
+ const std::vector<const DexFile*>& classpath) {
+ DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, classpath);
+ CHECK(pair.second != NULL);
+ if (pair.first != &dex_file) {
+ LOG(WARNING) << "Skipping class " << descriptor << " from " << dex_file.GetLocation()
+ << " previously found in " << pair.first->GetLocation();
+ return true;
+ }
+ return false;
+}
+
// Return true if the class should be skipped during compilation.
//
// The first case where we skip is for redundant class definitions in
@@ -1454,20 +1473,23 @@
// The second case where we skip is when an app bundles classes found
// in the boot classpath. Since at runtime we will select the class from
// the boot classpath, we ignore the one from the app.
+//
+// The third case is if the app itself has the class defined in multiple dex files. Then we skip
+// it if it is not the first occurrence.
static bool SkipClass(ClassLinker* class_linker, jobject class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
const DexFile::ClassDef& class_def) {
const char* descriptor = dex_file.GetClassDescriptor(class_def);
+
if (class_loader == NULL) {
- DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_linker->GetBootClassPath());
- CHECK(pair.second != NULL);
- if (pair.first != &dex_file) {
- LOG(WARNING) << "Skipping class " << descriptor << " from " << dex_file.GetLocation()
- << " previously found in " << pair.first->GetLocation();
- return true;
- }
- return false;
+ return SkipClassCheckClassPath(descriptor, dex_file, class_linker->GetBootClassPath());
}
- return class_linker->IsInBootClassPath(descriptor);
+
+ if (class_linker->IsInBootClassPath(descriptor)) {
+ return true;
+ }
+
+ return SkipClassCheckClassPath(descriptor, dex_file, dex_files);
}
// A fast version of SkipClass above if the class pointer is available
@@ -1525,7 +1547,7 @@
// definitions, since many of them many never be referenced by
// generated code.
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
- if (!SkipClass(class_linker, jclass_loader, dex_file, class_def)) {
+ if (!SkipClass(class_linker, jclass_loader, dex_file, manager->GetDexFiles(), class_def)) {
ScopedObjectAccess soa(self);
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
@@ -1632,13 +1654,15 @@
}
void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
// TODO: we could resolve strings here, although the string table is largely filled with class
// and method names.
- ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
+ ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
+ thread_pool);
if (IsImage()) {
// For images we resolve all types, such as array, whereas for applications just those with
// classdefs are resolved by ResolveClassFieldsAndMethods.
@@ -1655,7 +1679,7 @@
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
- VerifyDexFile(class_loader, *dex_file, thread_pool, timings);
+ VerifyDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
}
}
@@ -1707,10 +1731,12 @@
}
void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings) {
TimingLogger::ScopedTiming t("Verify Dex File", timings);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
+ ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
+ thread_pool);
context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
}
@@ -1800,10 +1826,12 @@
}
void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings) {
TimingLogger::ScopedTiming t("InitializeNoClinit", timings);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, thread_pool);
+ ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, dex_files,
+ thread_pool);
size_t thread_count;
if (IsImage()) {
// TODO: remove this when transactional mode supports multithreading.
@@ -1824,7 +1852,7 @@
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
- InitializeClasses(class_loader, *dex_file, thread_pool, timings);
+ InitializeClasses(class_loader, *dex_file, dex_files, thread_pool, timings);
}
}
@@ -1833,7 +1861,7 @@
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
- CompileDexFile(class_loader, *dex_file, thread_pool, timings);
+ CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
}
}
@@ -1843,7 +1871,7 @@
const DexFile& dex_file = *manager->GetDexFile();
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
ClassLinker* class_linker = manager->GetClassLinker();
- if (SkipClass(class_linker, jclass_loader, dex_file, class_def)) {
+ if (SkipClass(class_linker, jclass_loader, dex_file, manager->GetDexFiles(), class_def)) {
return;
}
ClassReference ref(&dex_file, class_def_index);
@@ -1912,10 +1940,11 @@
}
void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings) {
TimingLogger::ScopedTiming t("Compile Dex File", timings);
ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this,
- &dex_file, thread_pool);
+ &dex_file, dex_files, thread_pool);
context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);
}
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 6dae398..efedabf 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -658,12 +658,14 @@
ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void ResolveDexFile(jobject class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings);
void VerifyDexFile(jobject class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
@@ -671,6 +673,7 @@
ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void InitializeClasses(jobject class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
@@ -681,6 +684,7 @@
void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings);
void CompileDexFile(jobject class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,