Reduce number of physical pages used for DexCache's arrays

This commit reduces the amount of physical pages allocated for the .bss
section of an application's oat file.
Many of elements in the application's DexCache arrays are empty.
But during coping content of the DexCaches arrays from
the app's art file into the .bss section all pages become dirty.
The commit fixes that by copying non null elements only. So pages
in the .bss section that contains zeroes remains untouched.
This approach allows to save 209Kb of memory after one minute of
GMaps use.
This number is the difference between the size of .bss section and
the Rss value from the /proc/<pid>/smaps file.

Test: run test-art-host

Change-Id: I3d7bed0805b95b5f344303581274ca8e8e69940e
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 439849b..4e077c0 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1239,6 +1239,20 @@
   gc::accounting::HeapBitmap* const live_bitmap_;
 };
 
+// Copies data from one array to another array at the same position
+// if pred returns false. If there is a page of continuous data in
+// the src array for which pred consistently returns true then
+// corresponding page in the dst array will not be touched.
+// This should reduce number of allocated physical pages.
+template <class T, class NullPred>
+static void CopyNonNull(const T* src, size_t count, T* dst, const NullPred& pred) {
+  for (size_t i = 0; i < count; ++i) {
+    if (!pred(src[i])) {
+      dst[i] = src[i];
+    }
+  }
+}
+
 bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches(
     gc::space::ImageSpace* space,
     Handle<mirror::ClassLoader> class_loader,
@@ -1330,7 +1344,12 @@
           for (size_t j = 0; kIsDebugBuild && j < num_types; ++j) {
             DCHECK(types[j].IsNull());
           }
-          std::copy_n(image_resolved_types, num_types, types);
+          CopyNonNull(image_resolved_types,
+                      num_types,
+                      types,
+                      [](const GcRoot<mirror::Class>& elem) {
+                          return elem.IsNull();
+                      });
           dex_cache->SetResolvedTypes(types);
         }
         if (num_methods != 0u) {
@@ -1340,7 +1359,12 @@
           for (size_t j = 0; kIsDebugBuild && j < num_methods; ++j) {
             DCHECK(methods[j] == nullptr);
           }
-          std::copy_n(image_resolved_methods, num_methods, methods);
+          CopyNonNull(image_resolved_methods,
+                      num_methods,
+                      methods,
+                      [] (const ArtMethod* method) {
+                          return method == nullptr;
+                      });
           dex_cache->SetResolvedMethods(methods);
         }
         if (num_fields != 0u) {
@@ -1349,7 +1373,12 @@
           for (size_t j = 0; kIsDebugBuild && j < num_fields; ++j) {
             DCHECK(fields[j] == nullptr);
           }
-          std::copy_n(dex_cache->GetResolvedFields(), num_fields, fields);
+          CopyNonNull(dex_cache->GetResolvedFields(),
+                      num_fields,
+                      fields,
+                      [] (const ArtField* field) {
+                          return field == nullptr;
+                      });
           dex_cache->SetResolvedFields(fields);
         }
         if (num_method_types != 0u) {