Create CompilerOptions
Package up most compiler related options in CompilerOptions. Details include:
- Includes compiler filter, method thresholds, SEA IR mode.
- Excludes those needed during Runtime::Init such as CompilerCallbacks and VerificationResults.
- Pass CompilerOptions to CompilerDriver.
- Remove CompilerOptions from Runtime.
- Add ability to pass options for app and image dex2oat to runtime via
-Xcompiler-option and -Ximage-compiler-option respectively.
Other
- Replace 2x CompilerCallbacks implementations with one.
- Factor out execv code for use by both image and oat generation.
- More OatFile error_msg reporting.
- DCHECK for SuspendAll found trying to run valgrind.
Change-Id: Iecb57da907be0c856d00c3cd634b5042a229e620
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index bfda17d..6c879d0 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -34,7 +34,9 @@
#include "compiler_callbacks.h"
#include "dex_file-inl.h"
#include "dex/verification_results.h"
+#include "driver/compiler_callbacks_impl.h"
#include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
#include "elf_fixup.h"
#include "elf_stripper.h"
#include "gc/space/image_space.h"
@@ -54,15 +56,22 @@
#include "scoped_thread_state_change.h"
#include "sirt_ref.h"
#include "vector_output_stream.h"
-#include "verifier/method_verifier.h"
-#include "verifier/method_verifier-inl.h"
#include "well_known_classes.h"
#include "zip_archive.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
-
namespace art {
+static int original_argc;
+static char** original_argv;
+
+static std::string CommandLine() {
+ std::vector<std::string> command;
+ for (int i = 0; i < original_argc; ++i) {
+ command.push_back(original_argv[i]);
+ }
+ return Join(command, ' ');
+}
+
static void UsageErrorV(const char* fmt, va_list ap) {
std::string error;
StringAppendV(&error, fmt, ap);
@@ -82,6 +91,8 @@
UsageErrorV(fmt, ap);
va_end(ap);
+ UsageError("Command: %s", CommandLine().c_str());
+
UsageError("Usage: dex2oat [options]...");
UsageError("");
UsageError(" --dex-file=<dex-file>: specifies a .dex file to compile.");
@@ -147,6 +158,46 @@
UsageError(" Example: --compiler-backend=Portable");
UsageError(" Default: Quick");
UsageError("");
+ UsageError(" --compiler-filter=(interpret-only|space|balanced|speed|everything): select");
+ UsageError(" compiler filter.");
+ UsageError(" Example: --compiler-filter=everything");
+#if ART_SMALL_MODE
+ UsageError(" Default: interpret-only");
+#else
+ UsageError(" Default: speed");
+#endif
+ UsageError("");
+ UsageError(" --huge-method-max=<method-instruction-count>: the threshold size for a huge");
+ UsageError(" method for compiler filter tuning.");
+ UsageError(" Example: --huge-method-max=%d", CompilerOptions::kDefaultHugeMethodThreshold);
+ UsageError(" Default: %d", CompilerOptions::kDefaultHugeMethodThreshold);
+ UsageError("");
+ UsageError(" --huge-method-max=<method-instruction-count>: threshold size for a huge");
+ UsageError(" method for compiler filter tuning.");
+ UsageError(" Example: --huge-method-max=%d", CompilerOptions::kDefaultHugeMethodThreshold);
+ UsageError(" Default: %d", CompilerOptions::kDefaultHugeMethodThreshold);
+ UsageError("");
+ UsageError(" --large-method-max=<method-instruction-count>: threshold size for a large");
+ UsageError(" method for compiler filter tuning.");
+ UsageError(" Example: --large-method-max=%d", CompilerOptions::kDefaultLargeMethodThreshold);
+ UsageError(" Default: %d", CompilerOptions::kDefaultLargeMethodThreshold);
+ UsageError("");
+ UsageError(" --small-method-max=<method-instruction-count>: threshold size for a small");
+ UsageError(" method for compiler filter tuning.");
+ UsageError(" Example: --small-method-max=%d", CompilerOptions::kDefaultSmallMethodThreshold);
+ UsageError(" Default: %d", CompilerOptions::kDefaultSmallMethodThreshold);
+ UsageError("");
+ UsageError(" --tiny-method-max=<method-instruction-count>: threshold size for a tiny");
+ UsageError(" method for compiler filter tuning.");
+ UsageError(" Example: --tiny-method-max=%d", CompilerOptions::kDefaultTinyMethodThreshold);
+ UsageError(" Default: %d", CompilerOptions::kDefaultTinyMethodThreshold);
+ UsageError("");
+ UsageError(" --num-dex-methods=<method-count>: threshold size for a small dex file for");
+ UsageError(" compiler filter tuning. If the input has fewer than this many methods");
+ UsageError(" and the filter is not interpret-only, overrides the filter to use speed");
+ UsageError(" Example: --num-dex-method=%d", CompilerOptions::kDefaultNumDexMethodsThreshold);
+ UsageError(" Default: %d", CompilerOptions::kDefaultNumDexMethodsThreshold);
+ UsageError("");
UsageError(" --host: used with Portable backend to link against host runtime libraries");
UsageError("");
UsageError(" --dump-timing: display a breakdown of where time was spent");
@@ -163,15 +214,25 @@
class Dex2Oat {
public:
static bool Create(Dex2Oat** p_dex2oat,
- Runtime::Options& options,
+ const Runtime::Options& runtime_options,
+ const CompilerOptions& compiler_options,
CompilerBackend::Kind compiler_backend,
InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
+ VerificationResults* verification_results,
+ DexFileToMethodInlinerMap* method_inliner_map,
size_t thread_count)
SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
- UniquePtr<Dex2Oat> dex2oat(new Dex2Oat(compiler_backend, instruction_set,
- instruction_set_features, thread_count));
- if (!dex2oat->CreateRuntime(options, instruction_set)) {
+ CHECK(verification_results != nullptr);
+ CHECK(method_inliner_map != nullptr);
+ UniquePtr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options,
+ compiler_backend,
+ instruction_set,
+ instruction_set_features,
+ verification_results,
+ method_inliner_map,
+ thread_count));
+ if (!dex2oat->CreateRuntime(runtime_options, instruction_set)) {
*p_dex2oat = NULL;
return false;
}
@@ -275,8 +336,9 @@
Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);
}
- UniquePtr<CompilerDriver> driver(new CompilerDriver(verification_results_.get(),
- method_inliner_map_.get(),
+ UniquePtr<CompilerDriver> driver(new CompilerDriver(compiler_options_,
+ verification_results_,
+ method_inliner_map_,
compiler_backend_,
instruction_set_,
instruction_set_features_,
@@ -353,53 +415,30 @@
}
private:
- class Dex2OatCompilerCallbacks : public CompilerCallbacks {
- public:
- Dex2OatCompilerCallbacks(VerificationResults* verification_results,
- DexFileToMethodInlinerMap* method_inliner_map)
- : verification_results_(verification_results),
- method_inliner_map_(method_inliner_map) { }
- virtual ~Dex2OatCompilerCallbacks() { }
-
- virtual bool MethodVerified(verifier::MethodVerifier* verifier)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- bool result = verification_results_->ProcessVerifiedMethod(verifier);
- if (result) {
- MethodReference ref = verifier->GetMethodReference();
- method_inliner_map_->GetMethodInliner(ref.dex_file)
- ->AnalyseMethodCode(verifier);
- }
- return result;
- }
- virtual void ClassRejected(ClassReference ref) {
- verification_results_->AddRejectedClass(ref);
- }
-
- private:
- VerificationResults* verification_results_;
- DexFileToMethodInlinerMap* method_inliner_map_;
- };
-
- explicit Dex2Oat(CompilerBackend::Kind compiler_backend,
+ explicit Dex2Oat(const CompilerOptions* compiler_options,
+ CompilerBackend::Kind compiler_backend,
InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
+ VerificationResults* verification_results,
+ DexFileToMethodInlinerMap* method_inliner_map,
size_t thread_count)
- : compiler_backend_(compiler_backend),
+ : compiler_options_(compiler_options),
+ compiler_backend_(compiler_backend),
instruction_set_(instruction_set),
instruction_set_features_(instruction_set_features),
- verification_results_(new VerificationResults),
- method_inliner_map_(new DexFileToMethodInlinerMap),
- callbacks_(verification_results_.get(), method_inliner_map_.get()),
+ verification_results_(verification_results),
+ method_inliner_map_(method_inliner_map),
runtime_(nullptr),
thread_count_(thread_count),
start_ns_(NanoTime()) {
+ CHECK(compiler_options != nullptr);
+ CHECK(verification_results != nullptr);
+ CHECK(method_inliner_map != nullptr);
}
- bool CreateRuntime(Runtime::Options& options, InstructionSet instruction_set)
+ bool CreateRuntime(const Runtime::Options& runtime_options, InstructionSet instruction_set)
SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
- options.push_back(
- std::make_pair("compilercallbacks", static_cast<CompilerCallbacks*>(&callbacks_)));
- if (!Runtime::Create(options, false)) {
+ if (!Runtime::Create(runtime_options, false)) {
LOG(ERROR) << "Failed to create runtime";
return false;
}
@@ -448,14 +487,14 @@
return false;
}
+ const CompilerOptions* compiler_options_;
const CompilerBackend::Kind compiler_backend_;
const InstructionSet instruction_set_;
const InstructionSetFeatures instruction_set_features_;
- UniquePtr<VerificationResults> verification_results_;
- UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_;
- Dex2OatCompilerCallbacks callbacks_;
+ VerificationResults* verification_results_;
+ DexFileToMethodInlinerMap* method_inliner_map_;
Runtime* runtime_;
size_t thread_count_;
uint64_t start_ns_;
@@ -656,6 +695,9 @@
}
static int dex2oat(int argc, char** argv) {
+ original_argc = argc;
+ original_argv = argv;
+
TimingLogger timings("compiler", false, false);
CumulativeLogger compiler_phases_timings("compilation times");
@@ -690,6 +732,12 @@
CompilerBackend::Kind compiler_backend = kUsePortableCompiler
? CompilerBackend::kPortable
: CompilerBackend::kQuick;
+ const char* compiler_filter_string = NULL;
+ int huge_method_threshold = CompilerOptions::kDefaultHugeMethodThreshold;
+ int large_method_threshold = CompilerOptions::kDefaultLargeMethodThreshold;
+ int small_method_threshold = CompilerOptions::kDefaultSmallMethodThreshold;
+ int tiny_method_threshold = CompilerOptions::kDefaultTinyMethodThreshold;
+ int num_dex_methods_threshold = CompilerOptions::kDefaultNumDexMethodsThreshold;
// Take the default set of instruction features from the build.
InstructionSetFeatures instruction_set_features =
@@ -713,7 +761,6 @@
bool dump_slow_timing = kIsDebugBuild;
bool watch_dog_enabled = !kIsTargetBuild;
-
for (int i = 0; i < argc; i++) {
const StringPiece option(argv[i]);
bool log_options = false;
@@ -729,6 +776,9 @@
if (!ParseInt(zip_fd_str, &zip_fd)) {
Usage("Failed to parse --zip-fd argument '%s' as an integer", zip_fd_str);
}
+ if (zip_fd < 0) {
+ Usage("--zip-fd passed a negative value %d", zip_fd);
+ }
} else if (option.starts_with("--zip-location=")) {
zip_location = option.substr(strlen("--zip-location=")).data();
} else if (option.starts_with("--oat-file=")) {
@@ -740,6 +790,9 @@
if (!ParseInt(oat_fd_str, &oat_fd)) {
Usage("Failed to parse --oat-fd argument '%s' as an integer", oat_fd_str);
}
+ if (oat_fd < 0) {
+ Usage("--oat-fd passed a negative value %d", oat_fd);
+ }
} else if (option == "--watch-dog") {
watch_dog_enabled = true;
} else if (option == "--no-watch-dog") {
@@ -793,6 +846,48 @@
} else if (backend_str == "Portable") {
compiler_backend = CompilerBackend::kPortable;
}
+ } else if (option.starts_with("--compiler-filter=")) {
+ compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
+ } else if (option.starts_with("--huge-method-max=")) {
+ const char* threshold = option.substr(strlen("--huge-method-max=")).data();
+ if (!ParseInt(threshold, &huge_method_threshold)) {
+ Usage("Failed to parse --huge-method-max '%s' as an integer", threshold);
+ }
+ if (huge_method_threshold < 0) {
+ Usage("--huge-method-max passed a negative value %s", huge_method_threshold);
+ }
+ } else if (option.starts_with("--large-method-max=")) {
+ const char* threshold = option.substr(strlen("--large-method-max=")).data();
+ if (!ParseInt(threshold, &large_method_threshold)) {
+ Usage("Failed to parse --large-method-max '%s' as an integer", threshold);
+ }
+ if (large_method_threshold < 0) {
+ Usage("--large-method-max passed a negative value %s", large_method_threshold);
+ }
+ } else if (option.starts_with("--small-method-max=")) {
+ const char* threshold = option.substr(strlen("--small-method-max=")).data();
+ if (!ParseInt(threshold, &small_method_threshold)) {
+ Usage("Failed to parse --small-method-max '%s' as an integer", threshold);
+ }
+ if (small_method_threshold < 0) {
+ Usage("--small-method-max passed a negative value %s", small_method_threshold);
+ }
+ } else if (option.starts_with("--tiny-method-max=")) {
+ const char* threshold = option.substr(strlen("--tiny-method-max=")).data();
+ if (!ParseInt(threshold, &tiny_method_threshold)) {
+ Usage("Failed to parse --tiny-method-max '%s' as an integer", threshold);
+ }
+ if (tiny_method_threshold < 0) {
+ Usage("--tiny-method-max passed a negative value %s", tiny_method_threshold);
+ }
+ } else if (option.starts_with("--num-dex-methods=")) {
+ const char* threshold = option.substr(strlen("--num-dex-methods=")).data();
+ if (!ParseInt(threshold, &num_dex_methods_threshold)) {
+ Usage("Failed to parse --num-dex-methods '%s' as an integer", threshold);
+ }
+ if (num_dex_methods_threshold < 0) {
+ Usage("--num-dex-methods passed a negative value %s", num_dex_methods_threshold);
+ }
} else if (option == "--host") {
is_host = true;
} else if (option == "--runtime-arg") {
@@ -915,6 +1010,44 @@
oat_unstripped += oat_filename;
}
+ if (compiler_filter_string == NULL) {
+ if (image) {
+ compiler_filter_string = "everything";
+ } else {
+#if ART_SMALL_MODE
+ compiler_filter_string = "interpret-only";
+#else
+ compiler_filter_string = "speed";
+#endif
+ }
+ }
+ CHECK(compiler_filter_string != nullptr);
+ CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter;
+ if (strcmp(compiler_filter_string, "interpret-only") == 0) {
+ compiler_filter = CompilerOptions::kInterpretOnly;
+ } else if (strcmp(compiler_filter_string, "space") == 0) {
+ compiler_filter = CompilerOptions::kSpace;
+ } else if (strcmp(compiler_filter_string, "balanced") == 0) {
+ compiler_filter = CompilerOptions::kBalanced;
+ } else if (strcmp(compiler_filter_string, "speed") == 0) {
+ compiler_filter = CompilerOptions::kSpeed;
+ } else if (strcmp(compiler_filter_string, "everything") == 0) {
+ compiler_filter = CompilerOptions::kEverything;
+ } else {
+ Usage("Unknown --compiler-filter value %s", compiler_filter_string);
+ }
+
+ CompilerOptions compiler_options(compiler_filter,
+ huge_method_threshold,
+ large_method_threshold,
+ small_method_threshold,
+ tiny_method_threshold,
+ num_dex_methods_threshold
+#ifdef ART_SEA_IR_MODE
+ , compiler_options.sea_ir_ = true;
+#endif
+ ); // NOLINT(whitespace/parens)
+
// Done with usage checks, enable watchdog if requested
WatchDog watch_dog(watch_dog_enabled);
@@ -940,22 +1073,9 @@
}
timings.StartSplit("dex2oat Setup");
- LOG(INFO) << "dex2oat: " << oat_location;
+ LOG(INFO) << "dex2oat: " << CommandLine();
- if (image) {
- bool has_compiler_filter = false;
- for (const char* r : runtime_args) {
- if (strncmp(r, "-compiler-filter:", 17) == 0) {
- has_compiler_filter = true;
- break;
- }
- }
- if (!has_compiler_filter) {
- runtime_args.push_back("-compiler-filter:everything");
- }
- }
-
- Runtime::Options options;
+ Runtime::Options runtime_options;
std::vector<const DexFile*> boot_class_path;
if (boot_image_option.empty()) {
size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path);
@@ -963,24 +1083,33 @@
LOG(ERROR) << "Failed to open some dex files: " << failure_count;
return EXIT_FAILURE;
}
- options.push_back(std::make_pair("bootclasspath", &boot_class_path));
+ runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path));
} else {
- options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
+ runtime_options.push_back(std::make_pair(boot_image_option.c_str(),
+ reinterpret_cast<void*>(NULL)));
}
if (host_prefix.get() != NULL) {
- options.push_back(std::make_pair("host-prefix", host_prefix->c_str()));
+ runtime_options.push_back(std::make_pair("host-prefix", host_prefix->c_str()));
}
for (size_t i = 0; i < runtime_args.size(); i++) {
- options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL)));
+ runtime_options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL)));
}
-#ifdef ART_SEA_IR_MODE
- options.push_back(std::make_pair("-sea_ir", reinterpret_cast<void*>(NULL)));
-#endif
+ VerificationResults verification_results(&compiler_options);
+ DexFileToMethodInlinerMap method_inliner_map;
+ CompilerCallbacksImpl callbacks(&verification_results, &method_inliner_map);
+ runtime_options.push_back(std::make_pair("compilercallbacks", &callbacks));
Dex2Oat* p_dex2oat;
- if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set,
- instruction_set_features, thread_count)) {
+ if (!Dex2Oat::Create(&p_dex2oat,
+ runtime_options,
+ compiler_options,
+ compiler_backend,
+ instruction_set,
+ instruction_set_features,
+ &verification_results,
+ &method_inliner_map,
+ thread_count)) {
LOG(ERROR) << "Failed to create dex2oat";
return EXIT_FAILURE;
}
@@ -1050,7 +1179,8 @@
std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", getpid(), i));
UniquePtr<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";
+ PLOG(ERROR) << "Failed to open file " << tmp_file_name
+ << ". Try: adb shell chmod 777 /data/local/tmp";
continue;
}
tmp_file->WriteFully(dex_file->Begin(), dex_file->Size());
@@ -1070,15 +1200,15 @@
* If we're not in interpret-only mode, go ahead and compile small applications. Don't
* bother to check if we're doing the image.
*/
- if (!image && (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly)) {
+ if (!image && (compiler_options.GetCompilerFilter() != CompilerOptions::kInterpretOnly)) {
size_t num_methods = 0;
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
num_methods += dex_file->NumMethodIds();
}
- if (num_methods <= Runtime::Current()->GetNumDexMethodsThreshold()) {
- Runtime::Current()->SetCompilerFilter(Runtime::kSpeed);
+ if (num_methods <= compiler_options.GetNumDexMethodsThreshold()) {
+ compiler_options.SetCompilerFilter(CompilerOptions::kSpeed);
VLOG(compiler) << "Below method threshold, compiling anyways";
}
}
@@ -1222,13 +1352,13 @@
// Everything was successfully written, do an explicit exit here to avoid running Runtime
// destructors that take time (bug 10645725) unless we're a debug build or running on valgrind.
- if (!kIsDebugBuild || (RUNNING_ON_VALGRIND == 0)) {
+ if (!kIsDebugBuild && (RUNNING_ON_VALGRIND == 0)) {
dex2oat->LogCompletionTime();
exit(EXIT_SUCCESS);
}
return EXIT_SUCCESS;
-}
+} // NOLINT(readability/fn_size)
} // namespace art
int main(int argc, char** argv) {