Always create IMT conflict tables when generating an image.
It is required by the runtime. Also remove obsolete code around forcing
array class initialization: we now always intialize in array classes in
ClassLinker::FinishArrayClassSetup.
Test: eng builds
Bug: 166327764
Change-Id: I2f2398a8ba60360588c089affc4a73897d9df97b
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index ef0677d..c08227a 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -851,6 +851,51 @@
}
}
+class CreateConflictTablesVisitor : public ClassVisitor {
+ public:
+ explicit CreateConflictTablesVisitor(VariableSizedHandleScope& hs)
+ : hs_(hs) {}
+
+ bool operator()(ObjPtr<mirror::Class> klass) override
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
+ return true;
+ }
+ // Collect handles since there may be thread suspension in future EnsureInitialized.
+ to_visit_.push_back(hs_.NewHandle(klass));
+ return true;
+ }
+
+ void FillAllIMTAndConflictTables() REQUIRES_SHARED(Locks::mutator_lock_) {
+ for (Handle<mirror::Class> c : to_visit_) {
+ // Create the conflict tables.
+ FillIMTAndConflictTables(c.Get());
+ }
+ }
+
+ private:
+ void FillIMTAndConflictTables(ObjPtr<mirror::Class> klass)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!klass->ShouldHaveImt()) {
+ return;
+ }
+ if (visited_classes_.find(klass) != visited_classes_.end()) {
+ return;
+ }
+ if (klass->HasSuperClass()) {
+ FillIMTAndConflictTables(klass->GetSuperClass());
+ }
+ if (!klass->IsTemp()) {
+ Runtime::Current()->GetClassLinker()->FillIMTAndConflictTables(klass);
+ }
+ visited_classes_.insert(klass);
+ }
+
+ VariableSizedHandleScope& hs_;
+ std::vector<Handle<mirror::Class>> to_visit_;
+ std::unordered_set<ObjPtr<mirror::Class>, HashObjPtr> visited_classes_;
+};
+
void CompilerDriver::PreCompile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings,
@@ -927,6 +972,15 @@
InitializeClasses(class_loader, dex_files, timings);
VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
}
+ {
+ // Create conflict tables, as the runtime expects boot image classes to
+ // always have their conflict tables filled.
+ ScopedObjectAccess soa(Thread::Current());
+ VariableSizedHandleScope hs(soa.Self());
+ CreateConflictTablesVisitor visitor(hs);
+ Runtime::Current()->GetClassLinker()->VisitClassesWithoutClassesLock(&visitor);
+ visitor.FillAllIMTAndConflictTables();
+ }
UpdateImageClasses(timings, image_classes);
VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString(false);
@@ -2623,56 +2677,6 @@
class_linker->MakeInitializedClassesVisiblyInitialized(Thread::Current(), /*wait=*/ true);
}
-class InitializeArrayClassesAndCreateConflictTablesVisitor : public ClassVisitor {
- public:
- explicit InitializeArrayClassesAndCreateConflictTablesVisitor(VariableSizedHandleScope& hs)
- : hs_(hs) {}
-
- bool operator()(ObjPtr<mirror::Class> klass) override
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
- return true;
- }
- if (klass->IsArrayClass()) {
- StackHandleScope<1> hs(Thread::Current());
- auto h_klass = hs.NewHandleWrapper(&klass);
- Runtime::Current()->GetClassLinker()->EnsureInitialized(hs.Self(), h_klass, true, true);
- }
- // Collect handles since there may be thread suspension in future EnsureInitialized.
- to_visit_.push_back(hs_.NewHandle(klass));
- return true;
- }
-
- void FillAllIMTAndConflictTables() REQUIRES_SHARED(Locks::mutator_lock_) {
- for (Handle<mirror::Class> c : to_visit_) {
- // Create the conflict tables.
- FillIMTAndConflictTables(c.Get());
- }
- }
-
- private:
- void FillIMTAndConflictTables(ObjPtr<mirror::Class> klass)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (!klass->ShouldHaveImt()) {
- return;
- }
- if (visited_classes_.find(klass) != visited_classes_.end()) {
- return;
- }
- if (klass->HasSuperClass()) {
- FillIMTAndConflictTables(klass->GetSuperClass());
- }
- if (!klass->IsTemp()) {
- Runtime::Current()->GetClassLinker()->FillIMTAndConflictTables(klass);
- }
- visited_classes_.insert(klass);
- }
-
- VariableSizedHandleScope& hs_;
- std::vector<Handle<mirror::Class>> to_visit_;
- std::unordered_set<ObjPtr<mirror::Class>, HashObjPtr> visited_classes_;
-};
-
void CompilerDriver::InitializeClasses(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings) {
@@ -2681,20 +2685,6 @@
CHECK(dex_file != nullptr);
InitializeClasses(class_loader, *dex_file, dex_files, timings);
}
- if (GetCompilerOptions().IsBootImage() ||
- GetCompilerOptions().IsBootImageExtension() ||
- GetCompilerOptions().IsAppImage()) {
- // Make sure that we call EnsureIntiailized on all the array classes to call
- // SetVerificationAttempted so that the access flags are set. If we do not do this they get
- // changed at runtime resulting in more dirty image pages.
- // Also create conflict tables.
- // Only useful if we are compiling an image.
- ScopedObjectAccess soa(Thread::Current());
- VariableSizedHandleScope hs(soa.Self());
- InitializeArrayClassesAndCreateConflictTablesVisitor visitor(hs);
- Runtime::Current()->GetClassLinker()->VisitClassesWithoutClassesLock(&visitor);
- visitor.FillAllIMTAndConflictTables();
- }
if (GetCompilerOptions().IsBootImage() || GetCompilerOptions().IsBootImageExtension()) {
// Prune garbage objects created during aborted transactions.
Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ true);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 059b09c..09fa99b 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7046,9 +7046,6 @@
&new_conflict,
&imt_data[0]);
}
- if (!klass->ShouldHaveImt()) {
- return;
- }
// Compare the IMT with the super class including the conflict methods. If they are equivalent,
// we can just use the same pointer.
ImTable* imt = nullptr;