Mark array classes as verification attempted

We now initialize all array classes in the compiler driver. This in
turn will ensure they are marked verified in the image. This
prevents dirty pages in the image since we would otherwise set the
flags in the zygote.

On BusinessCard:
Reduces shared dirty from 636k -> 432k for boot.art, and dirty pages
from 183 to 132.

Bug: 27906566

Change-Id: I99fcaffe2cb7f0235a1a0845bebc44e2dc94cbf0
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index d29d528..be149af 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2486,6 +2486,20 @@
   context.ForAll(0, dex_file.NumClassDefs(), &visitor, init_thread_count);
 }
 
+class InitializeArrayClassVisitor : public ClassVisitor {
+ public:
+  virtual bool operator()(mirror::Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
+    if (klass->IsArrayClass()) {
+      StackHandleScope<1> hs(Thread::Current());
+      Runtime::Current()->GetClassLinker()->EnsureInitialized(hs.Self(),
+                                                              hs.NewHandle(klass),
+                                                              true,
+                                                              true);
+    }
+    return true;
+  }
+};
+
 void CompilerDriver::InitializeClasses(jobject class_loader,
                                        const std::vector<const DexFile*>& dex_files,
                                        TimingLogger* timings) {
@@ -2494,6 +2508,14 @@
     CHECK(dex_file != nullptr);
     InitializeClasses(class_loader, *dex_file, dex_files, timings);
   }
+  {
+    // 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.
+    ScopedObjectAccess soa(Thread::Current());
+    InitializeArrayClassVisitor visitor;
+    Runtime::Current()->GetClassLinker()->VisitClasses(&visitor);
+  }
   if (IsBootImage()) {
     // Prune garbage objects created during aborted transactions.
     Runtime::Current()->GetHeap()->CollectGarbage(true);
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 7082c88..9808c3e 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -299,7 +299,9 @@
   // Mutually exclusive from whether or not each method is allowed to skip access checks.
   void SetVerificationAttempted() SHARED_REQUIRES(Locks::mutator_lock_) {
     uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
-    SetAccessFlags(flags | kAccVerificationAttempted);
+    if ((flags & kAccVerificationAttempted) == 0) {
+      SetAccessFlags(flags | kAccVerificationAttempted);
+    }
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>