diff options
author | 2015-09-08 13:47:48 +0100 | |
---|---|---|
committer | 2015-10-15 16:46:41 +0100 | |
commit | 09d0943f5efe92c1f3a6b9dbdf255adb0f960a22 (patch) | |
tree | 7521bf5eefaa84f1cd18c2d601ac0891cc1598a5 | |
parent | 644044333f5f6d7ba7e327619ac0d0ce4e2609d3 (diff) |
ART: Use .bss section for dex cache arrays.
Change-Id: I5fd507973b56f6a662a02a8c1dd9ac4493fb7b36
-rw-r--r-- | compiler/oat_writer.cc | 55 | ||||
-rw-r--r-- | compiler/oat_writer.h | 11 | ||||
-rw-r--r-- | runtime/arch/instruction_set.h | 16 | ||||
-rw-r--r-- | runtime/class_linker.cc | 5 | ||||
-rw-r--r-- | runtime/image.cc | 2 | ||||
-rw-r--r-- | runtime/oat.cc | 6 | ||||
-rw-r--r-- | runtime/oat_file.cc | 37 | ||||
-rw-r--r-- | runtime/oat_file.h | 8 | ||||
-rw-r--r-- | runtime/utils/dex_cache_arrays_layout-inl.h | 15 | ||||
-rw-r--r-- | runtime/utils/dex_cache_arrays_layout.h | 5 |
10 files changed, 134 insertions, 26 deletions
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 7b410bfe37..a78a5b3644 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 @@ 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; diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 48fbc0b2ac..a82d09eedd 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -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_; diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h index 9cfd2eb2d6..ff9c0b320d 100644 --- a/runtime/arch/instruction_set.h +++ b/runtime/arch/instruction_set.h @@ -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) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 02f2e0b207..c91577a7ac 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -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); diff --git a/runtime/image.cc b/runtime/image.cc index 42b348ac58..192371fe75 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 5725b6ff6c..5625499848 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -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 ""; } diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 6cbbce9bb1..d931777e41 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 @@ 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() {} diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 364b7342d7..34f014123b 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -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); diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h index 4f662d5a8f..90e24b9632 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 d50be5ac03..cd84460c3b 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 @@ 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); |