Make the runtime option -Ximage a ParseStringList
Previously, the string spliting is done in multiple code locations,
including ImageSpace::BootImageLayout::LoadOrValidate and
GetPrimaryImageLocation (which may be called multiple times).
This change converts the -Ximage option from a string into a
ParseStringList<':'>.
It may be worth pointing out that this doesn't change the current code
expectation that each image can have a profile (e.g.
"/path/to/foo.art!/some/profile.prof").
There is a later plan to introduce new options of boot image fds with
ParseIntList<':'>. This change would make them more consistent.
Bug: 187327262
Test: boot looks normal
Test: dexopt looks normal
Test: TH
Change-Id: I82657cb725cda2d3b782cbe7a6e6d9a871e80ee7
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index a44a3e4..cfb79e5 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -422,7 +422,7 @@
ScopedObjectAccess soa(Thread::Current());
return gc::space::ImageSpace::LoadBootImage(/*boot_class_path=*/ boot_class_path,
/*boot_class_path_locations=*/ libcore_dex_files,
- image_location,
+ android::base::Split(image_location, ":"),
kRuntimeISA,
relocate,
/*executable=*/ true,
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 998f41a..5863e45 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -368,10 +368,11 @@
std::string error_msg;
const std::vector<std::string>& bcp = runtime->GetBootClassPath();
const std::vector<std::string>& bcp_locations = runtime->GetBootClassPathLocations();
+ const std::vector<std::string>& image_locations = runtime->GetImageLocations();
const std::string bcp_locations_path = android::base::Join(bcp_locations, ':');
if (!ImageSpace::VerifyBootClassPathChecksums(checksums,
bcp_locations_path,
- runtime->GetImageLocation(),
+ ArrayRef<const std::string>(image_locations),
ArrayRef<const std::string>(bcp_locations),
ArrayRef<const std::string>(bcp),
runtime->GetInstructionSet(),
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index cfd7f91..9b5b473 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -152,7 +152,7 @@
bool match = gc::space::ImageSpace::VerifyBootClassPathChecksums(
checksums,
oat_bcp,
- image_location,
+ ArrayRef<const std::string>(&image_location, 1),
ArrayRef<const std::string>(Runtime::Current()->GetBootClassPathLocations()),
ArrayRef<const std::string>(Runtime::Current()->GetBootClassPath()),
kRuntimeISA,
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index a3dd3c7..93a594e 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -262,7 +262,7 @@
size_t non_moving_space_capacity,
const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
- const std::string& image_file_name,
+ const std::vector<std::string>& image_file_names,
const InstructionSet image_instruction_set,
CollectorType foreground_collector_type,
CollectorType background_collector_type,
@@ -462,7 +462,7 @@
MemMap heap_reservation;
if (space::ImageSpace::LoadBootImage(boot_class_path,
boot_class_path_locations,
- image_file_name,
+ image_file_names,
image_instruction_set,
runtime->ShouldRelocate(),
/*executable=*/ !runtime->IsAotCompiler(),
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 31075b1..bd899bc 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -201,7 +201,7 @@
size_t non_moving_space_capacity,
const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
- const std::string& image_file_name,
+ const std::vector<std::string>& image_file_names,
InstructionSet image_instruction_set,
CollectorType foreground_collector_type,
CollectorType background_collector_type,
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 1627d78..5ee126c 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1411,10 +1411,10 @@
mutable android::base::unique_fd oat_fd;
};
- BootImageLayout(const std::string& image_location,
+ BootImageLayout(ArrayRef<const std::string> image_locations,
ArrayRef<const std::string> boot_class_path,
ArrayRef<const std::string> boot_class_path_locations)
- : image_location_(image_location),
+ : image_locations_(image_locations),
boot_class_path_(boot_class_path),
boot_class_path_locations_(boot_class_path_locations) {}
@@ -1485,7 +1485,7 @@
return boot_class_path_[bcp_index].substr(0u, bcp_slash_pos + 1u);
}
- bool VerifyImageLocation(const std::vector<std::string>& components,
+ bool VerifyImageLocation(ArrayRef<const std::string> components,
/*out*/size_t* named_components_count,
/*out*/std::string* error_msg);
@@ -1512,7 +1512,7 @@
const std::string& base_filename,
size_t bcp_index,
const std::string& profile_filename,
- ArrayRef<std::string> dependencies,
+ ArrayRef<const std::string> dependencies,
/*out*/std::string* error_msg);
bool CheckAndRemoveLastChunkChecksum(/*inout*/std::string_view* oat_checksums,
@@ -1527,7 +1527,7 @@
/*inout*/std::string_view* oat_checksums,
/*out*/std::string* error_msg);
- const std::string& image_location_;
+ ArrayRef<const std::string> image_locations_;
ArrayRef<const std::string> boot_class_path_;
ArrayRef<const std::string> boot_class_path_locations_;
@@ -1539,15 +1539,8 @@
};
std::string ImageSpace::BootImageLayout::GetPrimaryImageLocation() {
- size_t location_start = 0u;
- size_t location_end = image_location_.find(kComponentSeparator);
- while (location_end == location_start) {
- ++location_start;
- location_end = image_location_.find(location_start, kComponentSeparator);
- }
- std::string location = (location_end == std::string::npos)
- ? image_location_.substr(location_start)
- : image_location_.substr(location_start, location_end - location_start);
+ DCHECK(!image_locations_.empty());
+ std::string location = image_locations_[0];
if (location.find('/') == std::string::npos) {
// No path, so use the path from the first boot class path component.
size_t slash_pos = boot_class_path_.empty()
@@ -1562,7 +1555,7 @@
}
bool ImageSpace::BootImageLayout::VerifyImageLocation(
- const std::vector<std::string>& components,
+ ArrayRef<const std::string> components,
/*out*/size_t* named_components_count,
/*out*/std::string* error_msg) {
DCHECK(named_components_count != nullptr);
@@ -1853,7 +1846,7 @@
const std::string& base_filename,
size_t bcp_index,
const std::string& profile_filename,
- ArrayRef<std::string> dependencies,
+ ArrayRef<const std::string> dependencies,
/*out*/std::string* error_msg) {
DCHECK_LE(total_component_count_, next_bcp_index_);
DCHECK_LE(next_bcp_index_, bcp_index);
@@ -2080,8 +2073,7 @@
static_assert(ImageSpace::kImageChecksumPrefix == 'i', "Format prefix check.");
DCHECK(!validate || StartsWith(*oat_checksums, "i"));
- std::vector<std::string> components;
- Split(image_location_, kComponentSeparator, &components);
+ ArrayRef<const std::string> components = image_locations_;
size_t named_components_count = 0u;
if (!VerifyImageLocation(components, &named_components_count, error_msg)) {
return false;
@@ -2099,7 +2091,7 @@
DCHECK_EQ(named_component_locations.size(), named_components.size());
const size_t bcp_component_count = boot_class_path_.size();
size_t bcp_pos = 0u;
- ArrayRef<std::string> extension_dependencies;
+ ArrayRef<const std::string> extension_dependencies;
for (size_t i = 0, size = named_components.size(); i != size; ++i) {
const std::string& base_location = named_component_locations[i].base_location;
size_t bcp_index = named_component_locations[i].bcp_index;
@@ -2107,8 +2099,7 @@
if (extension_dependencies.empty() && !profile_filename.empty()) {
// Each extension is compiled against the same dependencies, namely the leading
// named components that were specified without providing the profile filename.
- extension_dependencies =
- ArrayRef<std::string>(components).SubArray(/*pos=*/ 0, /*length=*/ i);
+ extension_dependencies = components.SubArray(/*pos=*/ 0, /*length=*/ i);
}
if (bcp_index < bcp_pos) {
DCHECK_NE(i, 0u);
@@ -2158,8 +2149,7 @@
}
// Look for remaining components if there are any wildcard specifications.
- ArrayRef<const std::string> search_paths =
- ArrayRef<const std::string>(components).SubArray(/*pos=*/ named_components_count);
+ ArrayRef<const std::string> search_paths = components.SubArray(/*pos=*/ named_components_count);
if (!search_paths.empty()) {
const std::string& primary_base_location = named_component_locations[0].base_location;
size_t base_slash_pos = primary_base_location.rfind('/');
@@ -2229,13 +2219,13 @@
public:
BootImageLoader(const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
- const std::string& image_location,
+ const std::vector<std::string>& image_locations,
InstructionSet image_isa,
bool relocate,
bool executable)
: boot_class_path_(boot_class_path),
boot_class_path_locations_(boot_class_path_locations),
- image_location_(image_location),
+ image_locations_(image_locations),
image_isa_(image_isa),
relocate_(relocate),
executable_(executable),
@@ -2243,7 +2233,7 @@
}
void FindImageFiles() {
- BootImageLayout layout(image_location_, boot_class_path_, boot_class_path_locations_);
+ BootImageLayout layout(image_locations_, boot_class_path_, boot_class_path_locations_);
std::string image_location = layout.GetPrimaryImageLocation();
std::string system_filename;
bool found_image = FindImageFilenameImpl(image_location.c_str(),
@@ -3101,7 +3091,7 @@
const ArrayRef<const std::string> boot_class_path_;
const ArrayRef<const std::string> boot_class_path_locations_;
- const std::string image_location_;
+ const ArrayRef<const std::string> image_locations_;
const InstructionSet image_isa_;
const bool relocate_;
const bool executable_;
@@ -3115,7 +3105,7 @@
/*out*/std::string* error_msg) {
TimingLogger logger(__PRETTY_FUNCTION__, /*precise=*/ true, VLOG_IS_ON(image));
- BootImageLayout layout(image_location_, boot_class_path_, boot_class_path_locations_);
+ BootImageLayout layout(image_locations_, boot_class_path_, boot_class_path_locations_);
if (!layout.LoadFromSystem(image_isa_, error_msg)) {
return false;
}
@@ -3140,7 +3130,7 @@
bool ImageSpace::IsBootClassPathOnDisk(InstructionSet image_isa) {
Runtime* runtime = Runtime::Current();
- BootImageLayout layout(runtime->GetImageLocation(),
+ BootImageLayout layout(ArrayRef<const std::string>(runtime->GetImageLocations()),
ArrayRef<const std::string>(runtime->GetBootClassPath()),
ArrayRef<const std::string>(runtime->GetBootClassPathLocations()));
const std::string image_location = layout.GetPrimaryImageLocation();
@@ -3164,7 +3154,7 @@
bool ImageSpace::LoadBootImage(
const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
- const std::string& image_location,
+ const std::vector<std::string>& image_locations,
const InstructionSet image_isa,
bool relocate,
bool executable,
@@ -3179,13 +3169,13 @@
DCHECK(extra_reservation != nullptr);
DCHECK_NE(image_isa, InstructionSet::kNone);
- if (image_location.empty()) {
+ if (image_locations.empty()) {
return false;
}
BootImageLoader loader(boot_class_path,
boot_class_path_locations,
- image_location,
+ image_locations,
image_isa,
relocate,
executable);
@@ -3216,8 +3206,9 @@
oss << msg;
}
- LOG(ERROR) << "Could not create image space with image file '" << image_location << "'. "
- << "Attempting to fall back to imageless running. Error was: " << oss.str();
+ LOG(ERROR) << "Could not create image space with image file '"
+ << Join(image_locations, kComponentSeparator) << "'. Attempting to fall back to imageless "
+ << "running. Error was: " << oss.str();
return false;
}
@@ -3426,7 +3417,7 @@
bool ImageSpace::VerifyBootClassPathChecksums(std::string_view oat_checksums,
std::string_view oat_boot_class_path,
- const std::string& image_location,
+ ArrayRef<const std::string> image_locations,
ArrayRef<const std::string> boot_class_path_locations,
ArrayRef<const std::string> boot_class_path,
InstructionSet image_isa,
@@ -3447,7 +3438,7 @@
size_t bcp_pos = 0u;
if (StartsWith(oat_checksums, "i")) {
// Use only the matching part of the BCP for validation.
- BootImageLayout layout(image_location,
+ BootImageLayout layout(image_locations,
boot_class_path.SubArray(/*pos=*/ 0u, bcp_size),
boot_class_path_locations.SubArray(/*pos=*/ 0u, bcp_size));
std::string primary_image_location = layout.GetPrimaryImageLocation();
@@ -3458,7 +3449,7 @@
&system_filename,
&has_system)) {
*error_msg = StringPrintf("Unable to find image file for %s and %s",
- image_location.c_str(),
+ android::base::Join(image_locations, kComponentSeparator).c_str(),
GetInstructionSetString(image_isa));
return false;
}
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 545f659..aa93247 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -124,7 +124,7 @@
static bool LoadBootImage(
const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
- const std::string& image_location,
+ const std::vector<std::string>& image_locations,
const InstructionSet image_isa,
bool relocate,
bool executable,
@@ -233,7 +233,7 @@
// The boot image and dex files do not need to be loaded in memory.
static bool VerifyBootClassPathChecksums(std::string_view oat_checksums,
std::string_view oat_boot_class_path,
- const std::string& image_location,
+ ArrayRef<const std::string> image_locations,
ArrayRef<const std::string> boot_class_path_locations,
ArrayRef<const std::string> boot_class_path,
InstructionSet image_isa,
diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc
index 885dd21..1a53efa 100644
--- a/runtime/gc/space/image_space_test.cc
+++ b/runtime/gc/space/image_space_test.cc
@@ -128,7 +128,7 @@
ASSERT_TRUE(success) << error_msg;
}
- std::string full_image_locations;
+ std::vector<std::string> full_image_locations;
std::vector<std::unique_ptr<gc::space::ImageSpace>> boot_image_spaces;
MemMap extra_reservation;
auto load_boot_image = [&]() REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -165,9 +165,9 @@
// Load extensions and test for the presence of the test string.
ScopedObjectAccess soa(Thread::Current());
ASSERT_EQ(2u, extension_image_locations.size());
- full_image_locations = base_image_location +
- ImageSpace::kComponentSeparator + extension_image_locations[0] +
- ImageSpace::kComponentSeparator + extension_image_locations[1];
+ full_image_locations = {
+ base_image_location, extension_image_locations[0], extension_image_locations[1]
+ };
bool success = load_boot_image();
ASSERT_TRUE(success);
ASSERT_EQ(bcp.size(), boot_image_spaces.size());
@@ -178,9 +178,9 @@
// Reload extensions in reverse order and test for the presence of the test string.
std::swap(bcp[bcp.size() - 2u], bcp[bcp.size() - 1u]);
std::swap(bcp_locations[bcp_locations.size() - 2u], bcp_locations[bcp_locations.size() - 1u]);
- full_image_locations = base_image_location +
- ImageSpace::kComponentSeparator + extension_image_locations[1] +
- ImageSpace::kComponentSeparator + extension_image_locations[0];
+ full_image_locations = {
+ base_image_location, extension_image_locations[1], extension_image_locations[0]
+ };
success = load_boot_image();
ASSERT_TRUE(success);
ASSERT_EQ(bcp.size(), boot_image_spaces.size());
@@ -191,8 +191,7 @@
// Reload the image without the second extension.
bcp.erase(bcp.end() - 2u);
bcp_locations.erase(bcp_locations.end() - 2u);
- full_image_locations =
- base_image_location + ImageSpace::kComponentSeparator + extension_image_locations[0];
+ full_image_locations = {base_image_location, extension_image_locations[0]};
success = load_boot_image();
ASSERT_TRUE(success);
ASSERT_EQ(bcp.size(), boot_image_spaces.size());
@@ -334,7 +333,7 @@
return gc::space::ImageSpace::VerifyBootClassPathChecksums(
checksums,
android::base::Join(bcp_locations, ':'),
- runtime->GetImageLocation(),
+ ArrayRef<const std::string>(runtime->GetImageLocations()),
ArrayRef<const std::string>(bcp_locations),
ArrayRef<const std::string>(bcp),
kRuntimeISA,
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index c74f19b..a5ccb69 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -649,7 +649,7 @@
bool result = gc::space::ImageSpace::VerifyBootClassPathChecksums(
oat_boot_class_path_checksums_view,
oat_boot_class_path_view,
- runtime->GetImageLocation(),
+ ArrayRef<const std::string>(runtime->GetImageLocations()),
ArrayRef<const std::string>(runtime->GetBootClassPathLocations()),
ArrayRef<const std::string>(runtime->GetBootClassPath()),
isa_,
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index f896511..fec2587 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -166,7 +166,7 @@
.IntoKey(M::JITCompileThreshold)
.SetCategory("ART")
.Define("-Ximage:_")
- .WithType<std::string>()
+ .WithType<ParseStringList<':'>>()
.IntoKey(M::Image)
.Define("-Xprimaryzygote")
.IntoKey(M::PrimaryZygote)
@@ -733,8 +733,8 @@
}
if (!args.Exists(M::CompilerCallbacksPtr) && !args.Exists(M::Image)) {
- std::string image = GetDefaultBootImageLocation(GetAndroidRoot());
- args.Set(M::Image, image);
+ std::string image_locations = GetDefaultBootImageLocation(GetAndroidRoot());
+ args.Set(M::Image, ParseStringList<':'>::Split(image_locations));
}
// 0 means no growth limit, and growth limit should be always <= heap size
diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc
index 8873eb9..b9ca988 100644
--- a/runtime/parsed_options_test.cc
+++ b/runtime/parsed_options_test.cc
@@ -86,7 +86,9 @@
EXPECT_PARSED_EQ_AS_STRING_VECTOR(expected_boot_class_path, Opt::BootClassPath);
EXPECT_PARSED_EQ(class_path, Opt::ClassPath);
- EXPECT_PARSED_EQ(std::string("boot_image"), Opt::Image);
+ std::vector<std::string> boot_images = map.GetOrDefault(Opt::Image);
+ ASSERT_EQ(1U, boot_images.size());
+ EXPECT_EQ(std::string("boot_image"), boot_images[0]);
EXPECT_PARSED_EXISTS(Opt::CheckJni);
EXPECT_PARSED_EQ(2048U, Opt::MemoryInitialSize);
EXPECT_PARSED_EQ(4 * KB, Opt::MemoryMaximumSize);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 38f8ce1..97c1d6d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1342,7 +1342,7 @@
Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold),
runtime_options.GetOrDefault(Opt::StackDumpLockProfThreshold));
- image_location_ = runtime_options.GetOrDefault(Opt::Image);
+ image_locations_ = runtime_options.ReleaseOrDefault(Opt::Image);
SetInstructionSet(runtime_options.GetOrDefault(Opt::ImageInstructionSet));
boot_class_path_ = runtime_options.ReleaseOrDefault(Opt::BootClassPath);
@@ -1351,13 +1351,14 @@
boot_class_path_locations_.size() == boot_class_path_.size());
if (boot_class_path_.empty()) {
// Try to extract the boot class path from the system boot image.
- if (image_location_.empty()) {
+ if (image_locations_.empty()) {
LOG(ERROR) << "Empty boot class path, cannot continue without image.";
return false;
}
std::string system_oat_filename = ImageHeader::GetOatLocationFromImageLocation(
- GetSystemImageFilename(image_location_.c_str(), instruction_set_));
- std::string system_oat_location = ImageHeader::GetOatLocationFromImageLocation(image_location_);
+ GetSystemImageFilename(image_locations_[0].c_str(), instruction_set_));
+ std::string system_oat_location = ImageHeader::GetOatLocationFromImageLocation(
+ image_locations_[0]);
std::string error_msg;
std::unique_ptr<OatFile> oat_file(OatFile::Open(/*zip_fd=*/ -1,
system_oat_filename,
@@ -1503,7 +1504,7 @@
runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
GetBootClassPath(),
GetBootClassPathLocations(),
- image_location_,
+ image_locations_,
instruction_set_,
// Override the collector type to CC if the read barrier config.
kUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_,
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 88f7bc0..9664977 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -212,8 +212,8 @@
return image_compiler_options_;
}
- const std::string& GetImageLocation() const {
- return image_location_;
+ const std::vector<std::string>& GetImageLocations() const {
+ return image_locations_;
}
// Starts a runtime, which may cause threads to be started and code to run.
@@ -1089,7 +1089,7 @@
std::string compiler_executable_;
std::vector<std::string> compiler_options_;
std::vector<std::string> image_compiler_options_;
- std::string image_location_;
+ std::vector<std::string> image_locations_;
std::vector<std::string> boot_class_path_;
std::vector<std::string> boot_class_path_locations_;
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 3f0e3cc..9667484 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -41,7 +41,7 @@
RUNTIME_OPTIONS_KEY (ParseStringList<':'>,BootClassPath) // std::vector<std::string>
RUNTIME_OPTIONS_KEY (ParseStringList<':'>,BootClassPathLocations) // std::vector<std::string>
RUNTIME_OPTIONS_KEY (std::string, ClassPath)
-RUNTIME_OPTIONS_KEY (std::string, Image)
+RUNTIME_OPTIONS_KEY (ParseStringList<':'>,Image)
RUNTIME_OPTIONS_KEY (Unit, CheckJni)
RUNTIME_OPTIONS_KEY (Unit, JniOptsForceCopy)
RUNTIME_OPTIONS_KEY (std::string, JdwpOptions, "suspend=n,server=y")