ART: Use .bss section for dex cache arrays.

Change-Id: I5fd507973b56f6a662a02a8c1dd9ac4493fb7b36
diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h
index 9cfd2eb..ff9c0b3 100644
--- a/runtime/arch/instruction_set.h
+++ b/runtime/arch/instruction_set.h
@@ -107,6 +107,22 @@
   }
 }
 
+static inline bool IsValidInstructionSet(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+    case kArm64:
+    case kX86:
+    case kX86_64:
+    case kMips:
+    case kMips64:
+      return true;
+    case kNone:
+    default:
+      return false;
+  }
+}
+
 size_t GetInstructionSetAlignment(InstructionSet isa);
 
 static inline bool Is64BitInstructionSet(InstructionSet isa) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 02f2e0b..c91577a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1204,7 +1204,10 @@
   }
   DexCacheArraysLayout layout(image_pointer_size_, &dex_file);
   uint8_t* raw_arrays = nullptr;
-  if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u ||
+  if (dex_file.GetOatDexFile() != nullptr &&
+      dex_file.GetOatDexFile()->GetDexCacheArrays() != nullptr) {
+    raw_arrays = const_cast<uint8_t*>(dex_file.GetOatDexFile()->GetDexCacheArrays());
+  } else if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u ||
       dex_file.NumMethodIds() != 0u || dex_file.NumFieldIds() != 0u) {
     // NOTE: We "leak" the raw_arrays because we never destroy the dex cache.
     DCHECK(image_pointer_size_ == 4u || image_pointer_size_ == 8u);
diff --git a/runtime/image.cc b/runtime/image.cc
index 42b348a..192371f 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '1', '\0' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '2', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 5725b6f..5625499 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -134,6 +134,9 @@
   if (!IsAligned<kPageSize>(image_patch_delta_)) {
     return false;
   }
+  if (!IsValidInstructionSet(instruction_set_)) {
+    return false;
+  }
   return true;
 }
 
@@ -156,6 +159,9 @@
   if (!IsAligned<kPageSize>(image_patch_delta_)) {
     return "Image patch delta not page-aligned.";
   }
+  if (!IsValidInstructionSet(instruction_set_)) {
+    return StringPrintf("Invalid instruction set, %d.", static_cast<int>(instruction_set_));
+  }
   return "";
 }
 
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 6cbbce9..d931777 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -46,6 +46,7 @@
 #include "os.h"
 #include "runtime.h"
 #include "utils.h"
+#include "utils/dex_cache_arrays_layout-inl.h"
 #include "vmap_table.h"
 
 namespace art {
@@ -432,6 +433,8 @@
     return false;
   }
 
+  size_t pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet());
+  const uint8_t* dex_cache_arrays = bss_begin_;
   uint32_t dex_file_count = GetOatHeader().GetDexFileCount();
   oat_dex_files_storage_.reserve(dex_file_count);
   for (size_t i = 0; i < dex_file_count; i++) {
@@ -513,6 +516,22 @@
       return false;
     }
 
+    const uint8_t* current_dex_cache_arrays = nullptr;
+    if (dex_cache_arrays != nullptr) {
+      DexCacheArraysLayout layout(pointer_size, *header);
+      if (layout.Size() != 0u) {
+        if (static_cast<size_t>(bss_end_ - dex_cache_arrays) < layout.Size()) {
+          *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with "
+                                    "truncated dex cache arrays, %zd < %zd.",
+                                    GetLocation().c_str(), i, dex_file_location.c_str(),
+                                    static_cast<size_t>(bss_end_ - dex_cache_arrays), layout.Size());
+          return false;
+        }
+        current_dex_cache_arrays = dex_cache_arrays;
+        dex_cache_arrays += layout.Size();
+      }
+    }
+
     std::string canonical_location = DexFile::GetDexCanonicalLocation(dex_file_location.c_str());
 
     // Create the OatDexFile and add it to the owning container.
@@ -521,7 +540,8 @@
                                               canonical_location,
                                               dex_file_checksum,
                                               dex_file_pointer,
-                                              methods_offsets_pointer);
+                                              methods_offsets_pointer,
+                                              current_dex_cache_arrays);
     oat_dex_files_storage_.push_back(oat_dex_file);
 
     // Add the location and canonical location (if different) to the oat_dex_files_ table.
@@ -532,6 +552,15 @@
       oat_dex_files_.Put(canonical_key, oat_dex_file);
     }
   }
+
+  if (dex_cache_arrays != bss_end_) {
+    // We expect the bss section to be either empty (dex_cache_arrays and bss_end_
+    // both null) or contain just the dex cache arrays and nothing else.
+    *error_msg = StringPrintf("In oat file '%s' found unexpected bss size bigger by %zd bytes.",
+                              GetLocation().c_str(),
+                              static_cast<size_t>(bss_end_ - dex_cache_arrays));
+    return false;
+  }
   return true;
 }
 
@@ -634,13 +663,15 @@
                                 const std::string& canonical_dex_file_location,
                                 uint32_t dex_file_location_checksum,
                                 const uint8_t* dex_file_pointer,
-                                const uint32_t* oat_class_offsets_pointer)
+                                const uint32_t* oat_class_offsets_pointer,
+                                const uint8_t* dex_cache_arrays)
     : oat_file_(oat_file),
       dex_file_location_(dex_file_location),
       canonical_dex_file_location_(canonical_dex_file_location),
       dex_file_location_checksum_(dex_file_location_checksum),
       dex_file_pointer_(dex_file_pointer),
-      oat_class_offsets_pointer_(oat_class_offsets_pointer) {}
+      oat_class_offsets_pointer_(oat_class_offsets_pointer),
+      dex_cache_arrays_(dex_cache_arrays) {}
 
 OatFile::OatDexFile::~OatDexFile() {}
 
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 364b734..34f0141 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -396,6 +396,10 @@
   // Returns the offset to the OatClass information. Most callers should use GetOatClass.
   uint32_t GetOatClassOffset(uint16_t class_def_index) const;
 
+  const uint8_t* GetDexCacheArrays() const {
+    return dex_cache_arrays_;
+  }
+
   ~OatDexFile();
 
  private:
@@ -404,7 +408,8 @@
              const std::string& canonical_dex_file_location,
              uint32_t dex_file_checksum,
              const uint8_t* dex_file_pointer,
-             const uint32_t* oat_class_offsets_pointer);
+             const uint32_t* oat_class_offsets_pointer,
+             const uint8_t* dex_cache_arrays);
 
   const OatFile* const oat_file_;
   const std::string dex_file_location_;
@@ -412,6 +417,7 @@
   const uint32_t dex_file_location_checksum_;
   const uint8_t* const dex_file_pointer_;
   const uint32_t* const oat_class_offsets_pointer_;
+  const uint8_t* const dex_cache_arrays_;
 
   friend class OatFile;
   DISALLOW_COPY_AND_ASSIGN(OatDexFile);
diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h
index 4f662d5..90e24b9 100644
--- a/runtime/utils/dex_cache_arrays_layout-inl.h
+++ b/runtime/utils/dex_cache_arrays_layout-inl.h
@@ -27,20 +27,25 @@
 
 namespace art {
 
-inline DexCacheArraysLayout::DexCacheArraysLayout(size_t pointer_size, const DexFile* dex_file)
+inline DexCacheArraysLayout::DexCacheArraysLayout(size_t pointer_size,
+                                                  const DexFile::Header& header)
     : pointer_size_(pointer_size),
       /* types_offset_ is always 0u, so it's constexpr */
       methods_offset_(types_offset_ +
-                      RoundUp(TypesSize(dex_file->NumTypeIds()), MethodsAlignment())),
+                      RoundUp(TypesSize(header.type_ids_size_), MethodsAlignment())),
       strings_offset_(methods_offset_ +
-                      RoundUp(MethodsSize(dex_file->NumMethodIds()), StringsAlignment())),
+                      RoundUp(MethodsSize(header.method_ids_size_), StringsAlignment())),
       fields_offset_(strings_offset_ +
-                     RoundUp(StringsSize(dex_file->NumStringIds()), FieldsAlignment())),
+                     RoundUp(StringsSize(header.string_ids_size_), FieldsAlignment())),
       size_(fields_offset_ +
-            RoundUp(FieldsSize(dex_file->NumFieldIds()), Alignment())) {
+            RoundUp(FieldsSize(header.field_ids_size_), Alignment())) {
   DCHECK(ValidPointerSize(pointer_size)) << pointer_size;
 }
 
+inline DexCacheArraysLayout::DexCacheArraysLayout(size_t pointer_size, const DexFile* dex_file)
+    : DexCacheArraysLayout(pointer_size, dex_file->GetHeader()) {
+}
+
 inline size_t DexCacheArraysLayout::Alignment() const {
   // GcRoot<> alignment is 4, i.e. lower than or equal to the pointer alignment.
   static_assert(alignof(GcRoot<mirror::Class>) == 4, "Expecting alignof(GcRoot<>) == 4");
diff --git a/runtime/utils/dex_cache_arrays_layout.h b/runtime/utils/dex_cache_arrays_layout.h
index d50be5a..cd84460 100644
--- a/runtime/utils/dex_cache_arrays_layout.h
+++ b/runtime/utils/dex_cache_arrays_layout.h
@@ -17,6 +17,8 @@
 #ifndef ART_RUNTIME_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_
 #define ART_RUNTIME_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_
 
+#include "dex_file.h"
+
 namespace art {
 
 /**
@@ -36,6 +38,9 @@
         size_(0u) {
   }
 
+  // Construct a layout for a particular dex file header.
+  DexCacheArraysLayout(size_t pointer_size, const DexFile::Header& header);
+
   // Construct a layout for a particular dex file.
   DexCacheArraysLayout(size_t pointer_size, const DexFile* dex_file);