diff options
| -rw-r--r-- | compiler/dex/quick/quick_cfi_test.cc | 1 | ||||
| -rw-r--r-- | compiler/dex/quick/x86/quick_assemble_x86_test.cc | 1 | ||||
| -rw-r--r-- | compiler/driver/compiler_options.cc | 157 | ||||
| -rw-r--r-- | compiler/driver/compiler_options.h | 66 | ||||
| -rw-r--r-- | compiler/jit/jit_compiler.cc | 17 | ||||
| -rw-r--r-- | dex2oat/dex2oat.cc | 296 | ||||
| -rw-r--r-- | runtime/utils.cc | 39 | ||||
| -rw-r--r-- | runtime/utils.h | 31 |
8 files changed, 306 insertions, 302 deletions
diff --git a/compiler/dex/quick/quick_cfi_test.cc b/compiler/dex/quick/quick_cfi_test.cc index 18c2e55700..24daf2f15f 100644 --- a/compiler/dex/quick/quick_cfi_test.cc +++ b/compiler/dex/quick/quick_cfi_test.cc @@ -67,7 +67,6 @@ class QuickCFITest : public CFITest { false, false, nullptr, - new PassManagerOptions(), nullptr, false); VerificationResults verification_results(&compiler_options); diff --git a/compiler/dex/quick/x86/quick_assemble_x86_test.cc b/compiler/dex/quick/x86/quick_assemble_x86_test.cc index d9571c5f26..e977ebf722 100644 --- a/compiler/dex/quick/x86/quick_assemble_x86_test.cc +++ b/compiler/dex/quick/x86/quick_assemble_x86_test.cc @@ -50,7 +50,6 @@ class QuickAssembleX86TestBase : public testing::Test { false, false, nullptr, - new PassManagerOptions(), nullptr, false)); verification_results_.reset(new VerificationResults(compiler_options_.get())); diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index 3f5a1eabb6..a24c8a3347 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -16,6 +16,8 @@ #include "compiler_options.h" +#include <fstream> + #include "dex/pass_manager.h" namespace art { @@ -27,8 +29,8 @@ CompilerOptions::CompilerOptions() small_method_threshold_(kDefaultSmallMethodThreshold), tiny_method_threshold_(kDefaultTinyMethodThreshold), num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold), - inline_depth_limit_(kDefaultInlineDepthLimit), - inline_max_code_units_(kDefaultInlineMaxCodeUnits), + inline_depth_limit_(kUnsetInlineDepthLimit), + inline_max_code_units_(kUnsetInlineMaxCodeUnits), include_patch_information_(kDefaultIncludePatchInformation), top_k_profile_threshold_(kDefaultTopKProfileThreshold), debuggable_(false), @@ -38,7 +40,7 @@ CompilerOptions::CompilerOptions() implicit_suspend_checks_(false), compile_pic_(false), verbose_methods_(nullptr), - pass_manager_options_(new PassManagerOptions), + pass_manager_options_(), abort_on_hard_verifier_failure_(false), init_failure_output_(nullptr) { } @@ -65,7 +67,6 @@ CompilerOptions::CompilerOptions(CompilerFilter compiler_filter, bool implicit_suspend_checks, bool compile_pic, const std::vector<std::string>* verbose_methods, - PassManagerOptions* pass_manager_options, std::ostream* init_failure_output, bool abort_on_hard_verifier_failure ) : // NOLINT(whitespace/parens) @@ -86,9 +87,155 @@ CompilerOptions::CompilerOptions(CompilerFilter compiler_filter, implicit_suspend_checks_(implicit_suspend_checks), compile_pic_(compile_pic), verbose_methods_(verbose_methods), - pass_manager_options_(pass_manager_options), + pass_manager_options_(), abort_on_hard_verifier_failure_(abort_on_hard_verifier_failure), init_failure_output_(init_failure_output) { } +void CompilerOptions::ParseHugeMethodMax(const StringPiece& option, UsageFn Usage) { + ParseUintOption(option, "--huge-method-max", &huge_method_threshold_, Usage); +} + +void CompilerOptions::ParseLargeMethodMax(const StringPiece& option, UsageFn Usage) { + ParseUintOption(option, "--large-method-max", &large_method_threshold_, Usage); +} + +void CompilerOptions::ParseSmallMethodMax(const StringPiece& option, UsageFn Usage) { + ParseUintOption(option, "--small-method-max", &small_method_threshold_, Usage); +} + +void CompilerOptions::ParseTinyMethodMax(const StringPiece& option, UsageFn Usage) { + ParseUintOption(option, "--tiny-method-max", &tiny_method_threshold_, Usage); +} + +void CompilerOptions::ParseNumDexMethods(const StringPiece& option, UsageFn Usage) { + ParseUintOption(option, "--num-dex-methods", &num_dex_methods_threshold_, Usage); +} + +void CompilerOptions::ParseInlineDepthLimit(const StringPiece& option, UsageFn Usage) { + ParseUintOption(option, "--inline-depth-limit", &inline_depth_limit_, Usage); +} + +void CompilerOptions::ParseInlineMaxCodeUnits(const StringPiece& option, UsageFn Usage) { + ParseUintOption(option, "--inline-max-code-units=", &inline_max_code_units_, Usage); +} + +void CompilerOptions::ParseDisablePasses(const StringPiece& option, + UsageFn Usage ATTRIBUTE_UNUSED) { + DCHECK(option.starts_with("--disable-passes=")); + const std::string disable_passes = option.substr(strlen("--disable-passes=")).data(); + pass_manager_options_.SetDisablePassList(disable_passes); +} + +void CompilerOptions::ParsePrintPasses(const StringPiece& option, + UsageFn Usage ATTRIBUTE_UNUSED) { + DCHECK(option.starts_with("--print-passes=")); + const std::string print_passes = option.substr(strlen("--print-passes=")).data(); + pass_manager_options_.SetPrintPassList(print_passes); +} + +void CompilerOptions::ParseDumpCfgPasses(const StringPiece& option, + UsageFn Usage ATTRIBUTE_UNUSED) { + DCHECK(option.starts_with("--dump-cfg-passes=")); + const std::string dump_passes_string = option.substr(strlen("--dump-cfg-passes=")).data(); + pass_manager_options_.SetDumpPassList(dump_passes_string); +} + +void CompilerOptions::ParsePassOptions(const StringPiece& option, + UsageFn Usage ATTRIBUTE_UNUSED) { + DCHECK(option.starts_with("--pass-options=")); + const std::string pass_options = option.substr(strlen("--pass-options=")).data(); + pass_manager_options_.SetOverriddenPassOptions(pass_options); +} + +void CompilerOptions::ParseDumpInitFailures(const StringPiece& option, + UsageFn Usage ATTRIBUTE_UNUSED) { + DCHECK(option.starts_with("--dump-init-failures=")); + std::string file_name = option.substr(strlen("--dump-init-failures=")).data(); + init_failure_output_.reset(new std::ofstream(file_name)); + if (init_failure_output_.get() == nullptr) { + LOG(ERROR) << "Failed to allocate ofstream"; + } else if (init_failure_output_->fail()) { + LOG(ERROR) << "Failed to open " << file_name << " for writing the initialization " + << "failures."; + init_failure_output_.reset(); + } +} + +bool CompilerOptions::ParseCompilerOption(const StringPiece& option, UsageFn Usage) { + if (option.starts_with("--compiler-filter=")) { + const char* compiler_filter_string = option.substr(strlen("--compiler-filter=")).data(); + if (strcmp(compiler_filter_string, "verify-none") == 0) { + compiler_filter_ = CompilerOptions::kVerifyNone; + } else if (strcmp(compiler_filter_string, "interpret-only") == 0) { + compiler_filter_ = CompilerOptions::kInterpretOnly; + } else if (strcmp(compiler_filter_string, "verify-at-runtime") == 0) { + compiler_filter_ = CompilerOptions::kVerifyAtRuntime; + } 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 if (strcmp(compiler_filter_string, "time") == 0) { + compiler_filter_ = CompilerOptions::kTime; + } else { + Usage("Unknown --compiler-filter value %s", compiler_filter_string); + } + } else if (option == "--compile-pic") { + compile_pic_ = true; + } else if (option.starts_with("--huge-method-max=")) { + ParseHugeMethodMax(option, Usage); + } else if (option.starts_with("--large-method-max=")) { + ParseLargeMethodMax(option, Usage); + } else if (option.starts_with("--small-method-max=")) { + ParseSmallMethodMax(option, Usage); + } else if (option.starts_with("--tiny-method-max=")) { + ParseTinyMethodMax(option, Usage); + } else if (option.starts_with("--num-dex-methods=")) { + ParseNumDexMethods(option, Usage); + } else if (option.starts_with("--inline-depth-limit=")) { + ParseInlineDepthLimit(option, Usage); + } else if (option.starts_with("--inline-max-code-units=")) { + ParseInlineMaxCodeUnits(option, Usage); + } else if (option == "--generate-debug-info" || option == "-g") { + generate_debug_info_ = true; + } else if (option == "--no-generate-debug-info") { + generate_debug_info_ = false; + } else if (option == "--debuggable") { + debuggable_ = true; + generate_debug_info_ = true; + } else if (option.starts_with("--top-k-profile-threshold=")) { + ParseDouble(option.data(), '=', 0.0, 100.0, &top_k_profile_threshold_, Usage); + } else if (option == "--include-patch-information") { + include_patch_information_ = true; + } else if (option == "--no-include-patch-information") { + include_patch_information_ = false; + } else if (option == "--abort-on-hard-verifier-error") { + abort_on_hard_verifier_failure_ = true; + } else if (option == "--print-pass-names") { + pass_manager_options_.SetPrintPassNames(true); + } else if (option.starts_with("--disable-passes=")) { + ParseDisablePasses(option, Usage); + } else if (option.starts_with("--print-passes=")) { + ParsePrintPasses(option, Usage); + } else if (option == "--print-all-passes") { + pass_manager_options_.SetPrintAllPasses(); + } else if (option.starts_with("--dump-cfg-passes=")) { + ParseDumpCfgPasses(option, Usage); + } else if (option == "--print-pass-options") { + pass_manager_options_.SetPrintPassOptions(true); + } else if (option.starts_with("--pass-options=")) { + ParsePassOptions(option, Usage); + } else if (option.starts_with("--dump-init-failures=")) { + ParseDumpInitFailures(option, Usage); + } else { + // Option not recognized. + return false; + } + return true; +} + } // namespace art diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index 18f215d165..e6acab42f2 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -22,12 +22,12 @@ #include <vector> #include "base/macros.h" +#include "dex/pass_manager.h" #include "globals.h" +#include "utils.h" namespace art { -class PassManagerOptions; - class CompilerOptions FINAL { public: enum CompilerFilter { @@ -53,6 +53,8 @@ class CompilerOptions FINAL { static const bool kDefaultIncludePatchInformation = false; static const size_t kDefaultInlineDepthLimit = 3; static const size_t kDefaultInlineMaxCodeUnits = 20; + static constexpr size_t kUnsetInlineDepthLimit = -1; + static constexpr size_t kUnsetInlineMaxCodeUnits = -1; // Default inlining settings when the space filter is used. static constexpr size_t kSpaceFilterInlineDepthLimit = 3; @@ -78,7 +80,6 @@ class CompilerOptions FINAL { bool implicit_suspend_checks, bool compile_pic, const std::vector<std::string>* verbose_methods, - PassManagerOptions* pass_manager_options, std::ostream* init_failure_output, bool abort_on_hard_verifier_failure); @@ -200,47 +201,64 @@ class CompilerOptions FINAL { } std::ostream* GetInitFailureOutput() const { - return init_failure_output_; + return init_failure_output_.get(); } const PassManagerOptions* GetPassManagerOptions() const { - return pass_manager_options_.get(); + return &pass_manager_options_; } bool AbortOnHardVerifierFailure() const { return abort_on_hard_verifier_failure_; } + bool ParseCompilerOption(const StringPiece& option, UsageFn Usage); + private: + void ParseDumpInitFailures(const StringPiece& option, UsageFn Usage); + void ParsePassOptions(const StringPiece& option, UsageFn Usage); + void ParseDumpCfgPasses(const StringPiece& option, UsageFn Usage); + void ParsePrintPasses(const StringPiece& option, UsageFn Usage); + void ParseDisablePasses(const StringPiece& option, UsageFn Usage); + void ParseInlineMaxCodeUnits(const StringPiece& option, UsageFn Usage); + void ParseInlineDepthLimit(const StringPiece& option, UsageFn Usage); + void ParseNumDexMethods(const StringPiece& option, UsageFn Usage); + void ParseTinyMethodMax(const StringPiece& option, UsageFn Usage); + void ParseSmallMethodMax(const StringPiece& option, UsageFn Usage); + void ParseLargeMethodMax(const StringPiece& option, UsageFn Usage); + void ParseHugeMethodMax(const StringPiece& option, UsageFn Usage); + CompilerFilter compiler_filter_; - const size_t huge_method_threshold_; - const size_t large_method_threshold_; - const size_t small_method_threshold_; - const size_t tiny_method_threshold_; - const size_t num_dex_methods_threshold_; - const size_t inline_depth_limit_; - const size_t inline_max_code_units_; - const bool include_patch_information_; + size_t huge_method_threshold_; + size_t large_method_threshold_; + size_t small_method_threshold_; + size_t tiny_method_threshold_; + size_t num_dex_methods_threshold_; + size_t inline_depth_limit_; + size_t inline_max_code_units_; + bool include_patch_information_; // When using a profile file only the top K% of the profiled samples will be compiled. - const double top_k_profile_threshold_; - const bool debuggable_; - const bool generate_debug_info_; - const bool implicit_null_checks_; - const bool implicit_so_checks_; - const bool implicit_suspend_checks_; - const bool compile_pic_; + double top_k_profile_threshold_; + bool debuggable_; + bool generate_debug_info_; + bool implicit_null_checks_; + bool implicit_so_checks_; + bool implicit_suspend_checks_; + bool compile_pic_; // Vector of methods to have verbose output enabled for. - const std::vector<std::string>* const verbose_methods_; + const std::vector<std::string>* verbose_methods_; - std::unique_ptr<PassManagerOptions> pass_manager_options_; + PassManagerOptions pass_manager_options_; // Abort compilation with an error if we find a class that fails verification with a hard // failure. - const bool abort_on_hard_verifier_failure_; + bool abort_on_hard_verifier_failure_; // Log initialization of initialization failures to this stream if not null. - std::ostream* const init_failure_output_; + std::unique_ptr<std::ostream> init_failure_output_; + + friend class Dex2Oat; DISALLOW_COPY_AND_ASSIGN(CompilerOptions); }; diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index b563c80f7d..c1b87c9cd0 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -63,9 +63,18 @@ extern "C" bool jit_compile_method(void* handle, ArtMethod* method, Thread* self return jit_compiler->CompileMethod(self, method); } +// Callers of this method assume it has NO_RETURN. +NO_RETURN static void Usage(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + std::string error; + StringAppendV(&error, fmt, ap); + LOG(FATAL) << error; + va_end(ap); + exit(EXIT_FAILURE); +} + JitCompiler::JitCompiler() : total_time_(0) { - auto* pass_manager_options = new PassManagerOptions; - pass_manager_options->SetDisablePassList("GVN,DCE,GVNCleanup"); compiler_options_.reset(new CompilerOptions( CompilerOptions::kDefaultCompilerFilter, CompilerOptions::kDefaultHugeMethodThreshold, @@ -84,9 +93,11 @@ JitCompiler::JitCompiler() : total_time_(0) { /* implicit_suspend_checks */ false, /* pic */ true, // TODO: Support non-PIC in optimizing. /* verbose_methods */ nullptr, - pass_manager_options, /* init_failure_output */ nullptr, /* abort_on_hard_verifier_failure */ false)); + for (const std::string& argument : Runtime::Current()->GetCompilerOptions()) { + compiler_options_->ParseCompilerOption(argument, Usage); + } const InstructionSet instruction_set = kRuntimeISA; for (const StringPiece option : Runtime::Current()->GetCompilerOptions()) { VLOG(compiler) << "JIT compiler option " << option; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index af0bb65ccd..efc0ca613e 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -445,38 +445,6 @@ class WatchDog { pthread_t pthread_; }; -static void ParseStringAfterChar(const std::string& s, char c, std::string* parsed_value) { - std::string::size_type colon = s.find(c); - if (colon == std::string::npos) { - Usage("Missing char %c in option %s\n", c, s.c_str()); - } - // Add one to remove the char we were trimming until. - *parsed_value = s.substr(colon + 1); -} - -static void ParseDouble(const std::string& option, char after_char, double min, double max, - double* parsed_value) { - std::string substring; - ParseStringAfterChar(option, after_char, &substring); - bool sane_val = true; - double value; - if (false) { - // TODO: this doesn't seem to work on the emulator. b/15114595 - std::stringstream iss(substring); - iss >> value; - // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range. - sane_val = iss.eof() && (value >= min) && (value <= max); - } else { - char* end = nullptr; - value = strtod(substring.c_str(), &end); - sane_val = *end == '\0' && value >= min && value <= max; - } - if (!sane_val) { - Usage("Invalid double value %s for option %s\n", substring.c_str(), option.c_str()); - } - *parsed_value = value; -} - static constexpr size_t kMinDexFilesForSwap = 2; static constexpr size_t kMinDexFileCumulativeSizeForSwap = 20 * MB; @@ -555,66 +523,21 @@ class Dex2Oat FINAL { struct ParserOptions { std::string oat_symbols; std::string boot_image_filename; - const char* compiler_filter_string = nullptr; - CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter; - bool compile_pic = false; - 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; - static constexpr int kUnsetInlineDepthLimit = -1; - int inline_depth_limit = kUnsetInlineDepthLimit; - static constexpr int kUnsetInlineMaxCodeUnits = -1; - int inline_max_code_units = kUnsetInlineMaxCodeUnits; - - // Profile file to use - double top_k_profile_threshold = CompilerOptions::kDefaultTopKProfileThreshold; - - bool debuggable = false; - bool include_patch_information = CompilerOptions::kDefaultIncludePatchInformation; - bool generate_debug_info = kIsDebugBuild; bool watch_dog_enabled = true; - bool abort_on_hard_verifier_error = false; bool requested_specific_compiler = false; - - bool implicit_null_checks = false; - bool implicit_so_checks = false; - bool implicit_suspend_checks = false; - - PassManagerOptions pass_manager_options; - std::string error_msg; }; - template <typename T> - static void ParseUintOption(const StringPiece& option, - const std::string& option_name, - T* out, - bool is_long_option = true) { - std::string option_prefix = option_name + (is_long_option ? "=" : ""); - DCHECK(option.starts_with(option_prefix)); - const char* value_string = option.substr(option_prefix.size()).data(); - int64_t parsed_integer_value; - if (!ParseInt(value_string, &parsed_integer_value)) { - Usage("Failed to parse %s '%s' as an integer", option_name.c_str(), value_string); - } - if (parsed_integer_value < 0) { - Usage("%s passed a negative value %d", option_name.c_str(), parsed_integer_value); - } - *out = dchecked_integral_cast<T>(parsed_integer_value); - } - void ParseZipFd(const StringPiece& option) { - ParseUintOption(option, "--zip-fd", &zip_fd_); + ParseUintOption(option, "--zip-fd", &zip_fd_, Usage); } void ParseOatFd(const StringPiece& option) { - ParseUintOption(option, "--oat-fd", &oat_fd_); + ParseUintOption(option, "--oat-fd", &oat_fd_, Usage); } void ParseJ(const StringPiece& option) { - ParseUintOption(option, "-j", &thread_count_, /* is_long_option */ false); + ParseUintOption(option, "-j", &thread_count_, Usage, /* is_long_option */ false); } void ParseBase(const StringPiece& option) { @@ -685,80 +608,15 @@ class Dex2Oat FINAL { } } - void ParseHugeMethodMax(const StringPiece& option, ParserOptions* parser_options) { - ParseUintOption(option, "--huge-method-max", &parser_options->huge_method_threshold); - } - - void ParseLargeMethodMax(const StringPiece& option, ParserOptions* parser_options) { - ParseUintOption(option, "--large-method-max", &parser_options->large_method_threshold); - } - - void ParseSmallMethodMax(const StringPiece& option, ParserOptions* parser_options) { - ParseUintOption(option, "--small-method-max", &parser_options->small_method_threshold); - } - - void ParseTinyMethodMax(const StringPiece& option, ParserOptions* parser_options) { - ParseUintOption(option, "--tiny-method-max", &parser_options->tiny_method_threshold); - } - - void ParseNumDexMethods(const StringPiece& option, ParserOptions* parser_options) { - ParseUintOption(option, "--num-dex-methods", &parser_options->num_dex_methods_threshold); - } - - void ParseInlineDepthLimit(const StringPiece& option, ParserOptions* parser_options) { - ParseUintOption(option, "--inline-depth-limit", &parser_options->inline_depth_limit); - } - - void ParseInlineMaxCodeUnits(const StringPiece& option, ParserOptions* parser_options) { - ParseUintOption(option, "--inline-max-code-units=", &parser_options->inline_max_code_units); - } - - void ParseDisablePasses(const StringPiece& option, ParserOptions* parser_options) { - DCHECK(option.starts_with("--disable-passes=")); - const std::string disable_passes = option.substr(strlen("--disable-passes=")).data(); - parser_options->pass_manager_options.SetDisablePassList(disable_passes); - } - - void ParsePrintPasses(const StringPiece& option, ParserOptions* parser_options) { - DCHECK(option.starts_with("--print-passes=")); - const std::string print_passes = option.substr(strlen("--print-passes=")).data(); - parser_options->pass_manager_options.SetPrintPassList(print_passes); - } - - void ParseDumpCfgPasses(const StringPiece& option, ParserOptions* parser_options) { - DCHECK(option.starts_with("--dump-cfg-passes=")); - const std::string dump_passes_string = option.substr(strlen("--dump-cfg-passes=")).data(); - parser_options->pass_manager_options.SetDumpPassList(dump_passes_string); - } - - void ParsePassOptions(const StringPiece& option, ParserOptions* parser_options) { - DCHECK(option.starts_with("--pass-options=")); - const std::string pass_options = option.substr(strlen("--pass-options=")).data(); - parser_options->pass_manager_options.SetOverriddenPassOptions(pass_options); - } - - void ParseDumpInitFailures(const StringPiece& option) { - DCHECK(option.starts_with("--dump-init-failures=")); - std::string file_name = option.substr(strlen("--dump-init-failures=")).data(); - init_failure_output_.reset(new std::ofstream(file_name)); - if (init_failure_output_.get() == nullptr) { - LOG(ERROR) << "Failed to allocate ofstream"; - } else if (init_failure_output_->fail()) { - LOG(ERROR) << "Failed to open " << file_name << " for writing the initialization " - << "failures."; - init_failure_output_.reset(); - } - } - void ParseSwapFd(const StringPiece& option) { - ParseUintOption(option, "--swap-fd", &swap_fd_); + ParseUintOption(option, "--swap-fd", &swap_fd_, Usage); } void ProcessOptions(ParserOptions* parser_options) { image_ = (!image_filename_.empty()); if (image_) { // We need the boot image to always be debuggable. - parser_options->debuggable = true; + compiler_options_->debuggable_ = true; } if (oat_filename_.empty() && oat_fd_ == -1) { @@ -882,44 +740,19 @@ class Dex2Oat FINAL { } } - if (parser_options->compiler_filter_string == nullptr) { - parser_options->compiler_filter_string = "speed"; - } - - CHECK(parser_options->compiler_filter_string != nullptr); - if (strcmp(parser_options->compiler_filter_string, "verify-none") == 0) { - parser_options->compiler_filter = CompilerOptions::kVerifyNone; - } else if (strcmp(parser_options->compiler_filter_string, "interpret-only") == 0) { - parser_options->compiler_filter = CompilerOptions::kInterpretOnly; - } else if (strcmp(parser_options->compiler_filter_string, "verify-at-runtime") == 0) { - parser_options->compiler_filter = CompilerOptions::kVerifyAtRuntime; - } else if (strcmp(parser_options->compiler_filter_string, "space") == 0) { - parser_options->compiler_filter = CompilerOptions::kSpace; - } else if (strcmp(parser_options->compiler_filter_string, "balanced") == 0) { - parser_options->compiler_filter = CompilerOptions::kBalanced; - } else if (strcmp(parser_options->compiler_filter_string, "speed") == 0) { - parser_options->compiler_filter = CompilerOptions::kSpeed; - } else if (strcmp(parser_options->compiler_filter_string, "everything") == 0) { - parser_options->compiler_filter = CompilerOptions::kEverything; - } else if (strcmp(parser_options->compiler_filter_string, "time") == 0) { - parser_options->compiler_filter = CompilerOptions::kTime; - } else { - Usage("Unknown --compiler-filter value %s", parser_options->compiler_filter_string); - } - // It they are not set, use default values for inlining settings. // TODO: We should rethink the compiler filter. We mostly save // time here, which is orthogonal to space. - if (parser_options->inline_depth_limit == ParserOptions::kUnsetInlineDepthLimit) { - parser_options->inline_depth_limit = - (parser_options->compiler_filter == CompilerOptions::kSpace) + if (compiler_options_->inline_depth_limit_ == CompilerOptions::kUnsetInlineDepthLimit) { + compiler_options_->inline_depth_limit_ = + (compiler_options_->compiler_filter_ == CompilerOptions::kSpace) // Implementation of the space filter: limit inlining depth. ? CompilerOptions::kSpaceFilterInlineDepthLimit : CompilerOptions::kDefaultInlineDepthLimit; } - if (parser_options->inline_max_code_units == ParserOptions::kUnsetInlineMaxCodeUnits) { - parser_options->inline_max_code_units = - (parser_options->compiler_filter == CompilerOptions::kSpace) + if (compiler_options_->inline_max_code_units_ == CompilerOptions::kUnsetInlineMaxCodeUnits) { + compiler_options_->inline_max_code_units_ = + (compiler_options_->compiler_filter_ == CompilerOptions::kSpace) // Implementation of the space filter: limit inlining max code units. ? CompilerOptions::kSpaceFilterInlineMaxCodeUnits : CompilerOptions::kDefaultInlineMaxCodeUnits; @@ -935,8 +768,8 @@ class Dex2Oat FINAL { case kX86_64: case kMips: case kMips64: - parser_options->implicit_null_checks = true; - parser_options->implicit_so_checks = true; + compiler_options_->implicit_null_checks_ = true; + compiler_options_->implicit_so_checks_ = true; break; default: @@ -944,29 +777,7 @@ class Dex2Oat FINAL { break; } - compiler_options_.reset(new CompilerOptions(parser_options->compiler_filter, - parser_options->huge_method_threshold, - parser_options->large_method_threshold, - parser_options->small_method_threshold, - parser_options->tiny_method_threshold, - parser_options->num_dex_methods_threshold, - parser_options->inline_depth_limit, - parser_options->inline_max_code_units, - parser_options->include_patch_information, - parser_options->top_k_profile_threshold, - parser_options->debuggable, - parser_options->generate_debug_info, - parser_options->implicit_null_checks, - parser_options->implicit_so_checks, - parser_options->implicit_suspend_checks, - parser_options->compile_pic, - verbose_methods_.empty() ? - nullptr : - &verbose_methods_, - new PassManagerOptions( - parser_options->pass_manager_options), - init_failure_output_.get(), - parser_options->abort_on_hard_verifier_error)); + compiler_options_->verbose_methods_ = verbose_methods_.empty() ? nullptr : &verbose_methods_; // Done with usage checks, enable watchdog if requested if (parser_options->watch_dog_enabled) { @@ -977,7 +788,7 @@ class Dex2Oat FINAL { key_value_store_.reset(new SafeMap<std::string, std::string>()); } - void InsertCompileOptions(int argc, char** argv, ParserOptions* parser_options) { + void InsertCompileOptions(int argc, char** argv) { std::ostringstream oss; for (int i = 0; i < argc; ++i) { if (i > 0) { @@ -991,10 +802,10 @@ class Dex2Oat FINAL { key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str()); key_value_store_->Put( OatHeader::kPicKey, - parser_options->compile_pic ? OatHeader::kTrueValue : OatHeader::kFalseValue); + compiler_options_->compile_pic_ ? OatHeader::kTrueValue : OatHeader::kFalseValue); key_value_store_->Put( OatHeader::kDebuggableKey, - parser_options->debuggable ? OatHeader::kTrueValue : OatHeader::kFalseValue); + compiler_options_->debuggable_ ? OatHeader::kTrueValue : OatHeader::kFalseValue); } // Parse the arguments from the command line. In case of an unrecognized option or impossible @@ -1015,6 +826,7 @@ class Dex2Oat FINAL { } std::unique_ptr<ParserOptions> parser_options(new ParserOptions()); + compiler_options_.reset(new CompilerOptions()); for (int i = 0; i < argc; i++) { const StringPiece option(argv[i]); @@ -1072,24 +884,11 @@ class Dex2Oat FINAL { ParseInstructionSetFeatures(option, parser_options.get()); } else if (option.starts_with("--compiler-backend=")) { ParseCompilerBackend(option, parser_options.get()); - } else if (option.starts_with("--compiler-filter=")) { - parser_options->compiler_filter_string = option.substr(strlen("--compiler-filter=")).data(); - } else if (option == "--compile-pic") { - parser_options->compile_pic = true; - } else if (option.starts_with("--huge-method-max=")) { - ParseHugeMethodMax(option, parser_options.get()); - } else if (option.starts_with("--large-method-max=")) { - ParseLargeMethodMax(option, parser_options.get()); - } else if (option.starts_with("--small-method-max=")) { - ParseSmallMethodMax(option, parser_options.get()); - } else if (option.starts_with("--tiny-method-max=")) { - ParseTinyMethodMax(option, parser_options.get()); - } else if (option.starts_with("--num-dex-methods=")) { - ParseNumDexMethods(option, parser_options.get()); - } else if (option.starts_with("--inline-depth-limit=")) { - ParseInlineDepthLimit(option, parser_options.get()); - } else if (option.starts_with("--inline-max-code-units=")) { - ParseInlineMaxCodeUnits(option, parser_options.get()); + } else if (option.starts_with("--profile-file=")) { + profile_file_ = option.substr(strlen("--profile-file=")).data(); + VLOG(compiler) << "dex2oat: profile file is " << profile_file_; + } else if (option == "--no-profile-file") { + // No profile } else if (option == "--host") { is_host_ = true; } else if (option == "--runtime-arg") { @@ -1110,52 +909,16 @@ class Dex2Oat FINAL { dump_cfg_append_ = true; } else if (option == "--dump-stats") { dump_stats_ = true; - } else if (option == "--generate-debug-info" || option == "-g") { - parser_options->generate_debug_info = true; - } else if (option == "--no-generate-debug-info") { - parser_options->generate_debug_info = false; - } else if (option == "--debuggable") { - parser_options->debuggable = true; - parser_options->generate_debug_info = true; - } else if (option.starts_with("--profile-file=")) { - profile_file_ = option.substr(strlen("--profile-file=")).data(); - VLOG(compiler) << "dex2oat: profile file is " << profile_file_; - } else if (option == "--no-profile-file") { - // No profile - } else if (option.starts_with("--top-k-profile-threshold=")) { - ParseDouble(option.data(), '=', 0.0, 100.0, &parser_options->top_k_profile_threshold); - } else if (option == "--print-pass-names") { - parser_options->pass_manager_options.SetPrintPassNames(true); - } else if (option.starts_with("--disable-passes=")) { - ParseDisablePasses(option, parser_options.get()); - } else if (option.starts_with("--print-passes=")) { - ParsePrintPasses(option, parser_options.get()); - } else if (option == "--print-all-passes") { - parser_options->pass_manager_options.SetPrintAllPasses(); - } else if (option.starts_with("--dump-cfg-passes=")) { - ParseDumpCfgPasses(option, parser_options.get()); - } else if (option == "--print-pass-options") { - parser_options->pass_manager_options.SetPrintPassOptions(true); - } else if (option.starts_with("--pass-options=")) { - ParsePassOptions(option, parser_options.get()); - } else if (option == "--include-patch-information") { - parser_options->include_patch_information = true; - } else if (option == "--no-include-patch-information") { - parser_options->include_patch_information = false; + } else if (option.starts_with("--swap-file=")) { + swap_file_name_ = option.substr(strlen("--swap-file=")).data(); + } else if (option.starts_with("--swap-fd=")) { + ParseSwapFd(option); } else if (option.starts_with("--verbose-methods=")) { // TODO: rather than switch off compiler logging, make all VLOG(compiler) messages // conditional on having verbost methods. gLogVerbosity.compiler = false; Split(option.substr(strlen("--verbose-methods=")).ToString(), ',', &verbose_methods_); - } else if (option.starts_with("--dump-init-failures=")) { - ParseDumpInitFailures(option); - } else if (option.starts_with("--swap-file=")) { - swap_file_name_ = option.substr(strlen("--swap-file=")).data(); - } else if (option.starts_with("--swap-fd=")) { - ParseSwapFd(option); - } else if (option == "--abort-on-hard-verifier-error") { - parser_options->abort_on_hard_verifier_error = true; - } else { + } else if (!compiler_options_->ParseCompilerOption(option, Usage)) { Usage("Unknown argument %s", option.data()); } } @@ -1163,7 +926,7 @@ class Dex2Oat FINAL { ProcessOptions(parser_options.get()); // Insert some compiler things. - InsertCompileOptions(argc, argv, parser_options.get()); + InsertCompileOptions(argc, argv); } // Check whether the oat output file is writable, and open it for later. Also open a swap file, @@ -2006,7 +1769,6 @@ class Dex2Oat FINAL { std::string profile_file_; // Profile file to use TimingLogger* timings_; std::unique_ptr<CumulativeLogger> compiler_phases_timings_; - std::unique_ptr<std::ostream> init_failure_output_; DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat); }; diff --git a/runtime/utils.cc b/runtime/utils.cc index dee4f9c891..48dce63f00 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -1835,4 +1835,43 @@ void DumpMethodCFG(const DexFile* dex_file, uint32_t dex_method_idx, std::ostrea os << "Something went wrong, didn't find the method in the class data."; } +static void ParseStringAfterChar(const std::string& s, + char c, + std::string* parsed_value, + UsageFn Usage) { + std::string::size_type colon = s.find(c); + if (colon == std::string::npos) { + Usage("Missing char %c in option %s\n", c, s.c_str()); + } + // Add one to remove the char we were trimming until. + *parsed_value = s.substr(colon + 1); +} + +void ParseDouble(const std::string& option, + char after_char, + double min, + double max, + double* parsed_value, + UsageFn Usage) { + std::string substring; + ParseStringAfterChar(option, after_char, &substring, Usage); + bool sane_val = true; + double value; + if ((false)) { + // TODO: this doesn't seem to work on the emulator. b/15114595 + std::stringstream iss(substring); + iss >> value; + // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range. + sane_val = iss.eof() && (value >= min) && (value <= max); + } else { + char* end = nullptr; + value = strtod(substring.c_str(), &end); + sane_val = *end == '\0' && value >= min && value <= max; + } + if (!sane_val) { + Usage("Invalid double value %s for option %s\n", substring.c_str(), option.c_str()); + } + *parsed_value = value; +} + } // namespace art diff --git a/runtime/utils.h b/runtime/utils.h index bd52b686fd..5cca2964ce 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -26,8 +26,10 @@ #include <vector> #include "arch/instruction_set.h" +#include "base/casts.h" #include "base/logging.h" #include "base/mutex.h" +#include "base/stringpiece.h" #include "globals.h" #include "primitive.h" @@ -35,7 +37,6 @@ class BacktraceMap; namespace art { -class ArtCode; class ArtField; class ArtMethod; class DexFile; @@ -321,6 +322,34 @@ static inline const void* EntryPointToCodePointer(const void* entry_point) { return reinterpret_cast<const void*>(code); } +using UsageFn = void (*)(const char*, ...); + +template <typename T> +static void ParseUintOption(const StringPiece& option, + const std::string& option_name, + T* out, + UsageFn Usage, + bool is_long_option = true) { + std::string option_prefix = option_name + (is_long_option ? "=" : ""); + DCHECK(option.starts_with(option_prefix)); + const char* value_string = option.substr(option_prefix.size()).data(); + int64_t parsed_integer_value; + if (!ParseInt(value_string, &parsed_integer_value)) { + Usage("Failed to parse %s '%s' as an integer", option_name.c_str(), value_string); + } + if (parsed_integer_value < 0) { + Usage("%s passed a negative value %d", option_name.c_str(), parsed_integer_value); + } + *out = dchecked_integral_cast<T>(parsed_integer_value); +} + +void ParseDouble(const std::string& option, + char after_char, + double min, + double max, + double* parsed_value, + UsageFn Usage); + } // namespace art #endif // ART_RUNTIME_UTILS_H_ |