OSDN Git Service

ART: Use .bss section for dex cache arrays.
authorVladimir Marko <vmarko@google.com>
Tue, 8 Sep 2015 12:47:48 +0000 (13:47 +0100)
committerVladimir Marko <vmarko@google.com>
Thu, 15 Oct 2015 15:46:41 +0000 (16:46 +0100)
Change-Id: I5fd507973b56f6a662a02a8c1dd9ac4493fb7b36

compiler/oat_writer.cc
compiler/oat_writer.h
runtime/arch/instruction_set.h
runtime/class_linker.cc
runtime/image.cc
runtime/oat.cc
runtime/oat_file.cc
runtime/oat_file.h
runtime/utils/dex_cache_arrays_layout-inl.h
runtime/utils/dex_cache_arrays_layout.h

index 7b410bf..a78a5b3 100644 (file)
@@ -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 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
   }
   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 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
       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 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
   }
 
   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 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
 
   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 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
 
   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;
index 48fbc0b..a82d09e 100644 (file)
@@ -90,6 +90,13 @@ class OatWriter {
             TimingLogger* timings,
             SafeMap<std::string, std::string>* key_value_store);
 
+  // Returns whether the oat file has an associated image.
+  bool HasImage() const {
+    // Since the image is being created at the same time as the oat file,
+    // check if there's an image writer.
+    return image_writer_ != nullptr;
+  }
+
   const OatHeader& GetOatHeader() const {
     return *oat_header_;
   }
@@ -272,6 +279,10 @@ class OatWriter {
   // The size of the required .bss section holding the DexCache data.
   size_t bss_size_;
 
+  // Offsets of the dex cache arrays for each app dex file. For the
+  // boot image, this information is provided by the ImageWriter.
+  SafeMap<const DexFile*, size_t> dex_cache_arrays_offsets_;
+
   // Offset of the oat data from the start of the mmapped region of the elf file.
   size_t oat_data_offset_;
 
index 9cfd2eb..ff9c0b3 100644 (file)
@@ -107,6 +107,22 @@ static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
   }
 }
 
+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) {
index 02f2e0b..c91577a 100644 (file)
@@ -1204,7 +1204,10 @@ mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_fi
   }
   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);
index 42b348a..192371f 100644 (file)
@@ -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,
index 5725b6f..5625499 100644 (file)
@@ -134,6 +134,9 @@ bool OatHeader::IsValid() const {
   if (!IsAligned<kPageSize>(image_patch_delta_)) {
     return false;
   }
+  if (!IsValidInstructionSet(instruction_set_)) {
+    return false;
+  }
   return true;
 }
 
@@ -156,6 +159,9 @@ std::string OatHeader::GetValidationErrorMessage() const {
   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 "";
 }
 
index 6cbbce9..d931777 100644 (file)
@@ -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 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) {
     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 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) {
       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 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) {
                                               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 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) {
       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 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
                                 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() {}
 
index 364b734..34f0141 100644 (file)
@@ -396,6 +396,10 @@ class OatDexFile FINAL {
   // 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 @@ class OatDexFile FINAL {
              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 @@ class OatDexFile FINAL {
   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);
index 4f662d5..90e24b9 100644 (file)
 
 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");
index d50be5a..cd84460 100644 (file)
@@ -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 @@ class DexCacheArraysLayout {
         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);