Revert "Load boot image at a random address."
This reverts commit 5ad79d85d77a42456728897ac3e2e7d4530e618e.
Reason for revert: Breaks GSS garbage collection config.
Bug: 77856493
Change-Id: Ifa39966ac2470154f8ba093de4804689d545219b
diff --git a/compiler/dex/quick_compiler_callbacks.h b/compiler/dex/quick_compiler_callbacks.h
index e92b67a..b7117bd 100644
--- a/compiler/dex/quick_compiler_callbacks.h
+++ b/compiler/dex/quick_compiler_callbacks.h
@@ -38,6 +38,11 @@
void ClassRejected(ClassReference ref) override;
+ // We are running in an environment where we can call patchoat safely so we should.
+ bool IsRelocationPossible() override {
+ return true;
+ }
+
verifier::VerifierDeps* GetVerifierDeps() const override {
return verifier_deps_.get();
}
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index e1b23cc..306b73f 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -49,6 +49,7 @@
void MethodVerified(verifier::MethodVerifier* verifier ATTRIBUTE_UNUSED) override {}
void ClassRejected(ClassReference ref ATTRIBUTE_UNUSED) override {}
+ bool IsRelocationPossible() override { return false; }
verifier::VerifierDeps* GetVerifierDeps() const override { return deps_; }
void SetVerifierDeps(verifier::VerifierDeps* deps) override { deps_ = deps; }
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index 245a15b..1b2e8d7 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -36,7 +36,7 @@
#include "class_linker.h"
#include "gc/heap.h"
#include "gc/space/image_space.h"
-#include "image-inl.h"
+#include "image.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "oat.h"
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 570b0e6..48ddc69 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -725,10 +725,6 @@
ALWAYS_INLINE CodeItemDebugInfoAccessor DexInstructionDebugInfo()
REQUIRES_SHARED(Locks::mutator_lock_);
- GcRoot<mirror::Class>& DeclaringClassRoot() {
- return declaring_class_;
- }
-
protected:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// The class we are a part of.
diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h
index b29eb70..6855dcd 100644
--- a/runtime/compiler_callbacks.h
+++ b/runtime/compiler_callbacks.h
@@ -51,6 +51,10 @@
REQUIRES_SHARED(Locks::mutator_lock_) = 0;
virtual void ClassRejected(ClassReference ref) = 0;
+ // Return true if we should attempt to relocate to a random base address if we have not already
+ // done so. Return false if relocating in this way would be problematic.
+ virtual bool IsRelocationPossible() = 0;
+
virtual verifier::VerifierDeps* GetVerifierDeps() const = 0;
virtual void SetVerifierDeps(verifier::VerifierDeps* deps ATTRIBUTE_UNUSED) {}
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 8af5d55..ee4a0f4 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -28,7 +28,6 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
-#include "base/bit_memory_region.h"
#include "base/callee_save_type.h"
#include "base/enums.h"
#include "base/file_utils.h"
@@ -39,16 +38,13 @@
#include "base/systrace.h"
#include "base/time_utils.h"
#include "base/utils.h"
-#include "class_root.h"
#include "dex/art_dex_file_loader.h"
#include "dex/dex_file_loader.h"
#include "exec_utils.h"
#include "gc/accounting/space_bitmap-inl.h"
#include "image-inl.h"
#include "image_space_fs.h"
-#include "intern_table.h"
#include "mirror/class-inl.h"
-#include "mirror/executable.h"
#include "mirror/object-inl.h"
#include "mirror/object-refvisitor-inl.h"
#include "oat_file.h"
@@ -59,6 +55,7 @@
namespace gc {
namespace space {
+using android::base::StringAppendF;
using android::base::StringPrintf;
Atomic<uint32_t> ImageSpace::bitmap_index_(0);
@@ -242,37 +239,142 @@
return true;
}
-static std::unique_ptr<ImageHeader> ReadSpecificImageHeader(const char* filename,
- std::string* error_msg) {
+// Relocate the image at image_location to dest_filename and relocate it by a random amount.
+static bool RelocateImage(const char* image_location,
+ const char* dest_directory,
+ InstructionSet isa,
+ std::string* error_msg) {
+ // We should clean up so we are more likely to have room for the image.
+ if (Runtime::Current()->IsZygote()) {
+ LOG(INFO) << "Pruning dalvik-cache since we are relocating an image and will need to recompile";
+ PruneDalvikCache(isa);
+ }
+
+ std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
+
+ std::string input_image_location_arg("--input-image-location=");
+ input_image_location_arg += image_location;
+
+ std::string output_image_directory_arg("--output-image-directory=");
+ output_image_directory_arg += dest_directory;
+
+ std::string instruction_set_arg("--instruction-set=");
+ instruction_set_arg += GetInstructionSetString(isa);
+
+ std::string base_offset_arg("--base-offset-delta=");
+ StringAppendF(&base_offset_arg, "%d", ChooseRelocationOffsetDelta());
+
+ std::vector<std::string> argv;
+ argv.push_back(patchoat);
+
+ argv.push_back(input_image_location_arg);
+ argv.push_back(output_image_directory_arg);
+
+ argv.push_back(instruction_set_arg);
+ argv.push_back(base_offset_arg);
+
+ std::string command_line(android::base::Join(argv, ' '));
+ LOG(INFO) << "RelocateImage: " << command_line;
+ return Exec(argv, error_msg);
+}
+
+static bool VerifyImage(const char* image_location,
+ const char* dest_directory,
+ InstructionSet isa,
+ std::string* error_msg) {
+ std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
+
+ std::string input_image_location_arg("--input-image-location=");
+ input_image_location_arg += image_location;
+
+ std::string output_image_directory_arg("--output-image-directory=");
+ output_image_directory_arg += dest_directory;
+
+ std::string instruction_set_arg("--instruction-set=");
+ instruction_set_arg += GetInstructionSetString(isa);
+
+ std::vector<std::string> argv;
+ argv.push_back(patchoat);
+
+ argv.push_back(input_image_location_arg);
+ argv.push_back(output_image_directory_arg);
+
+ argv.push_back(instruction_set_arg);
+
+ argv.push_back("--verify");
+
+ std::string command_line(android::base::Join(argv, ' '));
+ LOG(INFO) << "VerifyImage: " << command_line;
+ return Exec(argv, error_msg);
+}
+
+static ImageHeader* ReadSpecificImageHeader(const char* filename, std::string* error_msg) {
std::unique_ptr<ImageHeader> hdr(new ImageHeader);
if (!ReadSpecificImageHeader(filename, hdr.get())) {
*error_msg = StringPrintf("Unable to read image header for %s", filename);
return nullptr;
}
- return hdr;
+ return hdr.release();
}
-std::unique_ptr<ImageHeader> ImageSpace::ReadImageHeader(const char* image_location,
- const InstructionSet image_isa,
- std::string* error_msg) {
+ImageHeader* ImageSpace::ReadImageHeader(const char* image_location,
+ const InstructionSet image_isa,
+ std::string* error_msg) {
std::string system_filename;
bool has_system = false;
std::string cache_filename;
bool has_cache = false;
bool dalvik_cache_exists = false;
bool is_global_cache = false;
- if (FindImageFilename(image_location,
- image_isa,
- &system_filename,
- &has_system,
- &cache_filename,
- &dalvik_cache_exists,
- &has_cache,
- &is_global_cache)) {
- if (has_system) {
- return ReadSpecificImageHeader(system_filename.c_str(), error_msg);
- } else if (has_cache) {
- return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
+ if (FindImageFilename(image_location, image_isa, &system_filename, &has_system,
+ &cache_filename, &dalvik_cache_exists, &has_cache, &is_global_cache)) {
+ if (Runtime::Current()->ShouldRelocate()) {
+ if (has_system && has_cache) {
+ std::unique_ptr<ImageHeader> sys_hdr(new ImageHeader);
+ std::unique_ptr<ImageHeader> cache_hdr(new ImageHeader);
+ if (!ReadSpecificImageHeader(system_filename.c_str(), sys_hdr.get())) {
+ *error_msg = StringPrintf("Unable to read image header for %s at %s",
+ image_location, system_filename.c_str());
+ return nullptr;
+ }
+ if (!ReadSpecificImageHeader(cache_filename.c_str(), cache_hdr.get())) {
+ *error_msg = StringPrintf("Unable to read image header for %s at %s",
+ image_location, cache_filename.c_str());
+ return nullptr;
+ }
+ if (sys_hdr->GetOatChecksum() != cache_hdr->GetOatChecksum()) {
+ *error_msg = StringPrintf("Unable to find a relocated version of image file %s",
+ image_location);
+ return nullptr;
+ }
+ return cache_hdr.release();
+ } else if (!has_cache) {
+ *error_msg = StringPrintf("Unable to find a relocated version of image file %s",
+ image_location);
+ return nullptr;
+ } else if (!has_system && has_cache) {
+ // This can probably just use the cache one.
+ return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
+ }
+ } else {
+ // We don't want to relocate, Just pick the appropriate one if we have it and return.
+ if (has_system && has_cache) {
+ // We want the cache if the checksum matches, otherwise the system.
+ std::unique_ptr<ImageHeader> system(ReadSpecificImageHeader(system_filename.c_str(),
+ error_msg));
+ std::unique_ptr<ImageHeader> cache(ReadSpecificImageHeader(cache_filename.c_str(),
+ error_msg));
+ if (system.get() == nullptr ||
+ (cache.get() != nullptr && cache->GetOatChecksum() == system->GetOatChecksum())) {
+ return cache.release();
+ } else {
+ return system.release();
+ }
+ } else if (has_system) {
+ return ReadSpecificImageHeader(system_filename.c_str(), error_msg);
+ } else if (has_cache) {
+ return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
+ }
}
}
@@ -381,66 +483,10 @@
// nested class), but not declare functions in the header.
class ImageSpace::Loader {
public:
- static std::unique_ptr<ImageSpace> InitAppImage(const char* image_filename,
- const char* image_location,
- bool validate_oat_file,
- const OatFile* oat_file,
- /*inout*/MemMap* image_reservation,
- /*inout*/MemMap* oat_reservation,
- /*out*/std::string* error_msg)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- TimingLogger logger(__PRETTY_FUNCTION__, true, VLOG_IS_ON(image));
- std::unique_ptr<ImageSpace> space = Init(image_filename,
- image_location,
- validate_oat_file,
- oat_file,
- &logger,
- image_reservation,
- oat_reservation,
- error_msg);
- if (space != nullptr) {
- TimingLogger::ScopedTiming timing("RelocateImage", &logger);
- ImageHeader* image_header = reinterpret_cast<ImageHeader*>(space->GetMemMap()->Begin());
- if (!RelocateInPlace(*image_header,
- space->GetMemMap()->Begin(),
- space->GetLiveBitmap(),
- oat_file,
- error_msg)) {
- return nullptr;
- }
- Runtime* runtime = Runtime::Current();
- 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(CalleeSaveType::kSaveAllCalleeSaves),
- image_header->GetImageMethod(ImageHeader::kSaveAllCalleeSavesMethod));
- CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsOnly),
- image_header->GetImageMethod(ImageHeader::kSaveRefsOnlyMethod));
- CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs),
- image_header->GetImageMethod(ImageHeader::kSaveRefsAndArgsMethod));
- CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything),
- image_header->GetImageMethod(ImageHeader::kSaveEverythingMethod));
- CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit),
- image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForClinit));
- CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck),
- image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForSuspendCheck));
-
- VLOG(image) << "ImageSpace::Loader::InitAppImage exiting " << *space.get();
- if (VLOG_IS_ON(image)) {
- logger.Dump(LOG_STREAM(INFO));
- }
- }
- return space;
- }
-
static std::unique_ptr<ImageSpace> Init(const char* image_filename,
const char* image_location,
bool validate_oat_file,
const OatFile* oat_file,
- TimingLogger* logger,
/*inout*/MemMap* image_reservation,
/*inout*/MemMap* oat_reservation,
/*out*/std::string* error_msg)
@@ -448,11 +494,12 @@
CHECK(image_filename != nullptr);
CHECK(image_location != nullptr);
+ TimingLogger logger(__PRETTY_FUNCTION__, true, VLOG_IS_ON(image));
VLOG(image) << "ImageSpace::Init entering image_filename=" << image_filename;
std::unique_ptr<File> file;
{
- TimingLogger::ScopedTiming timing("OpenImageFile", logger);
+ TimingLogger::ScopedTiming timing("OpenImageFile", &logger);
file.reset(OS::OpenFileForReading(image_filename));
if (file == nullptr) {
*error_msg = StringPrintf("Failed to open '%s'", image_filename);
@@ -462,7 +509,7 @@
ImageHeader temp_image_header;
ImageHeader* image_header = &temp_image_header;
{
- TimingLogger::ScopedTiming timing("ReadImageHeader", logger);
+ 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);
@@ -539,10 +586,24 @@
image_filename,
image_location,
*image_header,
+ image_header->GetImageBegin(),
file->Fd(),
logger,
image_reservation,
- error_msg);
+ (image_reservation == nullptr && image_header->IsPic()) ? nullptr : error_msg);
+ // If the header specifies PIC mode, we can also map at a random low_4gb address since we can
+ // relocate in-place.
+ if (!map.IsValid() && image_reservation == nullptr && image_header->IsPic()) {
+ map = LoadImageFile(image_filename,
+ image_location,
+ *image_header,
+ /* address */ nullptr,
+ file->Fd(),
+ logger,
+ /* image_reservation */ nullptr,
+ error_msg);
+ }
+ // Were we able to load something and continue?
if (!map.IsValid()) {
DCHECK(!error_msg->empty());
return nullptr;
@@ -550,8 +611,7 @@
DCHECK_EQ(0, memcmp(image_header, map.Begin(), sizeof(ImageHeader)));
MemMap image_bitmap_map = MemMap::MapFile(bitmap_section.Size(),
- PROT_READ,
- MAP_PRIVATE,
+ PROT_READ, MAP_PRIVATE,
file->Fd(),
image_bitmap_offset,
/* low_4gb */ false,
@@ -574,7 +634,7 @@
uint8_t* const image_end = map.Begin() + image_objects.End();
std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap;
{
- TimingLogger::ScopedTiming timing("CreateImageBitmap", logger);
+ TimingLogger::ScopedTiming timing("CreateImageBitmap", &logger);
bitmap.reset(
accounting::ContinuousSpaceBitmap::CreateFromMemMap(
bitmap_name,
@@ -587,6 +647,16 @@
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.
std::unique_ptr<ImageSpace> space(new ImageSpace(image_filename,
image_location,
@@ -600,7 +670,7 @@
// Object::SizeOf() which VerifyImageAllocations() calls, are not
// set yet at this point.
if (oat_file == nullptr) {
- TimingLogger::ScopedTiming timing("OpenOatFile", logger);
+ TimingLogger::ScopedTiming timing("OpenOatFile", &logger);
space->oat_file_ = OpenOatFile(*space, image_filename, oat_reservation, error_msg);
if (space->oat_file_ == nullptr) {
DCHECK(!error_msg->empty());
@@ -612,7 +682,7 @@
}
if (validate_oat_file) {
- TimingLogger::ScopedTiming timing("ValidateOatFile", logger);
+ TimingLogger::ScopedTiming timing("ValidateOatFile", &logger);
CHECK(space->oat_file_ != nullptr);
if (!ImageSpace::ValidateOatFile(*space->oat_file_, error_msg)) {
DCHECK(!error_msg->empty());
@@ -620,6 +690,60 @@
}
}
+ Runtime* runtime = Runtime::Current();
+
+ // 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(CalleeSaveType::kSaveAllCalleeSaves),
+ image_header->GetImageMethod(ImageHeader::kSaveAllCalleeSavesMethod));
+ CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsOnly),
+ image_header->GetImageMethod(ImageHeader::kSaveRefsOnlyMethod));
+ CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs),
+ image_header->GetImageMethod(ImageHeader::kSaveRefsAndArgsMethod));
+ CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything),
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethod));
+ CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit),
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForClinit));
+ CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck),
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForSuspendCheck));
+ } 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));
+ runtime->SetImtUnimplementedMethod(
+ image_header->GetImageMethod(ImageHeader::kImtUnimplementedMethod));
+ runtime->SetCalleeSaveMethod(
+ image_header->GetImageMethod(ImageHeader::kSaveAllCalleeSavesMethod),
+ CalleeSaveType::kSaveAllCalleeSaves);
+ runtime->SetCalleeSaveMethod(
+ image_header->GetImageMethod(ImageHeader::kSaveRefsOnlyMethod),
+ CalleeSaveType::kSaveRefsOnly);
+ runtime->SetCalleeSaveMethod(
+ image_header->GetImageMethod(ImageHeader::kSaveRefsAndArgsMethod),
+ CalleeSaveType::kSaveRefsAndArgs);
+ runtime->SetCalleeSaveMethod(
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethod),
+ CalleeSaveType::kSaveEverything);
+ runtime->SetCalleeSaveMethod(
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForClinit),
+ CalleeSaveType::kSaveEverythingForClinit);
+ runtime->SetCalleeSaveMethod(
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForSuspendCheck),
+ CalleeSaveType::kSaveEverythingForSuspendCheck);
+ }
+
+ VLOG(image) << "ImageSpace::Init exiting " << *space.get();
+ if (VLOG_IS_ON(image)) {
+ logger.Dump(LOG_STREAM(INFO));
+ }
return space;
}
@@ -627,12 +751,12 @@
static MemMap LoadImageFile(const char* image_filename,
const char* image_location,
const ImageHeader& image_header,
+ uint8_t* address,
int fd,
- TimingLogger* logger,
+ TimingLogger& logger,
/*inout*/MemMap* image_reservation,
/*out*/std::string* error_msg) {
- TimingLogger::ScopedTiming timing("MapImageFile", logger);
- uint8_t* address = (image_reservation != nullptr) ? image_reservation->Begin() : nullptr;
+ TimingLogger::ScopedTiming timing("MapImageFile", &logger);
const ImageHeader::StorageMode storage_mode = image_header.GetStorageMode();
if (storage_mode == ImageHeader::kStorageModeUncompressed) {
return MemMap::MapFileAtAddress(address,
@@ -640,10 +764,10 @@
PROT_READ | PROT_WRITE,
MAP_PRIVATE,
fd,
- /* start= */ 0,
- /* low_4gb= */ true,
+ /* start */ 0,
+ /* low_4gb */ true,
image_filename,
- /* reuse= */ false,
+ /* reuse */ false,
image_reservation,
error_msg);
}
@@ -662,8 +786,8 @@
address,
image_header.GetImageSize(),
PROT_READ | PROT_WRITE,
- /* low_4gb= */ true,
- /* reuse= */ false,
+ /* low_4gb */ true,
+ /* reuse */ false,
image_reservation,
error_msg);
if (map.IsValid()) {
@@ -673,8 +797,8 @@
PROT_READ,
MAP_PRIVATE,
fd,
- /* offset= */ 0,
- /* low_4gb= */ false,
+ /* offset */ 0,
+ /* low_4gb */ false,
image_filename,
error_msg);
if (!temp_map.IsValid()) {
@@ -684,7 +808,7 @@
memcpy(map.Begin(), &image_header, sizeof(ImageHeader));
const uint64_t start = NanoTime();
// LZ4HC and LZ4 have same internal format, both use LZ4_decompress.
- TimingLogger::ScopedTiming timing2("LZ4 decompress image", logger);
+ TimingLogger::ScopedTiming timing2("LZ4 decompress image", &logger);
const size_t decompressed_size = LZ4_decompress_safe(
reinterpret_cast<char*>(temp_map.Begin()) + sizeof(ImageHeader),
reinterpret_cast<char*>(map.Begin()) + decompress_offset,
@@ -1012,14 +1136,23 @@
};
// Relocate an image space mapped at target_base which possibly used to be at a different base
- // address. In place means modifying a single ImageSpace in place rather than relocating from
- // one ImageSpace to another.
+ // 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;
@@ -1239,17 +1372,13 @@
CHECK(image_header.GetOatDataBegin() != nullptr);
- uint8_t* oat_data_begin = image_header.GetOatDataBegin();
- if (oat_reservation != nullptr) {
- oat_data_begin += oat_reservation->Begin() - image_header.GetOatFileBegin();
- }
- std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd= */ -1,
+ std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
oat_filename,
oat_filename,
- oat_data_begin,
+ image_header.GetOatDataBegin(),
!Runtime::Current()->IsAotCompiler(),
- /* low_4gb= */ false,
- /* abs_dex_location= */ nullptr,
+ /* low_4gb */ false,
+ /* abs_dex_location */ nullptr,
oat_reservation,
error_msg));
if (oat_file == nullptr) {
@@ -1323,7 +1452,6 @@
/*out*/std::vector<std::unique_ptr<space::ImageSpace>>* boot_image_spaces,
/*out*/MemMap* extra_reservation,
/*out*/std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) {
- TimingLogger logger(__PRETTY_FUNCTION__, true, VLOG_IS_ON(image));
std::string filename = GetSystemImageFilename(image_location_.c_str(), image_isa_);
std::vector<std::string> locations;
if (!GetBootClassPathImageLocations(image_location_, filename, &locations, error_msg)) {
@@ -1362,8 +1490,7 @@
filename = GetSystemImageFilename(location.c_str(), image_isa_);
spaces.push_back(Load(location,
filename,
- /* validate_oat_file= */ false,
- &logger,
+ /* validate_oat_file */ false,
&image_reservation,
&oat_reservation,
error_msg));
@@ -1375,25 +1502,18 @@
return false;
}
- MaybeRelocateSpaces(spaces, &logger);
- InitRuntimeMethods(spaces);
*extra_reservation = std::move(local_extra_reservation);
boot_image_spaces->swap(spaces);
-
- VLOG(image) << "ImageSpace::BootImageLoader::InitFromDalvikCache exiting " << *spaces.front();
- if (VLOG_IS_ON(image)) {
- logger.Dump(LOG_STREAM(INFO));
- }
return true;
}
bool LoadFromDalvikCache(
+ bool validate_system_checksums,
bool validate_oat_file,
size_t extra_reservation_size,
/*out*/std::vector<std::unique_ptr<space::ImageSpace>>* boot_image_spaces,
/*out*/MemMap* extra_reservation,
/*out*/std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) {
- TimingLogger logger(__PRETTY_FUNCTION__, true, VLOG_IS_ON(image));
DCHECK(DalvikCacheExists());
std::vector<std::string> locations;
if (!GetBootClassPathImageLocations(image_location_, cache_filename_, &locations, error_msg)) {
@@ -1442,531 +1562,42 @@
spaces.push_back(Load(location,
filename,
validate_oat_file,
- &logger,
&image_reservation,
&oat_reservation,
error_msg));
if (spaces.back() == nullptr) {
return false;
}
+ if (validate_system_checksums) {
+ ImageHeader system_hdr;
+ std::string system_filename = GetSystemImageFilename(location.c_str(), image_isa_);
+ if (!ReadSpecificImageHeader(system_filename.c_str(), &system_hdr)) {
+ *error_msg = StringPrintf("Cannot read header of %s", system_filename.c_str());
+ return false;
+ }
+ if (spaces.back()->GetImageHeader().GetOatChecksum() != system_hdr.GetOatChecksum()) {
+ *error_msg = StringPrintf("Checksum mismatch: %u(%s) vs %u(%s)",
+ spaces.back()->GetImageHeader().GetOatChecksum(),
+ filename.c_str(),
+ system_hdr.GetOatChecksum(),
+ system_filename.c_str());
+ return false;
+ }
+ }
}
if (!CheckReservationsExhausted(image_reservation, oat_reservation, error_msg)) {
return false;
}
- MaybeRelocateSpaces(spaces, &logger);
- InitRuntimeMethods(spaces);
*extra_reservation = std::move(local_extra_reservation);
boot_image_spaces->swap(spaces);
-
- VLOG(image) << "ImageSpace::BootImageLoader::InitFromDalvikCache exiting " << *spaces.front();
- if (VLOG_IS_ON(image)) {
- logger.Dump(LOG_STREAM(INFO));
- }
return true;
}
private:
- template <typename T>
- ALWAYS_INLINE static T* RelocatedAddress(T* src, uint32_t diff) {
- DCHECK(src != nullptr);
- return reinterpret_cast32<T*>(reinterpret_cast32<uint32_t>(src) + diff);
- }
-
- template <bool kMayBeNull = true, typename T>
- ALWAYS_INLINE static void PatchGcRoot(uint32_t diff, /*inout*/GcRoot<T>* root)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- static_assert(sizeof(GcRoot<mirror::Class*>) == sizeof(uint32_t), "GcRoot size check");
- T* old_value = root->template Read<kWithoutReadBarrier>();
- DCHECK(kMayBeNull || old_value != nullptr);
- if (!kMayBeNull || old_value != nullptr) {
- *root = GcRoot<T>(RelocatedAddress(old_value, diff));
- }
- }
-
- template <PointerSize kPointerSize, bool kMayBeNull = true, typename T>
- ALWAYS_INLINE static void PatchNativePointer(uint32_t diff, /*inout*/T** entry) {
- if (kPointerSize == PointerSize::k64) {
- uint64_t* raw_entry = reinterpret_cast<uint64_t*>(entry);
- T* old_value = reinterpret_cast64<T*>(*raw_entry);
- DCHECK(kMayBeNull || old_value != nullptr);
- if (!kMayBeNull || old_value != nullptr) {
- T* new_value = RelocatedAddress(old_value, diff);
- *raw_entry = reinterpret_cast64<uint64_t>(new_value);
- }
- } else {
- uint32_t* raw_entry = reinterpret_cast<uint32_t*>(entry);
- T* old_value = reinterpret_cast32<T*>(*raw_entry);
- DCHECK(kMayBeNull || old_value != nullptr);
- if (!kMayBeNull || old_value != nullptr) {
- T* new_value = RelocatedAddress(old_value, diff);
- *raw_entry = reinterpret_cast32<uint32_t>(new_value);
- }
- }
- }
-
- class PatchedObjectsMap {
- public:
- PatchedObjectsMap(uint8_t* image_space_begin, size_t size)
- : image_space_begin_(image_space_begin),
- data_(new uint8_t[BitsToBytesRoundUp(NumLocations(size))]),
- visited_objects_(data_.get(), /* bit_start= */ 0u, NumLocations(size)) {
- DCHECK_ALIGNED(image_space_begin_, kObjectAlignment);
- std::memset(data_.get(), 0, BitsToBytesRoundUp(NumLocations(size)));
- }
-
- ALWAYS_INLINE bool IsVisited(mirror::Object* object) const {
- return visited_objects_.LoadBit(GetIndex(object));
- }
-
- ALWAYS_INLINE void MarkVisited(mirror::Object* object) {
- DCHECK(!IsVisited(object));
- visited_objects_.StoreBit(GetIndex(object), /* value= */ true);
- }
-
- private:
- static size_t NumLocations(size_t size) {
- DCHECK_ALIGNED(size, kObjectAlignment);
- return size / kObjectAlignment;
- }
-
- size_t GetIndex(mirror::Object* object) const {
- DCHECK_ALIGNED(object, kObjectAlignment);
- return (reinterpret_cast<uint8_t*>(object) - image_space_begin_) / kObjectAlignment;
- }
-
- uint8_t* const image_space_begin_;
- const std::unique_ptr<uint8_t[]> data_;
- BitMemoryRegion visited_objects_;
- };
-
- class PatchArtFieldVisitor final : public ArtFieldVisitor {
- public:
- explicit PatchArtFieldVisitor(uint32_t diff)
- : diff_(diff) {}
-
- void Visit(ArtField* field) override REQUIRES_SHARED(Locks::mutator_lock_) {
- PatchGcRoot</* kMayBeNull */ false>(diff_, &field->DeclaringClassRoot());
- }
-
- private:
- const uint32_t diff_;
- };
-
- template <PointerSize kPointerSize>
- class PatchArtMethodVisitor final : public ArtMethodVisitor {
- public:
- explicit PatchArtMethodVisitor(uint32_t diff)
- : diff_(diff) {}
-
- void Visit(ArtMethod* method) override REQUIRES_SHARED(Locks::mutator_lock_) {
- PatchGcRoot(diff_, &method->DeclaringClassRoot());
- void** data_address = PointerAddress(method, ArtMethod::DataOffset(kPointerSize));
- PatchNativePointer<kPointerSize>(diff_, data_address);
- void** entrypoint_address =
- PointerAddress(method, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kPointerSize));
- PatchNativePointer<kPointerSize>(diff_, entrypoint_address);
- }
-
- private:
- void** PointerAddress(ArtMethod* method, MemberOffset offset) {
- return reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(method) + offset.Uint32Value());
- }
-
- const uint32_t diff_;
- };
-
- class ClassTableVisitor final {
- public:
- explicit ClassTableVisitor(uint32_t diff) : diff_(diff) {}
-
- void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(root->AsMirrorPtr() != nullptr);
- root->Assign(RelocatedAddress(root->AsMirrorPtr(), diff_));
- }
-
- private:
- const uint32_t diff_;
- };
-
- template <PointerSize kPointerSize>
- class PatchObjectVisitor final {
- public:
- explicit PatchObjectVisitor(uint32_t diff)
- : diff_(diff) {}
-
- void VisitClass(mirror::Class* klass) REQUIRES_SHARED(Locks::mutator_lock_) {
- // First, patch the `klass->klass_`, known to be a reference to the j.l.Class.class.
- // This should be the only reference field in j.l.Object and we assert that below.
- PatchReferenceField</* kMayBeNull */ false>(klass, mirror::Object::ClassOffset());
- // Then patch the reference instance fields described by j.l.Class.class.
- // Use the sizeof(Object) to determine where these reference fields start.
- mirror::Class* class_class = klass->GetClass<kVerifyNone, kWithoutReadBarrier>();
- size_t num_reference_instance_fields = class_class->NumReferenceInstanceFields<kVerifyNone>();
- DCHECK_NE(num_reference_instance_fields, 0u);
- static_assert(IsAligned<kHeapReferenceSize>(sizeof(mirror::Object)), "Size alignment check.");
- MemberOffset instance_field_offset(sizeof(mirror::Object));
- for (size_t i = 0; i != num_reference_instance_fields; ++i) {
- PatchReferenceField(klass, instance_field_offset);
- instance_field_offset = MemberOffset(
- instance_field_offset.Uint32Value() + sizeof(mirror::HeapReference<mirror::Object>));
- }
- // Now that we have patched the `super_class_`, if this is the j.l.Class.class,
- // we can get a reference to j.l.Object.class and assert that it has only one
- // reference instance field (the `klass_` patched above).
- if (kIsDebugBuild && klass == class_class) {
- mirror::Class* object_class = klass->GetSuperClass<kVerifyNone, kWithoutReadBarrier>();
- CHECK_EQ(object_class->NumReferenceInstanceFields<kVerifyNone>(), 1u);
- }
- // Then patch static fields.
- size_t num_reference_static_fields = klass->NumReferenceStaticFields<kVerifyNone>();
- if (num_reference_static_fields != 0u) {
- MemberOffset static_field_offset =
- klass->GetFirstReferenceStaticFieldOffset<kVerifyNone>(kPointerSize);
- for (size_t i = 0; i != num_reference_static_fields; ++i) {
- PatchReferenceField(klass, static_field_offset);
- static_field_offset = MemberOffset(
- static_field_offset.Uint32Value() + sizeof(mirror::HeapReference<mirror::Object>));
- }
- }
- // Then patch native pointers.
- klass->FixupNativePointers<kVerifyNone>(klass, kPointerSize, *this);
- }
-
- template <typename T>
- T* operator()(T* ptr, void** dest_addr ATTRIBUTE_UNUSED) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (ptr != nullptr) {
- ptr = RelocatedAddress(ptr, diff_);
- }
- return ptr;
- }
-
- void VisitPointerArray(mirror::PointerArray* pointer_array)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- // Fully patch the pointer array, including the `klass_` field.
- PatchReferenceField</* kMayBeNull */ false>(pointer_array, mirror::Object::ClassOffset());
-
- int32_t length = pointer_array->GetLength<kVerifyNone>();
- for (int32_t i = 0; i != length; ++i) {
- ArtMethod** method_entry = reinterpret_cast<ArtMethod**>(
- pointer_array->ElementAddress<kVerifyNone>(i, kPointerSize));
- PatchNativePointer<kPointerSize, /* kMayBeNull */ false>(diff_, method_entry);
- }
- }
-
- void VisitObject(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
- // Visit all reference fields.
- object->VisitReferences</* kVisitNativeRoots */ false,
- kVerifyNone,
- kWithoutReadBarrier>(*this, *this);
- // This function should not be called for classes.
- DCHECK(!object->IsClass<kVerifyNone>());
- }
-
- // Visitor for VisitReferences().
- ALWAYS_INLINE void operator()(mirror::Object* object, MemberOffset field_offset, bool is_static)
- const REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(!is_static);
- PatchReferenceField(object, field_offset);
- }
- // Visitor for VisitReferences(), java.lang.ref.Reference case.
- ALWAYS_INLINE void operator()(ObjPtr<mirror::Class> klass, mirror::Reference* ref) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(klass->IsTypeOfReferenceClass());
- this->operator()(ref, mirror::Reference::ReferentOffset(), /* is_static= */ false);
- }
- // Ignore class native roots; not called from VisitReferences() for kVisitNativeRoots == false.
- void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED)
- const {}
- void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {}
-
- void VisitDexCacheArrays(mirror::DexCache* dex_cache) REQUIRES_SHARED(Locks::mutator_lock_) {
- FixupDexCacheArray<mirror::StringDexCacheType>(dex_cache,
- mirror::DexCache::StringsOffset(),
- dex_cache->NumStrings<kVerifyNone>());
- FixupDexCacheArray<mirror::TypeDexCacheType>(dex_cache,
- mirror::DexCache::ResolvedTypesOffset(),
- dex_cache->NumResolvedTypes<kVerifyNone>());
- FixupDexCacheArray<mirror::MethodDexCacheType>(dex_cache,
- mirror::DexCache::ResolvedMethodsOffset(),
- dex_cache->NumResolvedMethods<kVerifyNone>());
- FixupDexCacheArray<mirror::FieldDexCacheType>(dex_cache,
- mirror::DexCache::ResolvedFieldsOffset(),
- dex_cache->NumResolvedFields<kVerifyNone>());
- FixupDexCacheArray<mirror::MethodTypeDexCacheType>(
- dex_cache,
- mirror::DexCache::ResolvedMethodTypesOffset(),
- dex_cache->NumResolvedMethodTypes<kVerifyNone>());
- FixupDexCacheArray<GcRoot<mirror::CallSite>>(
- dex_cache,
- mirror::DexCache::ResolvedCallSitesOffset(),
- dex_cache->NumResolvedCallSites<kVerifyNone>());
- }
-
- private:
- template <bool kMayBeNull = true>
- ALWAYS_INLINE void PatchReferenceField(mirror::Object* object, MemberOffset offset) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Object* old_value =
- object->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(offset);
- DCHECK(kMayBeNull || old_value != nullptr);
- if (!kMayBeNull || old_value != nullptr) {
- mirror::Object* new_value = RelocatedAddress(old_value, diff_);
- object->SetFieldObjectWithoutWriteBarrier</* kTransactionActive */ false,
- /* kCheckTransaction */ true,
- kVerifyNone>(offset, new_value);
- }
- }
-
- template <typename T>
- void FixupDexCacheArrayEntry(std::atomic<mirror::DexCachePair<T>>* array, uint32_t index)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- static_assert(sizeof(std::atomic<mirror::DexCachePair<T>>) == sizeof(mirror::DexCachePair<T>),
- "Size check for removing std::atomic<>.");
- PatchGcRoot(diff_, &(reinterpret_cast<mirror::DexCachePair<T>*>(array)[index].object));
- }
-
- template <typename T>
- void FixupDexCacheArrayEntry(std::atomic<mirror::NativeDexCachePair<T>>* array, uint32_t index)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- static_assert(sizeof(std::atomic<mirror::NativeDexCachePair<T>>) ==
- sizeof(mirror::NativeDexCachePair<T>),
- "Size check for removing std::atomic<>.");
- mirror::NativeDexCachePair<T> pair =
- mirror::DexCache::GetNativePairPtrSize(array, index, kPointerSize);
- if (pair.object != nullptr) {
- pair.object = RelocatedAddress(pair.object, diff_);
- mirror::DexCache::SetNativePairPtrSize(array, index, pair, kPointerSize);
- }
- }
-
- void FixupDexCacheArrayEntry(GcRoot<mirror::CallSite>* array, uint32_t index)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- PatchGcRoot(diff_, &array[index]);
- }
-
- template <typename EntryType>
- void FixupDexCacheArray(mirror::DexCache* dex_cache,
- MemberOffset array_offset,
- uint32_t size) REQUIRES_SHARED(Locks::mutator_lock_) {
- EntryType* old_array =
- reinterpret_cast64<EntryType*>(dex_cache->GetField64<kVerifyNone>(array_offset));
- DCHECK_EQ(old_array != nullptr, size != 0u);
- if (old_array != nullptr) {
- EntryType* new_array = RelocatedAddress(old_array, diff_);
- dex_cache->SetField64<kVerifyNone>(array_offset, reinterpret_cast64<uint64_t>(new_array));
- for (uint32_t i = 0; i != size; ++i) {
- FixupDexCacheArrayEntry(new_array, i);
- }
- }
- }
-
- const uint32_t diff_;
- };
-
- template <PointerSize kPointerSize>
- static void DoRelocateSpaces(const std::vector<std::unique_ptr<ImageSpace>>& spaces,
- uint32_t diff) REQUIRES_SHARED(Locks::mutator_lock_) {
- PatchedObjectsMap patched_objects(spaces.front()->Begin(),
- spaces.back()->End() - spaces.front()->Begin());
- PatchObjectVisitor<kPointerSize> patch_object_visitor(diff);
-
- mirror::Class* dcheck_class_class = nullptr; // Used only for a DCHECK().
- for (size_t s = 0, size = spaces.size(); s != size; ++s) {
- const ImageSpace* space = spaces[s].get();
-
- // First patch the image header. The `diff` is OK for patching 32-bit fields but
- // the 64-bit method fields in the ImageHeader may need a negative `delta`.
- reinterpret_cast<ImageHeader*>(space->Begin())->RelocateImage(
- (reinterpret_cast32<uint32_t>(space->Begin()) < diff)
- ? -static_cast<int64_t>(-diff) : static_cast<int64_t>(diff));
-
- // Patch fields and methods.
- const ImageHeader& image_header = space->GetImageHeader();
- PatchArtFieldVisitor field_visitor(diff);
- image_header.VisitPackedArtFields(&field_visitor, space->Begin());
- PatchArtMethodVisitor<kPointerSize> method_visitor(diff);
- image_header.VisitPackedArtMethods(&method_visitor, space->Begin(), kPointerSize);
- auto method_table_visitor = [diff](ArtMethod* method) {
- DCHECK(method != nullptr);
- return RelocatedAddress(method, diff);
- };
- image_header.VisitPackedImTables(method_table_visitor, space->Begin(), kPointerSize);
- image_header.VisitPackedImtConflictTables(method_table_visitor, space->Begin(), kPointerSize);
-
- // Patch the intern table.
- if (image_header.GetInternedStringsSection().Size() != 0u) {
- const uint8_t* data = space->Begin() + image_header.GetInternedStringsSection().Offset();
- size_t read_count;
- InternTable::UnorderedSet temp_set(data, /* make_copy_of_data= */ false, &read_count);
- for (GcRoot<mirror::String>& slot : temp_set) {
- PatchGcRoot</* kMayBeNull */ false>(diff, &slot);
- }
- }
-
- // Patch the class table and classes, so that we can traverse class hierarchy to
- // determine the types of other objects when we visit them later.
- if (image_header.GetClassTableSection().Size() != 0u) {
- uint8_t* data = space->Begin() + image_header.GetClassTableSection().Offset();
- size_t read_count;
- ClassTable::ClassSet temp_set(data, /* make_copy_of_data= */ false, &read_count);
- DCHECK(!temp_set.empty());
- ClassTableVisitor class_table_visitor(diff);
- for (ClassTable::TableSlot& slot : temp_set) {
- slot.VisitRoot(class_table_visitor);
- mirror::Class* klass = slot.Read<kWithoutReadBarrier>();
- DCHECK(klass != nullptr);
- patched_objects.MarkVisited(klass);
- patch_object_visitor.VisitClass(klass);
- if (kIsDebugBuild) {
- mirror::Class* class_class = klass->GetClass<kVerifyNone, kWithoutReadBarrier>();
- if (dcheck_class_class == nullptr) {
- dcheck_class_class = class_class;
- } else {
- CHECK_EQ(class_class, dcheck_class_class);
- }
- }
- // Then patch the non-embedded vtable and iftable.
- mirror::PointerArray* vtable = klass->GetVTable<kVerifyNone, kWithoutReadBarrier>();
- if (vtable != nullptr && !patched_objects.IsVisited(vtable)) {
- patched_objects.MarkVisited(vtable);
- patch_object_visitor.VisitPointerArray(vtable);
- }
- auto* iftable = klass->GetIfTable<kVerifyNone, kWithoutReadBarrier>();
- if (iftable != nullptr) {
- int32_t ifcount = klass->GetIfTableCount<kVerifyNone, kWithoutReadBarrier>();
- for (int32_t i = 0; i != ifcount; ++i) {
- mirror::PointerArray* unpatched_ifarray =
- iftable->GetMethodArrayOrNull<kVerifyNone, kWithoutReadBarrier>(i);
- if (unpatched_ifarray != nullptr) {
- // The iftable has not been patched, so we need to explicitly adjust the pointer.
- mirror::PointerArray* ifarray = RelocatedAddress(unpatched_ifarray, diff);
- if (!patched_objects.IsVisited(ifarray)) {
- patched_objects.MarkVisited(ifarray);
- patch_object_visitor.VisitPointerArray(ifarray);
- }
- }
- }
- }
- }
- }
- }
-
- // Patch class roots now, so that we can recognize mirror::Method and mirror::Constructor.
- ObjPtr<mirror::Class> method_class;
- ObjPtr<mirror::Class> constructor_class;
- {
- const ImageSpace* space = spaces.front().get();
- const ImageHeader& image_header = space->GetImageHeader();
-
- ObjPtr<mirror::ObjectArray<mirror::Object>> image_roots =
- image_header.GetImageRoots<kWithoutReadBarrier>();
- patched_objects.MarkVisited(image_roots.Ptr());
- patch_object_visitor.VisitObject(image_roots.Ptr());
-
- ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots =
- ObjPtr<mirror::ObjectArray<mirror::Class>>::DownCast(MakeObjPtr(
- image_header.GetImageRoot<kWithoutReadBarrier>(ImageHeader::kClassRoots)));
- patched_objects.MarkVisited(class_roots.Ptr());
- patch_object_visitor.VisitObject(class_roots.Ptr());
-
- method_class = GetClassRoot<mirror::Method, kWithoutReadBarrier>(class_roots);
- constructor_class = GetClassRoot<mirror::Constructor, kWithoutReadBarrier>(class_roots);
- }
-
- for (size_t s = 0, size = spaces.size(); s != size; ++s) {
- const ImageSpace* space = spaces[s].get();
- const ImageHeader& image_header = space->GetImageHeader();
-
- static_assert(IsAligned<kObjectAlignment>(sizeof(ImageHeader)), "Header alignment check");
- uint32_t objects_end = image_header.GetObjectsSection().Size();
- DCHECK_ALIGNED(objects_end, kObjectAlignment);
- for (uint32_t pos = sizeof(ImageHeader); pos != objects_end; ) {
- mirror::Object* object = reinterpret_cast<mirror::Object*>(space->Begin() + pos);
- if (!patched_objects.IsVisited(object)) {
- // This is the last pass over objects, so we do not need to MarkVisited().
- patch_object_visitor.VisitObject(object);
- mirror::Class* klass = object->GetClass<kVerifyNone, kWithoutReadBarrier>();
- if (klass->IsDexCacheClass<kVerifyNone>()) {
- // Patch dex cache array pointers and elements.
- mirror::DexCache* dex_cache = object->AsDexCache<kVerifyNone, kWithoutReadBarrier>();
- patch_object_visitor.VisitDexCacheArrays(dex_cache);
- } else if (klass == method_class || klass == constructor_class) {
- // Patch the ArtMethod* in the mirror::Executable subobject.
- ObjPtr<mirror::Executable> as_executable =
- ObjPtr<mirror::Executable>::DownCast(MakeObjPtr(object));
- ArtMethod* unpatched_method = as_executable->GetArtMethod<kVerifyNone>();
- ArtMethod* patched_method = RelocatedAddress(unpatched_method, diff);
- as_executable->SetArtMethod</* kTransactionActive */ false,
- /* kCheckTransaction */ true,
- kVerifyNone>(patched_method);
- }
- }
- pos += RoundUp(object->SizeOf<kVerifyNone>(), kObjectAlignment);
- }
- }
- }
-
- static void MaybeRelocateSpaces(const std::vector<std::unique_ptr<ImageSpace>>& spaces,
- TimingLogger* logger)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- TimingLogger::ScopedTiming timing("MaybeRelocateSpaces", logger);
- ImageSpace* first_space = spaces.front().get();
- const ImageHeader& first_space_header = first_space->GetImageHeader();
- uint32_t diff =
- static_cast<uint32_t>(first_space->Begin() - first_space_header.GetImageBegin());
- if (!Runtime::Current()->ShouldRelocate()) {
- DCHECK_EQ(diff, 0u);
- return;
- }
-
- PointerSize pointer_size = first_space_header.GetPointerSize();
- if (pointer_size == PointerSize::k64) {
- DoRelocateSpaces<PointerSize::k64>(spaces, diff);
- } else {
- DoRelocateSpaces<PointerSize::k32>(spaces, diff);
- }
- }
-
- static void InitRuntimeMethods(const std::vector<std::unique_ptr<ImageSpace>>& spaces)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- Runtime* runtime = Runtime::Current();
- DCHECK(!runtime->HasResolutionMethod());
- DCHECK(!spaces.empty());
- ImageSpace* space = spaces[0].get();
- const ImageHeader& image_header = space->GetImageHeader();
- // Use oat_file_non_owned_ from the `space` to set the runtime methods.
- runtime->SetInstructionSet(space->oat_file_non_owned_->GetOatHeader().GetInstructionSet());
- runtime->SetResolutionMethod(image_header.GetImageMethod(ImageHeader::kResolutionMethod));
- runtime->SetImtConflictMethod(image_header.GetImageMethod(ImageHeader::kImtConflictMethod));
- runtime->SetImtUnimplementedMethod(
- image_header.GetImageMethod(ImageHeader::kImtUnimplementedMethod));
- runtime->SetCalleeSaveMethod(
- image_header.GetImageMethod(ImageHeader::kSaveAllCalleeSavesMethod),
- CalleeSaveType::kSaveAllCalleeSaves);
- runtime->SetCalleeSaveMethod(
- image_header.GetImageMethod(ImageHeader::kSaveRefsOnlyMethod),
- CalleeSaveType::kSaveRefsOnly);
- runtime->SetCalleeSaveMethod(
- image_header.GetImageMethod(ImageHeader::kSaveRefsAndArgsMethod),
- CalleeSaveType::kSaveRefsAndArgs);
- runtime->SetCalleeSaveMethod(
- image_header.GetImageMethod(ImageHeader::kSaveEverythingMethod),
- CalleeSaveType::kSaveEverything);
- runtime->SetCalleeSaveMethod(
- image_header.GetImageMethod(ImageHeader::kSaveEverythingMethodForClinit),
- CalleeSaveType::kSaveEverythingForClinit);
- runtime->SetCalleeSaveMethod(
- image_header.GetImageMethod(ImageHeader::kSaveEverythingMethodForSuspendCheck),
- CalleeSaveType::kSaveEverythingForSuspendCheck);
- }
-
std::unique_ptr<ImageSpace> Load(const std::string& image_location,
const std::string& image_filename,
bool validate_oat_file,
- TimingLogger* logger,
/*inout*/MemMap* image_reservation,
/*inout*/MemMap* oat_reservation,
/*out*/std::string* error_msg)
@@ -1998,8 +1629,7 @@
return Loader::Init(image_filename.c_str(),
image_location.c_str(),
validate_oat_file,
- /* oat_file= */ nullptr,
- logger,
+ /* oat_file */ nullptr,
image_reservation,
oat_reservation,
error_msg);
@@ -2012,14 +1642,14 @@
/*out*/ std::vector<std::string>* all_locations,
/*out*/ std::string* error_msg) {
std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(image_filename);
- std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd= */ -1,
+ std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
oat_filename,
oat_filename,
- /* requested_base= */ nullptr,
- /* executable= */ false,
- /* low_4gb= */ false,
- /* abs_dex_location= */ nullptr,
- /* reservation= */ nullptr,
+ /* requested_base */ nullptr,
+ /* executable */ false,
+ /* low_4gb */ false,
+ /* abs_dex_location */ nullptr,
+ /* reservation */ nullptr,
error_msg));
if (oat_file == nullptr) {
*error_msg = StringPrintf("Failed to open oat file '%s' for image file %s: %s",
@@ -2065,35 +1695,18 @@
DCHECK(!image_reservation->IsValid());
size_t total_size =
dchecked_integral_cast<size_t>(oat_end - image_start) + extra_reservation_size;
- bool relocate = Runtime::Current()->ShouldRelocate();
- // If relocating, choose a random address for ALSR. Since mmap() does not randomize
- // on its own, over-allocate and select a sub-region at a random offset.
- size_t randomize_size = relocate
- ? RoundUp(ART_BASE_ADDRESS_MAX_DELTA - ART_BASE_ADDRESS_MIN_DELTA, kPageSize) + kPageSize
- : 0u;
*image_reservation =
MemMap::MapAnonymous("Boot image reservation",
- relocate ? nullptr : reinterpret_cast32<uint8_t*>(image_start),
- total_size + randomize_size,
+ reinterpret_cast32<uint8_t*>(image_start),
+ total_size,
PROT_NONE,
- /* low_4gb= */ true,
- /* reuse= */ false,
- /* reservation= */ nullptr,
+ /* low_4gb */ true,
+ /* reuse */ false,
+ /* reservation */ nullptr,
error_msg);
if (!image_reservation->IsValid()) {
return false;
}
- if (relocate) {
- uint32_t offset = RoundDown(GetRandomNumber<uint32_t>(0u, randomize_size), kPageSize);
- if (offset != 0u) {
- MemMap unmapped_head = image_reservation->TakeReservedMemory(offset);
- // Let the destructor of `unmapped_head` unmap the memory before the chunk we shall use.
- }
- DCHECK_LE(total_size, image_reservation->Size());
- MemMap tmp = image_reservation->TakeReservedMemory(total_size);
- tmp.swap(*image_reservation);
- // Let the destructor of `tmp` unmap the memory after the chunk we shall use.
- }
DCHECK(!extra_reservation->IsValid());
if (extra_reservation_size != 0u) {
DCHECK_ALIGNED(extra_reservation_size, kPageSize);
@@ -2107,10 +1720,6 @@
return false;
}
}
- uint32_t diff = reinterpret_cast32<uint32_t>(image_reservation->Begin()) - image_start;
- image_start += diff;
- image_end += diff;
- oat_end += diff;
DCHECK(!oat_reservation->IsValid());
*oat_reservation = image_reservation->RemapAtEnd(reinterpret_cast32<uint8_t*>(image_end),
"Boot image oat reservation",
@@ -2229,8 +1838,11 @@
const std::string& dalvik_cache = loader.GetDalvikCache();
DCHECK(!dalvik_cache.empty());
std::string local_error_msg;
+ // All secondary images are verified when the primary image is verified.
+ bool verified =
+ VerifyImage(image_location.c_str(), dalvik_cache.c_str(), image_isa, &local_error_msg);
bool check_space = CheckSpace(dalvik_cache, &local_error_msg);
- if (!check_space) {
+ if (!verified || !check_space) {
LOG(WARNING) << local_error_msg << " Preemptively pruning the dalvik cache.";
PruneDalvikCache(image_isa);
@@ -2246,9 +1858,27 @@
// Collect all the errors.
std::vector<std::string> error_msgs;
- // Step 1: Check if we have an existing image in /system.
+ // Step 1: Check if we have an existing image in the dalvik cache.
+ if (loader.HasCache()) {
+ std::string local_error_msg;
+ // If we have system image, validate system image checksums, otherwise validate the oat file.
+ if (loader.LoadFromDalvikCache(/* validate_system_checksums */ loader.HasSystem(),
+ /* validate_oat_file */ !loader.HasSystem(),
+ extra_reservation_size,
+ boot_image_spaces,
+ extra_reservation,
+ &local_error_msg)) {
+ return true;
+ }
+ error_msgs.push_back(local_error_msg);
+ }
- if (loader.HasSystem()) {
+ // Step 2: We have an existing image in /system.
+
+ // Step 2.a: We are not required to relocate it. Then we can use it directly.
+ bool relocate = Runtime::Current()->ShouldRelocate();
+
+ if (loader.HasSystem() && !relocate) {
std::string local_error_msg;
if (loader.LoadFromSystem(extra_reservation_size,
boot_image_spaces,
@@ -2259,17 +1889,29 @@
error_msgs.push_back(local_error_msg);
}
- // Step 2: Check if we have an existing image in the dalvik cache.
- if (loader.HasCache()) {
+ // Step 2.b: We require a relocated image. Then we must patch it.
+ if (loader.HasSystem() && relocate) {
std::string local_error_msg;
- if (loader.LoadFromDalvikCache(/* validate_oat_file= */ true,
- extra_reservation_size,
- boot_image_spaces,
- extra_reservation,
- &local_error_msg)) {
- return true;
+ if (!dex2oat_enabled) {
+ local_error_msg = "Patching disabled.";
+ } else if (ImageCreationAllowed(loader.IsGlobalCache(), image_isa, &local_error_msg)) {
+ bool patch_success = RelocateImage(
+ image_location.c_str(), loader.GetDalvikCache().c_str(), image_isa, &local_error_msg);
+ if (patch_success) {
+ if (loader.LoadFromDalvikCache(/* validate_system_checksums */ false,
+ /* validate_oat_file */ false,
+ extra_reservation_size,
+ boot_image_spaces,
+ extra_reservation,
+ &local_error_msg)) {
+ return true;
+ }
+ }
}
- error_msgs.push_back(local_error_msg);
+ error_msgs.push_back(StringPrintf("Cannot relocate image %s to %s: %s",
+ image_location.c_str(),
+ loader.GetCacheFilename().c_str(),
+ local_error_msg.c_str()));
}
// Step 3: We do not have an existing image in /system,
@@ -2282,7 +1924,8 @@
bool compilation_success =
GenerateImage(loader.GetCacheFilename(), image_isa, &local_error_msg);
if (compilation_success) {
- if (loader.LoadFromDalvikCache(/* validate_oat_file= */ false,
+ if (loader.LoadFromDalvikCache(/* validate_system_checksums */ false,
+ /* validate_oat_file */ false,
extra_reservation_size,
boot_image_spaces,
extra_reservation,
@@ -2341,13 +1984,13 @@
std::unique_ptr<ImageSpace> ImageSpace::CreateFromAppImage(const char* image,
const OatFile* oat_file,
std::string* error_msg) {
- return Loader::InitAppImage(image,
- image,
- /* validate_oat_file= */ false,
- oat_file,
- /* image_reservation= */ nullptr,
- /* oat_reservation= */ nullptr,
- error_msg);
+ return Loader::Init(image,
+ image,
+ /* validate_oat_file */ false,
+ oat_file,
+ /* image_reservation */ nullptr,
+ /* oat_reservation */ nullptr,
+ error_msg);
}
const OatFile* ImageSpace::GetOatFile() const {
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 4db6fdc..a2490ac 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -57,9 +57,9 @@
// Reads the image header from the specified image location for the
// instruction set image_isa. Returns null on failure, with
// reason in error_msg.
- static std::unique_ptr<ImageHeader> ReadImageHeader(const char* image_location,
- InstructionSet image_isa,
- std::string* error_msg);
+ static ImageHeader* ReadImageHeader(const char* image_location,
+ InstructionSet image_isa,
+ std::string* error_msg);
// Give access to the OatFile.
const OatFile* GetOatFile() const;
diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc
index cc70788..299a413 100644
--- a/runtime/gc/space/image_space_test.cc
+++ b/runtime/gc/space/image_space_test.cc
@@ -110,7 +110,7 @@
EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
}
-template <bool kImage, bool kRelocate, bool kImageDex2oat>
+template <bool kImage, bool kRelocate, bool kPatchoat, bool kImageDex2oat>
class ImageSpaceLoadingTest : public CommonRuntimeTest {
protected:
void SetUpRuntimeOptions(RuntimeOptions* options) override {
@@ -119,6 +119,9 @@
nullptr);
}
options->emplace_back(kRelocate ? "-Xrelocate" : "-Xnorelocate", nullptr);
+ if (!kPatchoat) {
+ options->emplace_back("-Xpatchoat:false", nullptr);
+ }
options->emplace_back(kImageDex2oat ? "-Ximage-dex2oat" : "-Xnoimage-dex2oat", nullptr);
// We want to test the relocation behavior of ImageSpace. As such, don't pretend we're a
@@ -127,22 +130,27 @@
}
};
-using ImageSpaceDex2oatTest = ImageSpaceLoadingTest<false, true, true>;
+using ImageSpacePatchoatTest = ImageSpaceLoadingTest<true, true, true, true>;
+TEST_F(ImageSpacePatchoatTest, Test) {
+ EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
+}
+
+using ImageSpaceDex2oatTest = ImageSpaceLoadingTest<false, true, false, true>;
TEST_F(ImageSpaceDex2oatTest, Test) {
EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
}
-using ImageSpaceNoDex2oatTest = ImageSpaceLoadingTest<true, true, false>;
-TEST_F(ImageSpaceNoDex2oatTest, Test) {
+using ImageSpaceNoDex2oatNoPatchoatTest = ImageSpaceLoadingTest<true, true, false, false>;
+TEST_F(ImageSpaceNoDex2oatNoPatchoatTest, Test) {
+ EXPECT_TRUE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
+}
+
+using ImageSpaceNoRelocateNoDex2oatNoPatchoatTest = ImageSpaceLoadingTest<true, false, false, false>;
+TEST_F(ImageSpaceNoRelocateNoDex2oatNoPatchoatTest, Test) {
EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
}
-using ImageSpaceNoRelocateNoDex2oatTest = ImageSpaceLoadingTest<true, false, false>;
-TEST_F(ImageSpaceNoRelocateNoDex2oatTest, Test) {
- EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
-}
-
-class NoAccessAndroidDataTest : public ImageSpaceLoadingTest<false, true, true> {
+class NoAccessAndroidDataTest : public ImageSpaceLoadingTest<false, true, false, true> {
protected:
void SetUpRuntimeOptions(RuntimeOptions* options) override {
const char* android_data = getenv("ANDROID_DATA");
@@ -161,7 +169,7 @@
CHECK_NE(fd, -1) << strerror(errno);
result = close(fd);
CHECK_EQ(result, 0) << strerror(errno);
- ImageSpaceLoadingTest<false, true, true>::SetUpRuntimeOptions(options);
+ ImageSpaceLoadingTest<false, true, false, true>::SetUpRuntimeOptions(options);
}
void TearDown() override {
@@ -171,7 +179,7 @@
CHECK_EQ(result, 0) << strerror(errno);
result = setenv("ANDROID_DATA", old_android_data_.c_str(), /* replace */ 1);
CHECK_EQ(result, 0) << strerror(errno);
- ImageSpaceLoadingTest<false, true, true>::TearDown();
+ ImageSpaceLoadingTest<false, true, false, true>::TearDown();
}
private:
diff --git a/runtime/image-inl.h b/runtime/image-inl.h
index 9fde669..c527f6f 100644
--- a/runtime/image-inl.h
+++ b/runtime/image-inl.h
@@ -49,38 +49,6 @@
return image_roots;
}
-inline void ImageHeader::VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) const {
- const ImageSection& fields = GetFieldsSection();
- for (size_t pos = 0; pos < fields.Size(); ) {
- auto* array = reinterpret_cast<LengthPrefixedArray<ArtField>*>(base + fields.Offset() + pos);
- for (size_t i = 0; i < array->size(); ++i) {
- visitor->Visit(&array->At(i, sizeof(ArtField)));
- }
- pos += array->ComputeSize(array->size());
- }
-}
-
-inline void ImageHeader::VisitPackedArtMethods(ArtMethodVisitor* visitor,
- uint8_t* base,
- PointerSize pointer_size) const {
- const size_t method_alignment = ArtMethod::Alignment(pointer_size);
- const size_t method_size = ArtMethod::Size(pointer_size);
- const ImageSection& methods = GetMethodsSection();
- for (size_t pos = 0; pos < methods.Size(); ) {
- auto* array = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(base + methods.Offset() + pos);
- for (size_t i = 0; i < array->size(); ++i) {
- visitor->Visit(&array->At(i, method_size, method_alignment));
- }
- pos += array->ComputeSize(array->size(), method_size, method_alignment);
- }
- const ImageSection& runtime_methods = GetRuntimeMethodsSection();
- for (size_t pos = 0; pos < runtime_methods.Size(); ) {
- auto* method = reinterpret_cast<ArtMethod*>(base + runtime_methods.Offset() + pos);
- visitor->Visit(method);
- pos += method_size;
- }
-}
-
template <typename Visitor>
inline void ImageHeader::VisitPackedImTables(const Visitor& visitor,
uint8_t* base,
diff --git a/runtime/image.cc b/runtime/image.cc
index bdf045b..028c515 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -77,7 +77,7 @@
std::copy_n(sections, kSectionCount, sections_);
}
-void ImageHeader::RelocateImage(int64_t delta) {
+void ImageHeader::RelocateImage(off_t delta) {
CHECK_ALIGNED(delta, kPageSize) << " patch delta must be page aligned";
oat_file_begin_ += delta;
oat_data_begin_ += delta;
@@ -88,12 +88,12 @@
RelocateImageMethods(delta);
}
-void ImageHeader::RelocateImageObjects(int64_t delta) {
+void ImageHeader::RelocateImageObjects(off_t delta) {
image_begin_ += delta;
image_roots_ += delta;
}
-void ImageHeader::RelocateImageMethods(int64_t delta) {
+void ImageHeader::RelocateImageMethods(off_t delta) {
for (size_t i = 0; i < kImageMethodsCount; ++i) {
image_methods_[i] += delta;
}
@@ -152,6 +152,38 @@
}
}
+void ImageHeader::VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) const {
+ const ImageSection& fields = GetFieldsSection();
+ for (size_t pos = 0; pos < fields.Size(); ) {
+ auto* array = reinterpret_cast<LengthPrefixedArray<ArtField>*>(base + fields.Offset() + pos);
+ for (size_t i = 0; i < array->size(); ++i) {
+ visitor->Visit(&array->At(i, sizeof(ArtField)));
+ }
+ pos += array->ComputeSize(array->size());
+ }
+}
+
+void ImageHeader::VisitPackedArtMethods(ArtMethodVisitor* visitor,
+ uint8_t* base,
+ PointerSize pointer_size) const {
+ const size_t method_alignment = ArtMethod::Alignment(pointer_size);
+ const size_t method_size = ArtMethod::Size(pointer_size);
+ const ImageSection& methods = GetMethodsSection();
+ for (size_t pos = 0; pos < methods.Size(); ) {
+ auto* array = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(base + methods.Offset() + pos);
+ for (size_t i = 0; i < array->size(); ++i) {
+ visitor->Visit(&array->At(i, method_size, method_alignment));
+ }
+ pos += array->ComputeSize(array->size(), method_size, method_alignment);
+ }
+ const ImageSection& runtime_methods = GetRuntimeMethodsSection();
+ for (size_t pos = 0; pos < runtime_methods.Size(); ) {
+ auto* method = reinterpret_cast<ArtMethod*>(base + runtime_methods.Offset() + pos);
+ visitor->Visit(method);
+ pos += method_size;
+ }
+}
+
PointerSize ImageHeader::GetPointerSize() const {
return ConvertToPointerSize(pointer_size_);
}
diff --git a/runtime/image.h b/runtime/image.h
index 6acb64b..af092ad 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -175,11 +175,11 @@
return pointer_size_;
}
- int32_t GetPatchDelta() const {
+ off_t GetPatchDelta() const {
return patch_delta_;
}
- void SetPatchDelta(int32_t patch_delta) {
+ void SetPatchDelta(off_t patch_delta) {
patch_delta_ = patch_delta;
}
@@ -299,9 +299,9 @@
ObjPtr<mirror::ObjectArray<mirror::Object>> GetImageRoots() const
REQUIRES_SHARED(Locks::mutator_lock_);
- void RelocateImage(int64_t delta);
- void RelocateImageMethods(int64_t delta);
- void RelocateImageObjects(int64_t delta);
+ void RelocateImage(off_t delta);
+ void RelocateImageMethods(off_t delta);
+ void RelocateImageObjects(off_t delta);
bool CompilePic() const {
return compile_pic_ != 0;
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 00b947a..5ba3e18 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -185,11 +185,6 @@
return item.IsNull();
}
};
- using UnorderedSet = HashSet<GcRoot<mirror::String>,
- GcRootEmptyFn,
- StringHashEquals,
- StringHashEquals,
- TrackingAllocator<GcRoot<mirror::String>, kAllocatorTagInternTable>>;
// Table which holds pre zygote and post zygote interned strings. There is one instance for
// weak interns and strong interns.
@@ -222,6 +217,9 @@
REQUIRES(Locks::intern_table_lock_) REQUIRES_SHARED(Locks::mutator_lock_);
private:
+ typedef HashSet<GcRoot<mirror::String>, GcRootEmptyFn, StringHashEquals, StringHashEquals,
+ TrackingAllocator<GcRoot<mirror::String>, kAllocatorTagInternTable>> UnorderedSet;
+
void SweepWeaks(UnorderedSet* set, IsMarkedVisitor* visitor)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
@@ -289,7 +287,6 @@
// Weak root state, used for concurrent system weak processing and more.
gc::WeakRootState weak_root_state_ GUARDED_BY(Locks::intern_table_lock_);
- friend class gc::space::ImageSpace;
friend class linker::ImageWriter;
friend class Transaction;
ART_FRIEND_TEST(InternTableTest, CrossHash);
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index b3bf1ba..8b4fe44 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -78,7 +78,7 @@
GcRoot<mirror::String> str(mirror::String::AllocFromModifiedUtf8(soa.Self(), "00000000"));
MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
- for (InternTable::UnorderedSet& table : t.strong_interns_.tables_) {
+ for (InternTable::Table::UnorderedSet& table : t.strong_interns_.tables_) {
// The negative hash value shall be 32-bit wide on every host.
ASSERT_TRUE(IsUint<32>(table.hashfn_(str)));
}
diff --git a/runtime/mirror/executable.cc b/runtime/mirror/executable.cc
index 24e2047..fac3319 100644
--- a/runtime/mirror/executable.cc
+++ b/runtime/mirror/executable.cc
@@ -38,6 +38,18 @@
template bool Executable::CreateFromArtMethod<PointerSize::k64, false>(ArtMethod* method);
template bool Executable::CreateFromArtMethod<PointerSize::k64, true>(ArtMethod* method);
+ArtMethod* Executable::GetArtMethod() {
+ return reinterpret_cast<ArtMethod*>(GetField64(ArtMethodOffset()));
+}
+
+template <bool kTransactionActive>
+void Executable::SetArtMethod(ArtMethod* method) {
+ SetField64<kTransactionActive>(ArtMethodOffset(), reinterpret_cast<uint64_t>(method));
+}
+
+template void Executable::SetArtMethod<false>(ArtMethod* method);
+template void Executable::SetArtMethod<true>(ArtMethod* method);
+
mirror::Class* Executable::GetDeclaringClass() {
return GetFieldObject<mirror::Class>(DeclaringClassOffset());
}
diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h
index 14c9d4c..bf66d79 100644
--- a/runtime/mirror/executable.h
+++ b/runtime/mirror/executable.h
@@ -18,7 +18,7 @@
#define ART_RUNTIME_MIRROR_EXECUTABLE_H_
#include "accessible_object.h"
-#include "object-inl.h"
+#include "object.h"
#include "read_barrier_option.h"
namespace art {
@@ -36,19 +36,10 @@
bool CreateFromArtMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ArtMethod* GetArtMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
- return reinterpret_cast64<ArtMethod*>(GetField64<kVerifyFlags>(ArtMethodOffset()));
- }
-
- template <bool kTransactionActive = false,
- bool kCheckTransaction = true,
- VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- void SetArtMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
- SetField64<kTransactionActive, kCheckTransaction, kVerifyFlags>(
- ArtMethodOffset(), reinterpret_cast64<uint64_t>(method));
- }
-
+ ArtMethod* GetArtMethod() REQUIRES_SHARED(Locks::mutator_lock_);
+ // Only used by the image writer.
+ template <bool kTransactionActive = false>
+ void SetArtMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
mirror::Class* GetDeclaringClass() REQUIRES_SHARED(Locks::mutator_lock_);
static MemberOffset ArtMethodOffset() {
diff --git a/runtime/mirror/object-refvisitor-inl.h b/runtime/mirror/object-refvisitor-inl.h
index f0bee5a..748f03b 100644
--- a/runtime/mirror/object-refvisitor-inl.h
+++ b/runtime/mirror/object-refvisitor-inl.h
@@ -33,8 +33,8 @@
typename JavaLangRefVisitor>
inline void Object::VisitReferences(const Visitor& visitor,
const JavaLangRefVisitor& ref_visitor) {
- visitor(this, ClassOffset(), /* is_static= */ false);
ObjPtr<Class> klass = GetClass<kVerifyFlags, kReadBarrierOption>();
+ visitor(this, ClassOffset(), false);
const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>();
if (LIKELY(class_flags == kClassFlagNormal)) {
DCHECK((!klass->IsVariableSize<kVerifyFlags>()));
diff --git a/runtime/noop_compiler_callbacks.h b/runtime/noop_compiler_callbacks.h
index 439f485..496a6f3 100644
--- a/runtime/noop_compiler_callbacks.h
+++ b/runtime/noop_compiler_callbacks.h
@@ -31,6 +31,11 @@
void ClassRejected(ClassReference ref ATTRIBUTE_UNUSED) override {}
+ // This is only used by compilers which need to be able to run without relocation even when it
+ // would normally be enabled. For example the patchoat executable, and dex2oat --image, both need
+ // to disable the relocation since both deal with writing out the images directly.
+ bool IsRelocationPossible() override { return false; }
+
verifier::VerifierDeps* GetVerifierDeps() const override { return nullptr; }
private:
diff --git a/runtime/obj_ptr-inl.h b/runtime/obj_ptr-inl.h
index b949c96..f1e3b50 100644
--- a/runtime/obj_ptr-inl.h
+++ b/runtime/obj_ptr-inl.h
@@ -24,27 +24,18 @@
namespace art {
template<class MirrorType>
-inline uintptr_t ObjPtr<MirrorType>::GetCurrentTrimedCookie() {
- Thread* self = Thread::Current();
- if (UNLIKELY(self == nullptr)) {
- return kCookieMask;
- }
- return self->GetPoisonObjectCookie() & kCookieMask;
-}
-
-template<class MirrorType>
inline bool ObjPtr<MirrorType>::IsValid() const {
if (!kObjPtrPoisoning || IsNull()) {
return true;
}
- return GetCookie() == GetCurrentTrimedCookie();
+ return GetCookie() == TrimCookie(Thread::Current()->GetPoisonObjectCookie());
}
template<class MirrorType>
inline void ObjPtr<MirrorType>::AssertValid() const {
if (kObjPtrPoisoning) {
CHECK(IsValid()) << "Stale object pointer " << PtrUnchecked() << " , expected cookie "
- << GetCurrentTrimedCookie() << " but got " << GetCookie();
+ << TrimCookie(Thread::Current()->GetPoisonObjectCookie()) << " but got " << GetCookie();
}
}
@@ -56,7 +47,9 @@
DCHECK_LE(ref, 0xFFFFFFFFU);
ref >>= kObjectAlignmentShift;
// Put cookie in high bits.
- ref |= GetCurrentTrimedCookie() << kCookieShift;
+ Thread* self = Thread::Current();
+ DCHECK(self != nullptr);
+ ref |= self->GetPoisonObjectCookie() << kCookieShift;
}
return ref;
}
diff --git a/runtime/obj_ptr.h b/runtime/obj_ptr.h
index 60e21ab..e421d87 100644
--- a/runtime/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -156,7 +156,9 @@
private:
// Trim off high bits of thread local cookie.
- ALWAYS_INLINE static uintptr_t GetCurrentTrimedCookie();
+ ALWAYS_INLINE static uintptr_t TrimCookie(uintptr_t cookie) {
+ return cookie & kCookieMask;
+ }
ALWAYS_INLINE uintptr_t GetCookie() const {
return reference_ >> kCookieShift;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index a51d457..6878cc0 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -2499,7 +2499,7 @@
}
bool Runtime::CanRelocate() const {
- return !IsAotCompiler();
+ return !IsAotCompiler() || compiler_callbacks_->IsRelocationPossible();
}
bool Runtime::IsCompilingBootImage() const {
diff --git a/test/119-noimage-patchoat/check b/test/119-noimage-patchoat/check
new file mode 100755
index 0000000..d124ce8
--- /dev/null
+++ b/test/119-noimage-patchoat/check
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Strip the process pids and line numbers from exact error messages.
+sed -e '/^dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
+
+diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/119-noimage-patchoat/expected.txt b/test/119-noimage-patchoat/expected.txt
new file mode 100644
index 0000000..9b9db58
--- /dev/null
+++ b/test/119-noimage-patchoat/expected.txt
@@ -0,0 +1,11 @@
+Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false
+JNI_OnLoad called
+Has image is false, is image dex2oat enabled is false.
+Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false -Xno-dex-file-fallback
+Failed to initialize runtime (check log for details)
+Run -Ximage-dex2oat
+JNI_OnLoad called
+Has image is true, is image dex2oat enabled is true.
+Run default
+JNI_OnLoad called
+Has image is true, is image dex2oat enabled is true.
diff --git a/test/119-noimage-patchoat/info.txt b/test/119-noimage-patchoat/info.txt
new file mode 100644
index 0000000..6b85368
--- /dev/null
+++ b/test/119-noimage-patchoat/info.txt
@@ -0,0 +1 @@
+Test that disables patchoat'ing the image.
diff --git a/test/119-noimage-patchoat/run b/test/119-noimage-patchoat/run
new file mode 100644
index 0000000..497dc4a
--- /dev/null
+++ b/test/119-noimage-patchoat/run
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+flags="$@"
+
+# Force relocation otherwise we will just use the already created core.oat/art pair.
+# Note: relocate is the default.
+if [[ "${flags}" == *--no-relocate* ]] ; then
+ echo "Test 119-noimage-patchoat is not intended to run in no-relocate mode."
+ exit 1
+fi
+
+if [[ $@ == *--host* ]]; then
+ false_bin="/bin/false"
+else
+ false_bin="/system/bin/false"
+fi
+
+# Make sure we can run without an image file.
+echo "Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false"
+${RUN} ${flags} ${BPATH} --runtime-option -Xnoimage-dex2oat \
+ --runtime-option -Xpatchoat:${false_bin}
+return_status1=$?
+
+# Make sure we cannot run without an image file without fallback.
+echo "Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false -Xno-dex-file-fallback"
+${RUN} ${flags} ${BPATH} --runtime-option -Xnoimage-dex2oat \
+ --runtime-option -Xpatchoat:${false_bin} --runtime-option -Xno-dex-file-fallback
+# This second run is expected to fail: invert the return status of the previous command.
+return_status2=$((! $?))
+
+# Make sure we can run with the image file.
+echo "Run -Ximage-dex2oat"
+${RUN} ${flags} ${BPATH} --runtime-option -Ximage-dex2oat
+return_status3=$?
+
+# Make sure we can run with the default settings.
+echo "Run default"
+${RUN} ${flags} ${BPATH}
+return_status4=$?
+
+# Make sure we don't silently ignore an early failure.
+(exit $return_status1) && (exit $return_status2) && (exit $return_status3) && (exit $return_status4)
diff --git a/test/119-noimage-patchoat/src/Main.java b/test/119-noimage-patchoat/src/Main.java
new file mode 100644
index 0000000..6a70f58
--- /dev/null
+++ b/test/119-noimage-patchoat/src/Main.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+ boolean hasImage = hasImage();
+ System.out.println(
+ "Has image is " + hasImage + ", is image dex2oat enabled is "
+ + isImageDex2OatEnabled() + ".");
+
+ if (hasImage && !isImageDex2OatEnabled()) {
+ throw new Error("Image with dex2oat disabled runs with an oat file");
+ } else if (!hasImage && isImageDex2OatEnabled()) {
+ throw new Error("Image with dex2oat enabled runs without an oat file");
+ }
+ }
+
+ private native static boolean hasImage();
+
+ private native static boolean isImageDex2OatEnabled();
+}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index a227023..f0b88e9 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -67,7 +67,8 @@
},
{
"tests": ["117-nopatchoat",
- "118-noimage-dex2oat"],
+ "118-noimage-dex2oat",
+ "119-noimage-patchoat"],
"variant": "no-relocate",
"description": ["117-nopatchoat is not broken per-se it just doesn't",
"work (and isn't meant to) without --prebuild",
@@ -170,6 +171,7 @@
"tests": ["116-nodex2oat",
"117-nopatchoat",
"118-noimage-dex2oat",
+ "119-noimage-patchoat",
"137-cfi",
"138-duplicate-classes-check2"],
"variant": "no-image | relocate-npatchoat",
@@ -331,6 +333,7 @@
"116-nodex2oat",
"117-nopatchoat",
"118-noimage-dex2oat",
+ "119-noimage-patchoat",
"126-miranda-multidex",
"137-cfi"],
"description": "The test run dalvikvm more than once.",
@@ -759,6 +762,7 @@
"116-nodex2oat",
"117-nopatchoat",
"118-noimage-dex2oat",
+ "119-noimage-patchoat",
"127-checker-secondarydex",
"129-ThreadGetId",
"130-hprof",