summaryrefslogtreecommitdiff
path: root/dex2oat/dex2oat.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dex2oat/dex2oat.cc')
-rw-r--r--dex2oat/dex2oat.cc304
1 files changed, 183 insertions, 121 deletions
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 2aa4085fb1..6fae8e4109 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -71,6 +71,7 @@
#include "oat_writer.h"
#include "os.h"
#include "runtime.h"
+#include "runtime_options.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change.h"
#include "utils.h"
@@ -208,6 +209,11 @@ NO_RETURN static void Usage(const char* fmt, ...) {
UsageError(" --image=<file.art>: specifies the output image filename.");
UsageError(" Example: --image=/system/framework/boot.art");
UsageError("");
+ UsageError(" --image-format=(uncompressed|lz4):");
+ UsageError(" Which format to store the image.");
+ UsageError(" Example: --image-format=lz4");
+ UsageError(" Default: uncompressed");
+ UsageError("");
UsageError(" --image-classes=<classname-file>: specifies classes to include in an image.");
UsageError(" Example: --image=frameworks/base/preloaded-classes");
UsageError("");
@@ -490,6 +496,7 @@ class Dex2Oat FINAL {
image_base_(0U),
image_classes_zip_filename_(nullptr),
image_classes_filename_(nullptr),
+ image_storage_mode_(ImageHeader::kStorageModeUncompressed),
compiled_classes_zip_filename_(nullptr),
compiled_classes_filename_(nullptr),
compiled_methods_zip_filename_(nullptr),
@@ -621,6 +628,19 @@ class Dex2Oat FINAL {
}
}
+ void ParseImageFormat(const StringPiece& option) {
+ const StringPiece substr("--image-format=");
+ DCHECK(option.starts_with(substr));
+ const StringPiece format_str = option.substr(substr.length());
+ if (format_str == "lz4") {
+ image_storage_mode_ = ImageHeader::kStorageModeLZ4;
+ } else if (format_str == "uncompressed") {
+ image_storage_mode_ = ImageHeader::kStorageModeUncompressed;
+ } else {
+ Usage("Unknown image format: %s", format_str.data());
+ }
+ }
+
void ProcessOptions(ParserOptions* parser_options) {
boot_image_ = !image_filename_.empty();
app_image_ = app_image_fd_ != -1 || !app_image_file_name_.empty();
@@ -667,15 +687,14 @@ class Dex2Oat FINAL {
parser_options->boot_image_filename += "/framework/boot.art";
}
if (!parser_options->boot_image_filename.empty()) {
- boot_image_option_ += "-Ximage:";
- boot_image_option_ += parser_options->boot_image_filename;
+ boot_image_filename_ = parser_options->boot_image_filename;
}
if (image_classes_filename_ != nullptr && !IsBootImage()) {
Usage("--image-classes should only be used with --image");
}
- if (image_classes_filename_ != nullptr && !boot_image_option_.empty()) {
+ if (image_classes_filename_ != nullptr && !boot_image_filename_.empty()) {
Usage("--image-classes should not be used with --boot-image");
}
@@ -687,7 +706,7 @@ class Dex2Oat FINAL {
Usage("--compiled-classes should only be used with --image");
}
- if (compiled_classes_filename_ != nullptr && !boot_image_option_.empty()) {
+ if (compiled_classes_filename_ != nullptr && !boot_image_filename_.empty()) {
Usage("--compiled-classes should not be used with --boot-image");
}
@@ -719,7 +738,7 @@ class Dex2Oat FINAL {
Usage("--zip-location should be supplied with --zip-fd");
}
- if (boot_image_option_.empty()) {
+ if (boot_image_filename_.empty()) {
if (image_base_ == 0) {
Usage("Non-zero --base not specified");
}
@@ -877,6 +896,8 @@ class Dex2Oat FINAL {
image_classes_filename_ = option.substr(strlen("--image-classes=")).data();
} else if (option.starts_with("--image-classes-zip=")) {
image_classes_zip_filename_ = option.substr(strlen("--image-classes-zip=")).data();
+ } else if (option.starts_with("--image-format=")) {
+ ParseImageFormat(option);
} else if (option.starts_with("--compiled-classes=")) {
compiled_classes_filename_ = option.substr(strlen("--compiled-classes=")).data();
} else if (option.starts_with("--compiled-classes-zip=")) {
@@ -1014,20 +1035,10 @@ class Dex2Oat FINAL {
// boot class path.
bool Setup() {
TimingLogger::ScopedTiming t("dex2oat Setup", timings_);
- RuntimeOptions runtime_options;
art::MemMap::Init(); // For ZipEntry::ExtractToMemMap.
- if (boot_image_option_.empty()) {
- 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_, nullptr));
- }
- for (size_t i = 0; i < runtime_args_.size(); i++) {
- runtime_options.push_back(std::make_pair(runtime_args_[i], nullptr));
+
+ if (!PrepareImageClasses() || !PrepareCompiledClasses() || !PrepareCompiledMethods()) {
+ return false;
}
verification_results_.reset(new VerificationResults(compiler_options_.get()));
@@ -1037,23 +1048,15 @@ class Dex2Oat FINAL {
IsBootImage() ?
CompilerCallbacks::CallbackMode::kCompileBootImage :
CompilerCallbacks::CallbackMode::kCompileApp));
- runtime_options.push_back(std::make_pair("compilercallbacks", callbacks_.get()));
- runtime_options.push_back(
- std::make_pair("imageinstructionset", GetInstructionSetString(instruction_set_)));
- // Only allow no boot image for the runtime if we're compiling one. When we compile an app,
- // we don't want fallback mode, it will abort as we do not push a boot classpath (it might
- // have been stripped in preopting, anyways).
- if (!IsBootImage()) {
- runtime_options.push_back(std::make_pair("-Xno-dex-file-fallback", nullptr));
+ RuntimeArgumentMap runtime_options;
+ if (!PrepareRuntimeOptions(&runtime_options)) {
+ return false;
}
- // Disable libsigchain. We don't don't need it during compilation and it prevents us
- // from getting a statically linked version of dex2oat (because of dlsym and RTLD_NEXT).
- runtime_options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
{
TimingLogger::ScopedTiming t_runtime("Create runtime", timings_);
- if (!CreateRuntime(runtime_options)) {
+ if (!CreateRuntime(std::move(runtime_options))) {
return false;
}
}
@@ -1068,66 +1071,8 @@ class Dex2Oat FINAL {
// Whilst we're in native take the opportunity to initialize well known classes.
WellKnownClasses::Init(self->GetJniEnv());
- // If --image-classes was specified, calculate the full list of classes to include in the image
- if (image_classes_filename_ != nullptr) {
- std::string error_msg;
- if (image_classes_zip_filename_ != nullptr) {
- image_classes_.reset(ReadImageClassesFromZip(image_classes_zip_filename_,
- image_classes_filename_,
- &error_msg));
- } else {
- image_classes_.reset(ReadImageClassesFromFile(image_classes_filename_));
- }
- if (image_classes_.get() == nullptr) {
- LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename_ <<
- "': " << error_msg;
- return false;
- }
- } else if (IsBootImage()) {
- image_classes_.reset(new std::unordered_set<std::string>);
- }
- // If --compiled-classes was specified, calculate the full list of classes to compile in the
- // image.
- if (compiled_classes_filename_ != nullptr) {
- std::string error_msg;
- if (compiled_classes_zip_filename_ != nullptr) {
- compiled_classes_.reset(ReadImageClassesFromZip(compiled_classes_zip_filename_,
- compiled_classes_filename_,
- &error_msg));
- } else {
- compiled_classes_.reset(ReadImageClassesFromFile(compiled_classes_filename_));
- }
- if (compiled_classes_.get() == nullptr) {
- LOG(ERROR) << "Failed to create list of compiled classes from '"
- << compiled_classes_filename_ << "': " << error_msg;
- return false;
- }
- } else {
- compiled_classes_.reset(nullptr); // By default compile everything.
- }
- // If --compiled-methods was specified, read the methods to compile from the given file(s).
- if (compiled_methods_filename_ != nullptr) {
- std::string error_msg;
- if (compiled_methods_zip_filename_ != nullptr) {
- compiled_methods_.reset(ReadCommentedInputFromZip(compiled_methods_zip_filename_,
- compiled_methods_filename_,
- nullptr, // No post-processing.
- &error_msg));
- } else {
- compiled_methods_.reset(ReadCommentedInputFromFile(compiled_methods_filename_,
- nullptr)); // No post-processing.
- }
- if (compiled_methods_.get() == nullptr) {
- LOG(ERROR) << "Failed to create list of compiled methods from '"
- << compiled_methods_filename_ << "': " << error_msg;
- return false;
- }
- } else {
- compiled_methods_.reset(nullptr); // By default compile everything.
- }
-
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
- if (boot_image_option_.empty()) {
+ if (boot_image_filename_.empty()) {
dex_files_ = class_linker->GetBootClassPath();
} else {
TimingLogger::ScopedTiming t_dex("Opening dex files", timings_);
@@ -1164,22 +1109,7 @@ class Dex2Oat FINAL {
constexpr bool kSaveDexInput = false;
if (kSaveDexInput) {
- for (size_t i = 0; i < dex_files_.size(); ++i) {
- const DexFile* dex_file = dex_files_[i];
- std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex",
- getpid(), i));
- std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str()));
- if (tmp_file.get() == nullptr) {
- PLOG(ERROR) << "Failed to open file " << tmp_file_name
- << ". Try: adb shell chmod 777 /data/local/tmp";
- continue;
- }
- // This is just dumping files for debugging. Ignore errors, and leave remnants.
- UNUSED(tmp_file->WriteFully(dex_file->Begin(), dex_file->Size()));
- UNUSED(tmp_file->Flush());
- UNUSED(tmp_file->Close());
- LOG(INFO) << "Wrote input to " << tmp_file_name;
- }
+ SaveDexInput();
}
}
// Ensure opened dex files are writable for dex-to-dex transformations. Also ensure that
@@ -1238,16 +1168,13 @@ class Dex2Oat FINAL {
jobject class_path_class_loader = nullptr;
Thread* self = Thread::Current();
- if (!boot_image_option_.empty()) {
+ if (!boot_image_filename_.empty()) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
OpenClassPathFiles(runtime_->GetClassPathString(), dex_files_, &class_path_files_);
ScopedObjectAccess soa(self);
// Classpath: first the class-path given.
- std::vector<const DexFile*> class_path_files;
- for (auto& class_path_file : class_path_files_) {
- class_path_files.push_back(class_path_file.get());
- }
+ std::vector<const DexFile*> class_path_files = MakeNonOwningPointerVector(class_path_files_);
// Store the classpath we have right now.
key_value_store_->Put(OatHeader::kClassPathKey,
@@ -1432,14 +1359,9 @@ class Dex2Oat FINAL {
elf_writer->EndText(text);
elf_writer->SetBssSize(oat_writer->GetBssSize());
-
elf_writer->WriteDynamicSection();
-
- ArrayRef<const dwarf::MethodDebugInfo> method_infos(oat_writer->GetMethodDebugInfo());
- elf_writer->WriteDebugInfo(method_infos);
-
- ArrayRef<const uintptr_t> patch_locations(oat_writer->GetAbsolutePatchLocations());
- elf_writer->WritePatchLocations(patch_locations);
+ elf_writer->WriteDebugInfo(oat_writer->GetMethodDebugInfo());
+ elf_writer->WritePatchLocations(oat_writer->GetAbsolutePatchLocations());
if (!elf_writer->End()) {
LOG(ERROR) << "Failed to write ELF file " << oat_file_->GetPath();
@@ -1552,6 +1474,16 @@ class Dex2Oat FINAL {
}
private:
+ template <typename T>
+ static std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) {
+ std::vector<T*> result;
+ result.reserve(src.size());
+ for (const std::unique_ptr<T>& t : src) {
+ result.push_back(t.get());
+ }
+ return result;
+ }
+
static size_t OpenDexFiles(const std::vector<const char*>& dex_filenames,
const std::vector<const char*>& dex_locations,
std::vector<std::unique_ptr<const DexFile>>* dex_files) {
@@ -1612,10 +1544,138 @@ class Dex2Oat FINAL {
}
}
+ bool PrepareImageClasses() {
+ // If --image-classes was specified, calculate the full list of classes to include in the image.
+ if (image_classes_filename_ != nullptr) {
+ image_classes_ =
+ ReadClasses(image_classes_zip_filename_, image_classes_filename_, "image");
+ if (image_classes_ == nullptr) {
+ return false;
+ }
+ } else if (IsBootImage()) {
+ image_classes_.reset(new std::unordered_set<std::string>);
+ }
+ return true;
+ }
+
+ bool PrepareCompiledClasses() {
+ // If --compiled-classes was specified, calculate the full list of classes to compile in the
+ // image.
+ if (compiled_classes_filename_ != nullptr) {
+ compiled_classes_ =
+ ReadClasses(compiled_classes_zip_filename_, compiled_classes_filename_, "compiled");
+ if (compiled_classes_ == nullptr) {
+ return false;
+ }
+ } else {
+ compiled_classes_.reset(nullptr); // By default compile everything.
+ }
+ return true;
+ }
+
+ static std::unique_ptr<std::unordered_set<std::string>> ReadClasses(const char* zip_filename,
+ const char* classes_filename,
+ const char* tag) {
+ std::unique_ptr<std::unordered_set<std::string>> classes;
+ std::string error_msg;
+ if (zip_filename != nullptr) {
+ classes.reset(ReadImageClassesFromZip(zip_filename, classes_filename, &error_msg));
+ } else {
+ classes.reset(ReadImageClassesFromFile(classes_filename));
+ }
+ if (classes == nullptr) {
+ LOG(ERROR) << "Failed to create list of " << tag << " classes from '"
+ << classes_filename << "': " << error_msg;
+ }
+ return classes;
+ }
+
+ bool PrepareCompiledMethods() {
+ // If --compiled-methods was specified, read the methods to compile from the given file(s).
+ if (compiled_methods_filename_ != nullptr) {
+ std::string error_msg;
+ if (compiled_methods_zip_filename_ != nullptr) {
+ compiled_methods_.reset(ReadCommentedInputFromZip(compiled_methods_zip_filename_,
+ compiled_methods_filename_,
+ nullptr, // No post-processing.
+ &error_msg));
+ } else {
+ compiled_methods_.reset(ReadCommentedInputFromFile(compiled_methods_filename_,
+ nullptr)); // No post-processing.
+ }
+ if (compiled_methods_.get() == nullptr) {
+ LOG(ERROR) << "Failed to create list of compiled methods from '"
+ << compiled_methods_filename_ << "': " << error_msg;
+ return false;
+ }
+ } else {
+ compiled_methods_.reset(nullptr); // By default compile everything.
+ }
+ return true;
+ }
+
+ void SaveDexInput() {
+ for (size_t i = 0; i < dex_files_.size(); ++i) {
+ const DexFile* dex_file = dex_files_[i];
+ std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex",
+ getpid(), i));
+ std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str()));
+ if (tmp_file.get() == nullptr) {
+ PLOG(ERROR) << "Failed to open file " << tmp_file_name
+ << ". Try: adb shell chmod 777 /data/local/tmp";
+ continue;
+ }
+ // This is just dumping files for debugging. Ignore errors, and leave remnants.
+ UNUSED(tmp_file->WriteFully(dex_file->Begin(), dex_file->Size()));
+ UNUSED(tmp_file->Flush());
+ UNUSED(tmp_file->Close());
+ LOG(INFO) << "Wrote input to " << tmp_file_name;
+ }
+ }
+
+ bool PrepareRuntimeOptions(RuntimeArgumentMap* runtime_options) {
+ RuntimeOptions raw_options;
+ if (boot_image_filename_.empty()) {
+ std::string boot_class_path = "-Xbootclasspath:";
+ boot_class_path += Join(dex_filenames_, ':');
+ raw_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_, ':');
+ raw_options.push_back(std::make_pair(boot_class_path_locations, nullptr));
+ } else {
+ std::string boot_image_option = "-Ximage:";
+ boot_image_option += boot_image_filename_;
+ raw_options.push_back(std::make_pair(boot_image_option, nullptr));
+ }
+ for (size_t i = 0; i < runtime_args_.size(); i++) {
+ raw_options.push_back(std::make_pair(runtime_args_[i], nullptr));
+ }
+
+ raw_options.push_back(std::make_pair("compilercallbacks", callbacks_.get()));
+ raw_options.push_back(
+ std::make_pair("imageinstructionset", GetInstructionSetString(instruction_set_)));
+
+ // Only allow no boot image for the runtime if we're compiling one. When we compile an app,
+ // we don't want fallback mode, it will abort as we do not push a boot classpath (it might
+ // have been stripped in preopting, anyways).
+ if (!IsBootImage()) {
+ raw_options.push_back(std::make_pair("-Xno-dex-file-fallback", nullptr));
+ }
+ // Disable libsigchain. We don't don't need it during compilation and it prevents us
+ // from getting a statically linked version of dex2oat (because of dlsym and RTLD_NEXT).
+ raw_options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
+
+ if (!Runtime::ParseOptions(raw_options, false, runtime_options)) {
+ LOG(ERROR) << "Failed to parse runtime options";
+ return false;
+ }
+ return true;
+ }
+
// Create a runtime necessary for compilation.
- bool CreateRuntime(const RuntimeOptions& runtime_options)
+ bool CreateRuntime(RuntimeArgumentMap&& runtime_options)
SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
- if (!Runtime::Create(runtime_options, false)) {
+ if (!Runtime::Create(std::move(runtime_options))) {
LOG(ERROR) << "Failed to create runtime";
return false;
}
@@ -1643,7 +1703,8 @@ class Dex2Oat FINAL {
image_writer_.reset(new ImageWriter(*driver_,
image_base,
compiler_options_->GetCompilePic(),
- IsAppImage()));
+ IsAppImage(),
+ image_storage_mode_));
}
// Let the ImageWriter write the image file. If we do not compile PIC, also fix up the oat file.
@@ -1812,12 +1873,13 @@ class Dex2Oat FINAL {
std::vector<const char*> dex_locations_;
int zip_fd_;
std::string zip_location_;
- std::string boot_image_option_;
+ std::string boot_image_filename_;
std::vector<const char*> runtime_args_;
std::string image_filename_;
uintptr_t image_base_;
const char* image_classes_zip_filename_;
const char* image_classes_filename_;
+ ImageHeader::StorageMode image_storage_mode_;
const char* compiled_classes_zip_filename_;
const char* compiled_classes_filename_;
const char* compiled_methods_zip_filename_;