Revert "Load app images"
Fails when a method is duplicated (see test 097-duplicate-method)
Bug: 22858531
This reverts commit f7fd970244f143b1abb956e29794c446e4d57f46.
Change-Id: Ib30ae5be00cc568e799290be6b3c8f29cbbe4c20
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 9ff3d8d..5f6bb8e 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -475,10 +475,10 @@
return true;
}
-ImageSpace* ImageSpace::CreateBootImage(const char* image_location,
- const InstructionSet image_isa,
- bool secondary_image,
- std::string* error_msg) {
+ImageSpace* ImageSpace::Create(const char* image_location,
+ const InstructionSet image_isa,
+ bool secondary_image,
+ std::string* error_msg) {
std::string system_filename;
bool has_system = false;
std::string cache_filename;
@@ -584,13 +584,8 @@
// assume this if we are using a relocated image (i.e. image checksum
// matches) since this is only different by the offset. We need this to
// make sure that host tests continue to work.
- // Since we are the boot image, pass null since we load the oat file from the boot image oat
- // file name.
- space = ImageSpace::Init(image_filename->c_str(),
- image_location,
- !(is_system || relocated_version_used),
- /* oat_file */nullptr,
- error_msg);
+ space = ImageSpace::Init(image_filename->c_str(), image_location,
+ !(is_system || relocated_version_used), error_msg);
}
if (space != nullptr) {
return space;
@@ -651,7 +646,7 @@
// we leave Create.
ScopedFlock image_lock;
image_lock.Init(cache_filename.c_str(), error_msg);
- space = ImageSpace::Init(cache_filename.c_str(), image_location, true, nullptr, error_msg);
+ space = ImageSpace::Init(cache_filename.c_str(), image_location, true, error_msg);
if (space == nullptr) {
*error_msg = StringPrintf("Failed to load generated image '%s': %s",
cache_filename.c_str(), error_msg->c_str());
@@ -674,494 +669,34 @@
}
}
-// Helper class for relocating from one range of memory to another.
-class RelocationRange {
- public:
- RelocationRange() = default;
- RelocationRange(const RelocationRange&) = default;
- RelocationRange(uintptr_t source, uintptr_t dest, uintptr_t length)
- : source_(source),
- dest_(dest),
- length_(length) {}
-
- bool ContainsSource(uintptr_t address) const {
- return address - source_ < length_;
- }
-
- // Translate a source address to the destination space.
- uintptr_t ToDest(uintptr_t address) const {
- DCHECK(ContainsSource(address));
- return address + Delta();
- }
-
- // Returns the delta between the dest from the source.
- off_t Delta() const {
- return dest_ - source_;
- }
-
- uintptr_t Source() const {
- return source_;
- }
-
- uintptr_t Dest() const {
- return dest_;
- }
-
- uintptr_t Length() const {
- return length_;
- }
-
- private:
- const uintptr_t source_;
- const uintptr_t dest_;
- const uintptr_t length_;
-};
-
-class FixupVisitor : public ValueObject {
- public:
- FixupVisitor(const RelocationRange& boot_image,
- const RelocationRange& boot_oat,
- const RelocationRange& app_image,
- const RelocationRange& app_oat)
- : boot_image_(boot_image),
- boot_oat_(boot_oat),
- app_image_(app_image),
- app_oat_(app_oat) {}
-
- // Return the relocated address of a heap object.
- template <typename T>
- ALWAYS_INLINE T* ForwardObject(T* src) const {
- const uintptr_t uint_src = reinterpret_cast<uintptr_t>(src);
- if (boot_image_.ContainsSource(uint_src)) {
- return reinterpret_cast<T*>(boot_image_.ToDest(uint_src));
- }
- if (app_image_.ContainsSource(uint_src)) {
- return reinterpret_cast<T*>(app_image_.ToDest(uint_src));
- }
- return src;
- }
-
- // Return the relocated address of a code pointer (contained by an oat file).
- ALWAYS_INLINE const void* ForwardCode(const void* src) const {
- const uintptr_t uint_src = reinterpret_cast<uintptr_t>(src);
- if (boot_oat_.ContainsSource(uint_src)) {
- return reinterpret_cast<const void*>(boot_oat_.ToDest(uint_src));
- }
- if (app_oat_.ContainsSource(uint_src)) {
- return reinterpret_cast<const void*>(app_oat_.ToDest(uint_src));
- }
- return src;
- }
-
- protected:
- // Source section.
- const RelocationRange boot_image_;
- const RelocationRange boot_oat_;
- const RelocationRange app_image_;
- const RelocationRange app_oat_;
-};
-
-std::ostream& operator<<(std::ostream& os, const RelocationRange& reloc) {
- return os << "(" << reinterpret_cast<const void*>(reloc.Source()) << "-"
- << reinterpret_cast<const void*>(reloc.Source() + reloc.Length()) << ")->("
- << reinterpret_cast<const void*>(reloc.Dest()) << "-"
- << reinterpret_cast<const void*>(reloc.Dest() + reloc.Length()) << ")";
-}
-
-// Adapt for mirror::Class::FixupNativePointers.
-class FixupObjectAdapter : public FixupVisitor {
- public:
- template<typename... Args>
- explicit FixupObjectAdapter(Args... args) : FixupVisitor(args...) {}
-
- template <typename T>
- T* operator()(T* obj) const {
- return ForwardObject(obj);
- }
-};
-
-class FixupClassVisitor : public FixupVisitor {
- public:
- template<typename... Args>
- explicit FixupClassVisitor(Args... args) : FixupVisitor(args...) {}
-
- // The image space is contained so the GC doesn't need to know about it. Avoid requiring mutator
- // lock to prevent possible pauses.
- ALWAYS_INLINE void operator()(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
- mirror::Class* klass = obj->GetClass<kVerifyNone, kWithoutReadBarrier>();
- DCHECK(klass != nullptr) << "Null class in image";
- // No AsClass since our fields aren't quite fixed up yet.
- mirror::Class* new_klass = down_cast<mirror::Class*>(ForwardObject(klass));
- // Keep clean if possible.
- if (klass != new_klass) {
- obj->SetClass<kVerifyNone>(new_klass);
- }
- }
-};
-
-class FixupRootVisitor : public FixupVisitor {
- public:
- template<typename... Args>
- explicit FixupRootVisitor(Args... args) : FixupVisitor(args...) {}
-
- ALWAYS_INLINE void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
- SHARED_REQUIRES(Locks::mutator_lock_) {
- if (!root->IsNull()) {
- VisitRoot(root);
- }
- }
-
- ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
- SHARED_REQUIRES(Locks::mutator_lock_) {
- mirror::Object* ref = root->AsMirrorPtr();
- mirror::Object* new_ref = ForwardObject(ref);
- if (ref != new_ref) {
- root->Assign(new_ref);
- }
- }
-};
-
-class FixupObjectVisitor : public FixupVisitor {
- public:
- template<typename... Args>
- explicit FixupObjectVisitor(Args... args) : FixupVisitor(args...) {}
-
- // Fix up separately since we also need to fix up method entrypoints.
- ALWAYS_INLINE void VisitRootIfNonNull(
- mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {}
-
- ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED)
- const {}
-
- ALWAYS_INLINE void operator()(mirror::Object* obj,
- MemberOffset offset,
- bool is_static ATTRIBUTE_UNUSED) const
- NO_THREAD_SAFETY_ANALYSIS {
- // There could be overlap between ranges, we must avoid visiting the same reference twice.
- // Avoid the class field since we already fixed it up in FixupClassVisitor.
- if (offset.Uint32Value() != mirror::Object::ClassOffset().Uint32Value()) {
- // Space is not yet added to the heap, don't do a read barrier.
- mirror::Object* ref = obj->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(
- offset);
- // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
- // image.
- obj->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(offset, ForwardObject(ref));
- }
- }
-
- // java.lang.ref.Reference visitor.
- void operator()(mirror::Class* klass ATTRIBUTE_UNUSED, mirror::Reference* ref) const
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) {
- mirror::Object* obj = ref->GetReferent<kWithoutReadBarrier>();
- ref->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(
- mirror::Reference::ReferentOffset(),
- ForwardObject(obj));
- }
-
- ALWAYS_INLINE void operator()(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
- obj->VisitReferences</*visit native roots*/false, kVerifyNone, kWithoutReadBarrier>(
- *this,
- *this);
- // We want to use our own class loader and not the one in the image.
- if (obj->IsClass<kVerifyNone, kWithoutReadBarrier>()) {
- mirror::Class* klass = obj->AsClass<kVerifyNone, kWithoutReadBarrier>();
- FixupObjectAdapter visitor(boot_image_, boot_oat_, app_image_, app_oat_);
- klass->FixupNativePointers(klass, sizeof(void*), visitor);
- // Deal with the arrays.
- mirror::PointerArray* vtable = klass->GetVTable<kVerifyNone, kWithoutReadBarrier>();
- if (vtable != nullptr) {
- vtable->Fixup(vtable, sizeof(void*), visitor);
- }
- mirror::IfTable* iftable = klass->GetIfTable<kVerifyNone, kWithoutReadBarrier>();
- if (iftable != nullptr) {
- for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
- if (iftable->GetMethodArrayCount(i) > 0) {
- mirror::PointerArray* methods =
- iftable->GetMethodArray<kVerifyNone, kWithoutReadBarrier>(i);
- DCHECK(methods != nullptr);
- methods->Fixup(methods, sizeof(void*), visitor);
- }
- }
- }
- }
- }
-};
-
-class ForwardObjectAdapter {
- public:
- ALWAYS_INLINE ForwardObjectAdapter(const FixupVisitor* visitor) : visitor_(visitor) {}
-
- template <typename T>
- ALWAYS_INLINE T* operator()(T* src) const {
- return visitor_->ForwardObject(src);
- }
-
- private:
- const FixupVisitor* const visitor_;
-};
-
-class ForwardCodeAdapter {
- public:
- ALWAYS_INLINE ForwardCodeAdapter(const FixupVisitor* visitor) : visitor_(visitor) {}
-
- template <typename T>
- ALWAYS_INLINE T* operator()(T* src) const {
- return visitor_->ForwardCode(src);
- }
-
- private:
- const FixupVisitor* const visitor_;
-};
-
-class FixupArtMethodVisitor : public FixupVisitor, public ArtMethodVisitor {
- public:
- template<typename... Args>
- explicit FixupArtMethodVisitor(bool fixup_heap_objects, Args... args)
- : FixupVisitor(args...),
- fixup_heap_objects_(fixup_heap_objects) {}
-
- virtual void Visit(ArtMethod* method) NO_THREAD_SAFETY_ANALYSIS {
- if (fixup_heap_objects_) {
- method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this));
- }
- method->UpdateEntrypoints(ForwardCodeAdapter(this));
- }
-
- private:
- const bool fixup_heap_objects_;
-};
-
-class FixupArtFieldVisitor : public FixupVisitor, public ArtFieldVisitor {
- public:
- template<typename... Args>
- explicit FixupArtFieldVisitor(Args... args) : FixupVisitor(args...) {}
-
- virtual void Visit(ArtField* field) NO_THREAD_SAFETY_ANALYSIS {
- field->UpdateObjects(ForwardObjectAdapter(this));
- }
-};
-
-// Relocate an image space mapped at target_base which possibly used to be at a different base
-// address. Only needs a single image space, not one for both source and destination.
-// In place means modifying a single ImageSpace in place rather than relocating from one ImageSpace
-// to another.
-static bool RelocateInPlace(ImageHeader& image_header,
- uint8_t* target_base,
- accounting::ContinuousSpaceBitmap* bitmap,
- const OatFile* app_oat_file,
- std::string* error_msg) {
- DCHECK(error_msg != nullptr);
- if (!image_header.IsPic()) {
- if (image_header.GetImageBegin() == target_base) {
- return true;
- }
- *error_msg = StringPrintf("Cannot relocate non-pic image for oat file %s",
- (app_oat_file != nullptr) ? app_oat_file->GetLocation().c_str() : "");
- return false;
- }
- // Set up sections.
- uint32_t boot_image_begin = 0;
- uint32_t boot_image_end = 0;
- uint32_t boot_oat_begin = 0;
- uint32_t boot_oat_end = 0;
- gc::Heap* const heap = Runtime::Current()->GetHeap();
- heap->GetBootImagesSize(&boot_image_begin, &boot_image_end, &boot_oat_begin, &boot_oat_end);
- CHECK_NE(boot_image_begin, boot_image_end)
- << "Can not relocate app image without boot image space";
- CHECK_NE(boot_oat_begin, boot_oat_end) << "Can not relocate app image without boot oat file";
- const uint32_t boot_image_size = boot_image_end - boot_image_begin;
- const uint32_t boot_oat_size = boot_oat_end - boot_oat_begin;
- const uint32_t image_header_boot_image_size = image_header.GetBootImageSize();
- const uint32_t image_header_boot_oat_size = image_header.GetBootOatSize();
- if (boot_image_size != image_header_boot_image_size) {
- *error_msg = StringPrintf("Boot image size %" PRIu64 " does not match expected size %"
- PRIu64,
- static_cast<uint64_t>(boot_image_size),
- static_cast<uint64_t>(image_header_boot_image_size));
- return false;
- }
- if (boot_oat_size != image_header_boot_oat_size) {
- *error_msg = StringPrintf("Boot oat size %" PRIu64 " does not match expected size %"
- PRIu64,
- static_cast<uint64_t>(boot_oat_size),
- static_cast<uint64_t>(image_header_boot_oat_size));
- return false;
- }
- TimingLogger logger(__FUNCTION__, true, false);
- RelocationRange boot_image(image_header.GetBootImageBegin(),
- boot_image_begin,
- boot_image_size);
- RelocationRange boot_oat(image_header.GetBootOatBegin(),
- boot_oat_begin,
- boot_oat_size);
- RelocationRange app_image(reinterpret_cast<uintptr_t>(image_header.GetImageBegin()),
- reinterpret_cast<uintptr_t>(target_base),
- image_header.GetImageSize());
- // Use the oat data section since this is where the OatFile::Begin is.
- RelocationRange app_oat(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()),
- // Not necessarily in low 4GB.
- reinterpret_cast<uintptr_t>(app_oat_file->Begin()),
- image_header.GetOatDataEnd() - image_header.GetOatDataBegin());
- VLOG(image) << "App image " << app_image;
- VLOG(image) << "App oat " << app_oat;
- VLOG(image) << "Boot image " << boot_image;
- VLOG(image) << "Boot oat " << boot_oat;
- // True if we need to fixup any heap pointers, otherwise only code pointers.
- const bool fixup_image = boot_image.Delta() != 0 || app_image.Delta() != 0;
- const bool fixup_code = boot_oat.Delta() != 0 || app_oat.Delta() != 0;
- if (!fixup_image && !fixup_code) {
- // Nothing to fix up.
- return true;
- }
- // Need to update the image to be at the target base.
- const ImageSection& objects_section = image_header.GetImageSection(ImageHeader::kSectionObjects);
- uintptr_t objects_begin = reinterpret_cast<uintptr_t>(target_base + objects_section.Offset());
- uintptr_t objects_end = reinterpret_cast<uintptr_t>(target_base + objects_section.End());
- // Two pass approach, fix up all classes first, then fix up non class-objects.
- FixupObjectVisitor fixup_object_visitor(boot_image, boot_oat, app_image, app_oat);
- if (fixup_image) {
- TimingLogger::ScopedTiming timing("Fixup classes", &logger);
- // Fixup class only touches app image classes, don't need the mutator lock since the space is
- // not yet visible to the GC.
- FixupClassVisitor fixup_class_visitor(boot_image, boot_oat, app_image, app_oat);
- bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_class_visitor);
- // Fixup objects may read fields in the boot image, use the mutator lock here for sanity. Though
- // its probably not required.
- ScopedObjectAccess soa(Thread::Current());
- timing.NewTiming("Fixup objects");
- bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_object_visitor);
- FixupObjectAdapter fixup_adapter(boot_image, boot_oat, app_image, app_oat);
- // Fixup image roots.
- CHECK(app_image.ContainsSource(reinterpret_cast<uintptr_t>(image_header.GetImageRoots())));
- image_header.RelocateImageObjects(app_image.Delta());
- CHECK_EQ(image_header.GetImageBegin(), target_base);
- // Fix up dex cache DexFile pointers.
- auto* dex_caches = image_header.GetImageRoot(ImageHeader::kDexCaches)->
- AsObjectArray<mirror::DexCache>();
- for (int32_t i = 0, count = dex_caches->GetLength(); i < count; ++i) {
- mirror::DexCache* dex_cache = dex_caches->Get(i);
- // Fix up dex cache pointers.
- GcRoot<mirror::String>* strings = dex_cache->GetStrings();
- if (strings != nullptr) {
- GcRoot<mirror::String>* new_strings = fixup_adapter.ForwardObject(strings);
- if (strings != new_strings) {
- dex_cache->SetFieldPtr64<false>(mirror::DexCache::StringsOffset(), new_strings);
- }
- dex_cache->FixupStrings(new_strings, fixup_adapter);
- }
- GcRoot<mirror::Class>* types = dex_cache->GetResolvedTypes();
- if (types != nullptr) {
- GcRoot<mirror::Class>* new_types = fixup_adapter.ForwardObject(types);
- if (types != new_types) {
- dex_cache->SetFieldPtr64<false>(mirror::DexCache::ResolvedTypesOffset(), new_types);
- }
- dex_cache->FixupResolvedTypes(new_types, fixup_adapter);
- }
- ArtMethod** methods = dex_cache->GetResolvedMethods();
- if (methods != nullptr) {
- ArtMethod** new_methods = fixup_adapter.ForwardObject(methods);
- if (methods != new_methods) {
- dex_cache->SetFieldPtr64<false>(mirror::DexCache::ResolvedMethodsOffset(), new_methods);
- }
- for (size_t j = 0, num = dex_cache->NumResolvedMethods(); j != num; ++j) {
- ArtMethod* orig = mirror::DexCache::GetElementPtrSize(new_methods, j, sizeof(void*));
- ArtMethod* copy = fixup_adapter.ForwardObject(orig);
- if (orig != copy) {
- mirror::DexCache::SetElementPtrSize(new_methods, j, copy, sizeof(void*));
- }
- }
- }
- ArtField** fields = dex_cache->GetResolvedFields();
- if (fields != nullptr) {
- ArtField** new_fields = fixup_adapter.ForwardObject(fields);
- if (fields != new_fields) {
- dex_cache->SetFieldPtr64<false>(mirror::DexCache::ResolvedFieldsOffset(), new_fields);
- }
- for (size_t j = 0, num = dex_cache->NumResolvedFields(); j != num; ++j) {
- ArtField* orig = mirror::DexCache::GetElementPtrSize(new_fields, j, sizeof(void*));
- ArtField* copy = fixup_adapter.ForwardObject(orig);
- if (orig != copy) {
- mirror::DexCache::SetElementPtrSize(new_fields, j, copy, sizeof(void*));
- }
- }
- }
- }
- }
- {
- // Only touches objects in the app image, no need for mutator lock.
- TimingLogger::ScopedTiming timing("Fixup methods", &logger);
- FixupArtMethodVisitor method_visitor(fixup_image, boot_image, boot_oat, app_image, app_oat);
- image_header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods(
- &method_visitor,
- target_base,
- sizeof(void*));
- }
- if (fixup_image) {
- {
- // Only touches objects in the app image, no need for mutator lock.
- TimingLogger::ScopedTiming timing("Fixup fields", &logger);
- FixupArtFieldVisitor field_visitor(boot_image, boot_oat, app_image, app_oat);
- image_header.GetImageSection(ImageHeader::kSectionArtFields).VisitPackedArtFields(
- &field_visitor,
- target_base);
- }
- // In the app image case, the image methods are actually in the boot image.
- image_header.RelocateImageMethods(boot_image.Delta());
- const auto& class_table_section = image_header.GetImageSection(ImageHeader::kSectionClassTable);
- if (class_table_section.Size() > 0u) {
- // Note that we require that ReadFromMemory does not make an internal copy of the elements.
- // This also relies on visit roots not doing any verification which could fail after we update
- // the roots to be the image addresses.
- ScopedObjectAccess soa(Thread::Current());
- WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- ClassTable temp_table;
- temp_table.ReadFromMemory(target_base + class_table_section.Offset());
- FixupRootVisitor root_visitor(boot_image, boot_oat, app_image, app_oat);
- temp_table.VisitRoots(root_visitor);
- }
- }
- if (VLOG_IS_ON(image)) {
- logger.Dump(LOG(INFO));
- }
- return true;
-}
-
-ImageSpace* ImageSpace::Init(const char* image_filename,
- const char* image_location,
- bool validate_oat_file,
- const OatFile* oat_file,
- std::string* error_msg) {
+ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_location,
+ bool validate_oat_file, std::string* error_msg) {
CHECK(image_filename != nullptr);
CHECK(image_location != nullptr);
- TimingLogger logger(__FUNCTION__, true, false);
- VLOG(image) << "ImageSpace::Init entering image_filename=" << image_filename;
-
- std::unique_ptr<File> file;
- {
- TimingLogger::ScopedTiming timing("OpenImageFile", &logger);
- file.reset(OS::OpenFileForReading(image_filename));
- if (file == nullptr) {
- *error_msg = StringPrintf("Failed to open '%s'", image_filename);
- return nullptr;
- }
+ uint64_t start_time = 0;
+ if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+ start_time = NanoTime();
+ LOG(INFO) << "ImageSpace::Init entering image_filename=" << image_filename;
}
- ImageHeader temp_image_header;
- ImageHeader* image_header = &temp_image_header;
- {
- TimingLogger::ScopedTiming timing("ReadImageHeader", &logger);
- bool success = file->ReadFully(image_header, sizeof(*image_header));
- if (!success || !image_header->IsValid()) {
- *error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
- return nullptr;
- }
+
+ std::unique_ptr<File> file(OS::OpenFileForReading(image_filename));
+ if (file.get() == nullptr) {
+ *error_msg = StringPrintf("Failed to open '%s'", image_filename);
+ return nullptr;
+ }
+ ImageHeader image_header;
+ bool success = file->ReadFully(&image_header, sizeof(image_header));
+ if (!success || !image_header.IsValid()) {
+ *error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
+ return nullptr;
}
// Check that the file is larger or equal to the header size + data size.
const uint64_t image_file_size = static_cast<uint64_t>(file->GetLength());
- if (image_file_size < sizeof(ImageHeader) + image_header->GetDataSize()) {
+ if (image_file_size < sizeof(ImageHeader) + image_header.GetDataSize()) {
*error_msg = StringPrintf("Image file truncated: %" PRIu64 " vs. %" PRIu64 ".",
image_file_size,
- sizeof(ImageHeader) + image_header->GetDataSize());
+ image_header.GetDataSize());
return nullptr;
}
@@ -1169,17 +704,17 @@
LOG(INFO) << "Dumping image sections";
for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
const auto section_idx = static_cast<ImageHeader::ImageSections>(i);
- auto& section = image_header->GetImageSection(section_idx);
+ auto& section = image_header.GetImageSection(section_idx);
LOG(INFO) << section_idx << " start="
- << reinterpret_cast<void*>(image_header->GetImageBegin() + section.Offset()) << " "
- << section;
+ << reinterpret_cast<void*>(image_header.GetImageBegin() + section.Offset()) << " "
+ << section;
}
}
- const auto& bitmap_section = image_header->GetImageSection(ImageHeader::kSectionImageBitmap);
+ const auto& bitmap_section = image_header.GetImageSection(ImageHeader::kSectionImageBitmap);
// The location we want to map from is the first aligned page after the end of the stored
// (possibly compressed) data.
- const size_t image_bitmap_offset = RoundUp(sizeof(ImageHeader) + image_header->GetDataSize(),
+ const size_t image_bitmap_offset = RoundUp(sizeof(image_header) + image_header.GetDataSize(),
kPageSize);
const size_t end_of_bitmap = image_bitmap_offset + bitmap_section.Size();
if (end_of_bitmap != image_file_size) {
@@ -1189,84 +724,67 @@
return nullptr;
}
- // The preferred address to map the image, null specifies any address. If we manage to map the
- // image at the image begin, the amount of fixup work required is minimized.
- std::vector<uint8_t*> addresses(1, image_header->GetImageBegin());
- if (image_header->IsPic()) {
- // Can also map at a random low_4gb address since we can relocate in-place.
- addresses.push_back(nullptr);
- }
-
// Note: The image header is part of the image due to mmap page alignment required of offset.
std::unique_ptr<MemMap> map;
- std::string temp_error_msg;
- for (uint8_t* address : addresses) {
- TimingLogger::ScopedTiming timing("MapImageFile", &logger);
- // Only care about the error message for the last address in addresses. We want to avoid the
- // overhead of printing the process maps if we can relocate.
- std::string* out_error_msg = (address == addresses.back()) ? &temp_error_msg : nullptr;
- if (image_header->GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
- map.reset(MemMap::MapFileAtAddress(address,
- image_header->GetImageSize(),
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE,
- file->Fd(),
- 0,
- /*low_4gb*/true,
- /*reuse*/false,
- image_filename,
- /*out*/out_error_msg));
- } else {
- // Reserve output and decompress into it.
- map.reset(MemMap::MapAnonymous(image_location,
- address,
- image_header->GetImageSize(),
- PROT_READ | PROT_WRITE,
- /*low_4gb*/true,
- /*reuse*/false,
- out_error_msg));
- if (map != nullptr) {
- const size_t stored_size = image_header->GetDataSize();
- const size_t write_offset = sizeof(ImageHeader); // Skip the header.
- std::unique_ptr<MemMap> temp_map(MemMap::MapFile(sizeof(ImageHeader) + stored_size,
- PROT_READ,
- MAP_PRIVATE,
- file->Fd(),
- /*offset*/0,
- /*low_4gb*/false,
- image_filename,
- out_error_msg));
- if (temp_map == nullptr) {
- DCHECK(!out_error_msg->empty());
- return nullptr;
- }
- memcpy(map->Begin(), image_header, sizeof(ImageHeader));
- const uint64_t start = NanoTime();
- const size_t decompressed_size = LZ4_decompress_safe(
- reinterpret_cast<char*>(temp_map->Begin()) + sizeof(ImageHeader),
- reinterpret_cast<char*>(map->Begin()) + write_offset,
- stored_size,
- map->Size());
- VLOG(image) << "Decompressing image took " << PrettyDuration(NanoTime() - start);
- if (decompressed_size + sizeof(ImageHeader) != image_header->GetImageSize()) {
- *error_msg = StringPrintf("Decompressed size does not match expected image size %zu vs %zu",
- decompressed_size + sizeof(ImageHeader),
- image_header->GetImageSize());
- return nullptr;
- }
- }
- }
+ if (image_header.GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
+ map.reset(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
+ image_header.GetImageSize(),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE,
+ file->Fd(),
+ 0,
+ /*low_4gb*/false,
+ /*reuse*/false,
+ image_filename,
+ error_msg));
+ } else {
+ // Reserve output and decompress into it.
+ map.reset(MemMap::MapAnonymous(image_location,
+ image_header.GetImageBegin(),
+ image_header.GetImageSize(),
+ PROT_READ | PROT_WRITE,
+ /*low_4gb*/false,
+ /*reuse*/false,
+ error_msg));
if (map != nullptr) {
- break;
+ const size_t stored_size = image_header.GetDataSize();
+ const size_t write_offset = sizeof(image_header); // Skip the header.
+ std::unique_ptr<MemMap> temp_map(MemMap::MapFile(sizeof(ImageHeader) + stored_size,
+ PROT_READ,
+ MAP_PRIVATE,
+ file->Fd(),
+ /*offset*/0,
+ /*low_4gb*/false,
+ image_filename,
+ error_msg));
+ if (temp_map == nullptr) {
+ DCHECK(!error_msg->empty());
+ return nullptr;
+ }
+ memcpy(map->Begin(), &image_header, sizeof(image_header));
+ const uint64_t start = NanoTime();
+ const size_t decompressed_size = LZ4_decompress_safe(
+ reinterpret_cast<char*>(temp_map->Begin()) + sizeof(ImageHeader),
+ reinterpret_cast<char*>(map->Begin()) + write_offset,
+ stored_size,
+ map->Size());
+ // TODO: VLOG(image)
+ VLOG(class_linker) << "Decompressing image took " << PrettyDuration(NanoTime() - start);
+ if (decompressed_size + sizeof(ImageHeader) != image_header.GetImageSize()) {
+ *error_msg = StringPrintf("Decompressed size does not match expected image size %zu vs %zu",
+ decompressed_size + sizeof(ImageHeader),
+ image_header.GetImageSize());
+ return nullptr;
+ }
}
}
if (map == nullptr) {
- DCHECK(!temp_error_msg.empty());
- *error_msg = temp_error_msg;
+ DCHECK(!error_msg->empty());
return nullptr;
}
- DCHECK_EQ(0, memcmp(image_header, map->Begin(), sizeof(ImageHeader)));
+ CHECK_EQ(image_header.GetImageBegin(), map->Begin());
+ DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
std::unique_ptr<MemMap> image_bitmap_map(MemMap::MapFileAtAddress(nullptr,
bitmap_section.Size(),
@@ -1281,42 +799,25 @@
*error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
return nullptr;
}
- // Loaded the map, use the image header from the file now in case we patch it with
- // RelocateInPlace.
- image_header = reinterpret_cast<ImageHeader*>(map->Begin());
- const uint32_t bitmap_index = bitmap_index_.FetchAndAddSequentiallyConsistent(1);
- std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u",
- image_filename,
+ uint32_t bitmap_index = bitmap_index_.FetchAndAddSequentiallyConsistent(1);
+ std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_filename,
bitmap_index));
// Bitmap only needs to cover until the end of the mirror objects section.
- const ImageSection& image_objects = image_header->GetImageSection(ImageHeader::kSectionObjects);
- // We only want the mirror object, not the ArtFields and ArtMethods.
- uint8_t* const image_end = map->Begin() + image_objects.End();
- std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap;
- {
- TimingLogger::ScopedTiming timing("CreateImageBitmap", &logger);
- bitmap.reset(
+ const ImageSection& image_objects = image_header.GetImageSection(ImageHeader::kSectionObjects);
+ std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap(
accounting::ContinuousSpaceBitmap::CreateFromMemMap(
bitmap_name,
image_bitmap_map.release(),
reinterpret_cast<uint8_t*>(map->Begin()),
image_objects.End()));
- if (bitmap == nullptr) {
- *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str());
- return nullptr;
- }
+ if (bitmap == nullptr) {
+ *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str());
+ return nullptr;
}
- {
- TimingLogger::ScopedTiming timing("RelocateImage", &logger);
- if (!RelocateInPlace(*image_header,
- map->Begin(),
- bitmap.get(),
- oat_file,
- error_msg)) {
- return nullptr;
- }
- }
+
// We only want the mirror object, not the ArtFields and ArtMethods.
+ uint8_t* const image_end =
+ map->Begin() + image_header.GetImageSection(ImageHeader::kSectionObjects).End();
std::unique_ptr<ImageSpace> space(new ImageSpace(image_filename,
image_location,
map.release(),
@@ -1328,61 +829,38 @@
// and ArtField::java_lang_reflect_ArtField_, which are used from
// Object::SizeOf() which VerifyImageAllocations() calls, are not
// set yet at this point.
- if (oat_file == nullptr) {
- TimingLogger::ScopedTiming timing("OpenOatFile", &logger);
- space->oat_file_.reset(space->OpenOatFile(image_filename, error_msg));
- if (space->oat_file_ == nullptr) {
- DCHECK(!error_msg->empty());
- return nullptr;
- }
- space->oat_file_non_owned_ = space->oat_file_.get();
- } else {
- space->oat_file_non_owned_ = oat_file;
- }
- if (validate_oat_file) {
- TimingLogger::ScopedTiming timing("ValidateOatFile", &logger);
- if (!space->ValidateOatFile(error_msg)) {
- DCHECK(!error_msg->empty());
- return nullptr;
- }
+ space->oat_file_.reset(space->OpenOatFile(image_filename, error_msg));
+ if (space->oat_file_.get() == nullptr) {
+ DCHECK(!error_msg->empty());
+ return nullptr;
+ }
+ space->oat_file_non_owned_ = space->oat_file_.get();
+
+ if (validate_oat_file && !space->ValidateOatFile(error_msg)) {
+ DCHECK(!error_msg->empty());
+ return nullptr;
}
Runtime* runtime = Runtime::Current();
+ runtime->SetInstructionSet(space->oat_file_->GetOatHeader().GetInstructionSet());
- // If oat_file is null, then it is the boot image space. Use oat_file_non_owned_ from the space
- // to set the runtime methods.
- CHECK_EQ(oat_file != nullptr, image_header->IsAppImage());
- if (image_header->IsAppImage()) {
- CHECK_EQ(runtime->GetResolutionMethod(),
- image_header->GetImageMethod(ImageHeader::kResolutionMethod));
- CHECK_EQ(runtime->GetImtConflictMethod(),
- image_header->GetImageMethod(ImageHeader::kImtConflictMethod));
- CHECK_EQ(runtime->GetImtUnimplementedMethod(),
- image_header->GetImageMethod(ImageHeader::kImtUnimplementedMethod));
- CHECK_EQ(runtime->GetCalleeSaveMethod(Runtime::kSaveAll),
- image_header->GetImageMethod(ImageHeader::kCalleeSaveMethod));
- CHECK_EQ(runtime->GetCalleeSaveMethod(Runtime::kRefsOnly),
- image_header->GetImageMethod(ImageHeader::kRefsOnlySaveMethod));
- CHECK_EQ(runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs),
- image_header->GetImageMethod(ImageHeader::kRefsAndArgsSaveMethod));
- } else if (!runtime->HasResolutionMethod()) {
- runtime->SetInstructionSet(space->oat_file_non_owned_->GetOatHeader().GetInstructionSet());
- runtime->SetResolutionMethod(image_header->GetImageMethod(ImageHeader::kResolutionMethod));
- runtime->SetImtConflictMethod(image_header->GetImageMethod(ImageHeader::kImtConflictMethod));
+ if (!runtime->HasResolutionMethod()) {
+ runtime->SetResolutionMethod(image_header.GetImageMethod(ImageHeader::kResolutionMethod));
+ runtime->SetImtConflictMethod(image_header.GetImageMethod(ImageHeader::kImtConflictMethod));
runtime->SetImtUnimplementedMethod(
- image_header->GetImageMethod(ImageHeader::kImtUnimplementedMethod));
+ image_header.GetImageMethod(ImageHeader::kImtUnimplementedMethod));
runtime->SetCalleeSaveMethod(
- image_header->GetImageMethod(ImageHeader::kCalleeSaveMethod), Runtime::kSaveAll);
+ image_header.GetImageMethod(ImageHeader::kCalleeSaveMethod), Runtime::kSaveAll);
runtime->SetCalleeSaveMethod(
- image_header->GetImageMethod(ImageHeader::kRefsOnlySaveMethod), Runtime::kRefsOnly);
+ image_header.GetImageMethod(ImageHeader::kRefsOnlySaveMethod), Runtime::kRefsOnly);
runtime->SetCalleeSaveMethod(
- image_header->GetImageMethod(ImageHeader::kRefsAndArgsSaveMethod), Runtime::kRefsAndArgs);
+ image_header.GetImageMethod(ImageHeader::kRefsAndArgsSaveMethod), Runtime::kRefsAndArgs);
}
- VLOG(image) << "ImageSpace::Init exiting " << *space.get();
- if (VLOG_IS_ON(image)) {
- logger.Dump(LOG(INFO));
+ if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+ LOG(INFO) << "ImageSpace::Init exiting (" << PrettyDuration(NanoTime() - start_time)
+ << ") " << *space.get();
}
return space.release();
}
@@ -1524,16 +1002,6 @@
}
}
-ImageSpace* ImageSpace::CreateFromAppImage(const char* image,
- const OatFile* oat_file,
- std::string* error_msg) {
- return gc::space::ImageSpace::Init(image,
- image,
- /*validate_oat_file*/false,
- oat_file,
- /*out*/error_msg);
-}
-
} // namespace space
} // namespace gc
} // namespace art