ART: Use .bss section for dex cache arrays.

Change-Id: I5fd507973b56f6a662a02a8c1dd9ac4493fb7b36
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 7b410bf..a78a5b3 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -31,6 +31,7 @@
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
+#include "gc/space/image_space.h"
 #include "gc/space/space.h"
 #include "image_writer.h"
 #include "linker/relative_patcher.h"
@@ -43,6 +44,7 @@
 #include "safe_map.h"
 #include "scoped_thread_state_change.h"
 #include "handle_scope-inl.h"
+#include "utils/dex_cache_arrays_layout-inl.h"
 #include "verifier/method_verifier.h"
 
 namespace art {
@@ -143,6 +145,18 @@
   }
   size_ = offset;
 
+  if (!HasImage()) {
+    // Allocate space for app dex cache arrays in the .bss section.
+    size_t bss_start = RoundUp(size_, kPageSize);
+    size_t pointer_size = GetInstructionSetPointerSize(instruction_set);
+    bss_size_ = 0u;
+    for (const DexFile* dex_file : dex_files) {
+      dex_cache_arrays_offsets_.Put(dex_file, bss_start + bss_size_);
+      DexCacheArraysLayout layout(pointer_size, dex_file);
+      bss_size_ += layout.Size();
+    }
+  }
+
   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
   CHECK_EQ(compiler->IsImage(), image_writer_ != nullptr);
   CHECK_EQ(compiler->IsImage(),
@@ -655,10 +669,10 @@
       no_thread_suspension_(soa_.Self(), "OatWriter patching"),
       class_linker_(Runtime::Current()->GetClassLinker()),
       dex_cache_(nullptr) {
-    if (writer_->image_writer_ != nullptr) {
+    patched_code_.reserve(16 * KB);
+    if (writer_->HasImage()) {
       // If we're creating the image, the address space must be ready so that we can apply patches.
       CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
-      patched_code_.reserve(16 * KB);
     }
   }
 
@@ -841,24 +855,28 @@
   }
 
   uint32_t GetDexCacheOffset(const LinkerPatch& patch) SHARED_REQUIRES(Locks::mutator_lock_) {
-    if (writer_->image_writer_ != nullptr) {
+    if (writer_->HasImage()) {
       auto* element = writer_->image_writer_->GetDexCacheArrayElementImageAddress<const uint8_t*>(
               patch.TargetDexCacheDexFile(), patch.TargetDexCacheElementOffset());
       const uint8_t* oat_data = writer_->image_writer_->GetOatFileBegin() + file_offset_;
       return element - oat_data;
     } else {
-      LOG(FATAL) << "Unimplemented.";
-      UNREACHABLE();
+      size_t start = writer_->dex_cache_arrays_offsets_.Get(patch.TargetDexCacheDexFile());
+      return start + patch.TargetDexCacheElementOffset();
     }
   }
 
   void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
       SHARED_REQUIRES(Locks::mutator_lock_) {
-    // NOTE: Direct method pointers across oat files don't use linker patches. However, direct
-    // type pointers across oat files do. (TODO: Investigate why.)
-    if (writer_->image_writer_ != nullptr) {
+    if (writer_->HasImage()) {
       object = writer_->image_writer_->GetImageAddress(object);
+    } else {
+      // NOTE: We're using linker patches for app->boot references when the image can
+      // be relocated and therefore we need to emit .oat_patches. We're not using this
+      // for app->app references, so check that the object is in the image space.
+      DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace());
     }
+    // Note: We only patch targeting Objects in image which is in the low 4gb.
     uint32_t address = PointerToLowMemUInt32(object);
     DCHECK_LE(offset + 4, code->size());
     uint8_t* data = &(*code)[offset];
@@ -870,12 +888,17 @@
 
   void PatchMethodAddress(std::vector<uint8_t>* code, uint32_t offset, ArtMethod* method)
       SHARED_REQUIRES(Locks::mutator_lock_) {
-    // NOTE: Direct method pointers across oat files don't use linker patches. However, direct
-    // type pointers across oat files do. (TODO: Investigate why.)
-    if (writer_->image_writer_ != nullptr) {
+    if (writer_->HasImage()) {
       method = writer_->image_writer_->GetImageMethodAddress(method);
+    } else if (kIsDebugBuild) {
+      // NOTE: We're using linker patches for app->boot references when the image can
+      // be relocated and therefore we need to emit .oat_patches. We're not using this
+      // for app->app references, so check that the method is an image method.
+      gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
+      size_t method_offset = reinterpret_cast<const uint8_t*>(method) - image_space->Begin();
+      CHECK(image_space->GetImageHeader().GetMethodsSection().Contains(method_offset));
     }
-    // Note: We only patch ArtMethods to low 4gb since thats where the image is.
+    // Note: We only patch targeting ArtMethods in image which is in the low 4gb.
     uint32_t address = PointerToLowMemUInt32(method);
     DCHECK_LE(offset + 4, code->size());
     uint8_t* data = &(*code)[offset];
@@ -887,9 +910,11 @@
 
   void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
       SHARED_REQUIRES(Locks::mutator_lock_) {
-    uint32_t address = writer_->image_writer_ == nullptr ? target_offset :
-        PointerToLowMemUInt32(writer_->image_writer_->GetOatFileBegin() +
-                              writer_->oat_data_offset_ + target_offset);
+    uint32_t address = target_offset;
+    if (writer_->HasImage()) {
+      address = PointerToLowMemUInt32(writer_->image_writer_->GetOatFileBegin() +
+                                      writer_->oat_data_offset_ + target_offset);
+    }
     DCHECK_LE(offset + 4, code->size());
     uint8_t* data = &(*code)[offset];
     data[0] = address & 0xffu;