Remove back-door bootclasspath option from Runtime
The 'bootclasspath' option allowed users of the Runtime to load their
own boot class path DexFiles and pass them directly to the Runtime as
an option. This obscures the fact that the Runtime must take ownership
of the boot class path DexFiles.
This change removes the use of the bootclasspath option by dex2oat and
the common runtime tests. For dex2oat, we use the existing
-Xbootclasspath option instead, and introduce a new
-Xbootclasspath-locations option to override the dex locations for the
loaded boot class path dex files. For the common runtime tests, we
simply use -Xbootclasspath.
Bug: 18809837
Change-Id: Idfcd4885390bf0f3dc350993756dd337220def73
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 63009bf..4f279f2 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1014,17 +1014,16 @@
bool Setup() {
TimingLogger::ScopedTiming t("dex2oat Setup", timings_);
RuntimeOptions runtime_options;
- std::vector<const DexFile*> boot_class_path;
art::MemMap::Init(); // For ZipEntry::ExtractToMemMap.
if (boot_image_option_.empty()) {
- size_t failure_count = OpenDexFiles(dex_filenames_, dex_locations_, boot_class_path);
- if (failure_count > 0) {
- LOG(ERROR) << "Failed to open some dex files: " << failure_count;
- return false;
- }
- runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path));
+ std::string boot_class_path = "-Xbootclasspath:";
+ boot_class_path += Join(dex_filenames_, ':');
+ runtime_options.push_back(std::make_pair(boot_class_path, nullptr));
+ std::string boot_class_path_locations = "-Xbootclasspath-locations:";
+ boot_class_path_locations += Join(dex_locations_, ':');
+ runtime_options.push_back(std::make_pair(boot_class_path_locations, nullptr));
} else {
- runtime_options.push_back(std::make_pair(boot_image_option_.c_str(), nullptr));
+ runtime_options.push_back(std::make_pair(boot_image_option_, nullptr));
}
for (size_t i = 0; i < runtime_args_.size(); i++) {
runtime_options.push_back(std::make_pair(runtime_args_[i], nullptr));
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 98fe079..75ba9dd 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -201,22 +201,17 @@
int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700);
ASSERT_EQ(mkdir_result, 0);
- MemMap::Init(); // For LoadExpectSingleDexFile
-
- std::string error_msg;
- java_lang_dex_file_ = LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str());
- boot_class_path_.push_back(java_lang_dex_file_);
-
std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB));
std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB));
callbacks_.reset(new NoopCompilerCallbacks());
RuntimeOptions options;
- options.push_back(std::make_pair("bootclasspath", &boot_class_path_));
+ std::string boot_class_path_string = "-Xbootclasspath:" + GetLibCoreDexFileName();
+ options.push_back(std::make_pair(boot_class_path_string, nullptr));
options.push_back(std::make_pair("-Xcheck:jni", nullptr));
- options.push_back(std::make_pair(min_heap_string.c_str(), nullptr));
- options.push_back(std::make_pair(max_heap_string.c_str(), nullptr));
+ options.push_back(std::make_pair(min_heap_string, nullptr));
+ options.push_back(std::make_pair(max_heap_string, nullptr));
options.push_back(std::make_pair("compilercallbacks", callbacks_.get()));
SetUpRuntimeOptions(&options);
if (!Runtime::Create(options, false)) {
@@ -239,6 +234,11 @@
// pool is created by the runtime.
runtime_->GetHeap()->CreateThreadPool();
runtime_->GetHeap()->VerifyHeap(); // Check for heap corruption before the test
+
+ // Get the boot class path from the runtime so it can be used in tests.
+ boot_class_path_ = class_linker_->GetBootClassPath();
+ ASSERT_FALSE(boot_class_path_.empty());
+ java_lang_dex_file_ = boot_class_path_[0];
}
void CommonRuntimeTest::ClearDirectory(const char* dirpath) {
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 8851185..35dc30f 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -116,7 +116,7 @@
std::string android_data_;
std::string dalvik_cache_;
const DexFile* java_lang_dex_file_; // owned by runtime_
- std::vector<const DexFile*> boot_class_path_;
+ std::vector<const DexFile*> boot_class_path_; // owned by runtime_
std::unique_ptr<Runtime> runtime_;
// Owned by the runtime
ClassLinker* class_linker_;
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 1b992d5..4ba3cb9 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -34,7 +34,6 @@
ParsedOptions::ParsedOptions()
:
- boot_class_path_(nullptr),
check_jni_(kIsDebugBuild), // -Xcheck:jni is off by default for regular
// builds but on by default in debug builds.
force_copy_(false),
@@ -288,6 +287,9 @@
} else if (StartsWith(option, "-Xbootclasspath:")) {
boot_class_path_string_ = option.substr(strlen("-Xbootclasspath:")).data();
LOG(INFO) << "setting boot class path to " << boot_class_path_string_;
+ } else if (StartsWith(option, "-Xbootclasspath-locations:")) {
+ boot_class_path_locations_string_ = option.substr(
+ strlen("-Xbootclasspath-locations:")).data();
} else if (option == "-classpath" || option == "-cp") {
// TODO: support -Djava.class.path
i++;
@@ -297,9 +299,6 @@
}
const StringPiece& value = options[i].first;
class_path_string_ = value.data();
- } else if (option == "bootclasspath") {
- boot_class_path_
- = reinterpret_cast<const std::vector<const DexFile*>*>(options[i].second);
} else if (StartsWith(option, "-Ximage:")) {
if (!ParseStringAfterChar(option, ':', &image_)) {
return false;
@@ -720,6 +719,24 @@
boot_class_path_string_.replace(core_jar_pos, core_jar.size(), core_libart_jar);
}
+ if (!boot_class_path_locations_string_.empty()) {
+ std::vector<std::string> files;
+ Split(boot_class_path_string_, ':', &files);
+
+ std::vector<std::string> locations;
+ Split(boot_class_path_locations_string_, ':', &locations);
+
+ if (files.size() != locations.size()) {
+ Usage("The number of boot class path files does not match"
+ " the number of boot class path locations given\n"
+ " boot class path files (%zu): %s\n"
+ " boot class path locations (%zu): %s\n",
+ files.size(), boot_class_path_string_.c_str(),
+ locations.size(), boot_class_path_locations_string_.c_str());
+ return false;
+ }
+ }
+
if (compiler_callbacks_ == nullptr && image_.empty()) {
image_ += GetAndroidRoot();
image_ += "/framework/boot.art";
@@ -804,6 +821,8 @@
UsageMessage(stream, " -Xgc:[no]postverify_rosalloc\n");
UsageMessage(stream, " -Xgc:[no]presweepingverify\n");
UsageMessage(stream, " -Ximage:filename\n");
+ UsageMessage(stream, " -Xbootclasspath-locations:bootclasspath\n"
+ " (override the dex locations of the -Xbootclasspath files)\n");
UsageMessage(stream, " -XX:+DisableExplicitGC\n");
UsageMessage(stream, " -XX:ParallelGCThreads=integervalue\n");
UsageMessage(stream, " -XX:ConcGCThreads=integervalue\n");
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 9294868..c7162b8 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -40,8 +40,8 @@
// returns null if problem parsing and ignore_unrecognized is false
static ParsedOptions* Create(const RuntimeOptions& options, bool ignore_unrecognized);
- const std::vector<const DexFile*>* boot_class_path_;
std::string boot_class_path_string_;
+ std::string boot_class_path_locations_string_;
std::string class_path_string_;
std::string image_;
bool check_jni_;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index a2c9f50..fb6034d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -683,6 +683,7 @@
static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames,
+ const std::vector<std::string>& dex_locations,
const std::string& image_location,
std::vector<const DexFile*>& dex_files) {
size_t failure_count = 0;
@@ -692,12 +693,13 @@
failure_count = 0;
for (size_t i = 0; i < dex_filenames.size(); i++) {
const char* dex_filename = dex_filenames[i].c_str();
+ const char* dex_location = dex_locations[i].c_str();
std::string error_msg;
if (!OS::FileExists(dex_filename)) {
LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
continue;
}
- if (!DexFile::Open(dex_filename, dex_filename, &error_msg, &dex_files)) {
+ if (!DexFile::Open(dex_filename, dex_location, &error_msg, &dex_files)) {
LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
++failure_count;
}
@@ -858,17 +860,25 @@
CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);
class_linker_ = new ClassLinker(intern_table_);
- bool options_class_path_used = false;
if (GetHeap()->HasImageSpace()) {
class_linker_->InitFromImage();
if (kIsDebugBuild) {
GetHeap()->GetImageSpace()->VerifyImageAllocations();
}
- } else if (!IsCompiler() || !image_dex2oat_enabled_) {
+ } else {
std::vector<std::string> dex_filenames;
Split(boot_class_path_string_, ':', &dex_filenames);
+
+ std::vector<std::string> dex_locations;
+ if (options->boot_class_path_locations_string_.empty()) {
+ dex_locations = dex_filenames;
+ } else {
+ Split(options->boot_class_path_locations_string_, ':', &dex_locations);
+ CHECK_EQ(dex_filenames.size(), dex_locations.size());
+ }
+
std::vector<const DexFile*> boot_class_path;
- OpenDexFiles(dex_filenames, options->image_, boot_class_path);
+ OpenDexFiles(dex_filenames, dex_locations, options->image_, boot_class_path);
class_linker_->InitWithoutImage(boot_class_path);
// TODO: Should we move the following to InitWithoutImage?
SetInstructionSet(kRuntimeISA);
@@ -878,18 +888,6 @@
SetCalleeSaveMethod(CreateCalleeSaveMethod(), type);
}
}
- } else {
- CHECK(options->boot_class_path_ != nullptr);
- CHECK_NE(options->boot_class_path_->size(), 0U);
- class_linker_->InitWithoutImage(*options->boot_class_path_);
- options_class_path_used = true;
- }
-
- if (!options_class_path_used) {
- // If the class linker does not take ownership of the boot class path, wipe it to prevent leaks.
- auto boot_class_path_vector_ptr =
- const_cast<std::vector<const DexFile*>*>(options->boot_class_path_);
- STLDeleteElements(boot_class_path_vector_ptr);
}
CHECK(class_linker_ != nullptr);