From 9ec5e2217b0130b448013796255d803c7d1052c9 Mon Sep 17 00:00:00 2001 From: Roland Levillain Date: Mon, 17 Aug 2015 20:18:41 +0100 Subject: [PATCH] Refactor art::Dex2Oat::ParseArg. Split up art::Dex2Oat::ParseArg to allow `clang++ -01 -Werror -Wframe-larger-than=1728` to compile dex2oat.cc. Change-Id: I0b45f394568765ccd849c87a7cf910507291e65d --- dex2oat/dex2oat.cc | 770 +++++++++++++++++++++++++++++------------------------ 1 file changed, 419 insertions(+), 351 deletions(-) diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 976c00281..4b66ad859 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -539,26 +539,11 @@ class Dex2Oat FINAL { } } - // Parse the arguments from the command line. In case of an unrecognized option or impossible - // values/combinations, a usage error will be displayed and exit() is called. Thus, if the method - // returns, arguments have been successfully parsed. - void ParseArgs(int argc, char** argv) { - original_argc = argc; - original_argv = argv; - - InitLogging(argv); - - // Skip over argv[0]. - argv++; - argc--; - - if (argc == 0) { - Usage("No arguments specified"); - } - + 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; @@ -580,277 +565,192 @@ class Dex2Oat FINAL { 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 + 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(); + long long int 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 = parsed_integer_value; + } - for (int i = 0; i < argc; i++) { - const StringPiece option(argv[i]); - const bool log_options = false; - if (log_options) { - LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i]; - } - if (option.starts_with("--dex-file=")) { - dex_filenames_.push_back(option.substr(strlen("--dex-file=")).data()); - } else if (option.starts_with("--dex-location=")) { - dex_locations_.push_back(option.substr(strlen("--dex-location=")).data()); - } else if (option.starts_with("--zip-fd=")) { - const char* zip_fd_str = option.substr(strlen("--zip-fd=")).data(); - 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=")) { - oat_filename_ = option.substr(strlen("--oat-file=")).data(); - } else if (option.starts_with("--oat-symbols=")) { - oat_symbols = option.substr(strlen("--oat-symbols=")).data(); - } else if (option.starts_with("--oat-fd=")) { - const char* oat_fd_str = option.substr(strlen("--oat-fd=")).data(); - 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") { - watch_dog_enabled = false; - } else if (option.starts_with("-j")) { - const char* thread_count_str = option.substr(strlen("-j")).data(); - if (!ParseUint(thread_count_str, &thread_count_)) { - Usage("Failed to parse -j argument '%s' as an integer", thread_count_str); - } - } else if (option.starts_with("--oat-location=")) { - oat_location_ = option.substr(strlen("--oat-location=")).data(); - } else if (option.starts_with("--image=")) { - image_filename_ = option.substr(strlen("--image=")).data(); - } else if (option.starts_with("--image-classes=")) { - 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("--compiled-classes=")) { - compiled_classes_filename_ = option.substr(strlen("--compiled-classes=")).data(); - } else if (option.starts_with("--compiled-classes-zip=")) { - compiled_classes_zip_filename_ = option.substr(strlen("--compiled-classes-zip=")).data(); - } else if (option.starts_with("--compiled-methods=")) { - compiled_methods_filename_ = option.substr(strlen("--compiled-methods=")).data(); - } else if (option.starts_with("--compiled-methods-zip=")) { - compiled_methods_zip_filename_ = option.substr(strlen("--compiled-methods-zip=")).data(); - } else if (option.starts_with("--base=")) { - const char* image_base_str = option.substr(strlen("--base=")).data(); - char* end; - image_base_ = strtoul(image_base_str, &end, 16); - if (end == image_base_str || *end != '\0') { - Usage("Failed to parse hexadecimal value for option %s", option.data()); - } - } else if (option.starts_with("--boot-image=")) { - boot_image_filename = option.substr(strlen("--boot-image=")).data(); - } else if (option.starts_with("--android-root=")) { - android_root_ = option.substr(strlen("--android-root=")).data(); - } else if (option.starts_with("--instruction-set=")) { - StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data(); - // StringPiece is not necessarily zero-terminated, so need to make a copy and ensure it. - std::unique_ptr buf(new char[instruction_set_str.length() + 1]); - strncpy(buf.get(), instruction_set_str.data(), instruction_set_str.length()); - buf.get()[instruction_set_str.length()] = 0; - instruction_set_ = GetInstructionSetFromString(buf.get()); - // arm actually means thumb2. - if (instruction_set_ == InstructionSet::kArm) { - instruction_set_ = InstructionSet::kThumb2; - } - } else if (option.starts_with("--instruction-set-variant=")) { - StringPiece str = option.substr(strlen("--instruction-set-variant=")).data(); - instruction_set_features_.reset( - InstructionSetFeatures::FromVariant(instruction_set_, str.as_string(), &error_msg)); - if (instruction_set_features_.get() == nullptr) { - Usage("%s", error_msg.c_str()); - } - } else if (option.starts_with("--instruction-set-features=")) { - StringPiece str = option.substr(strlen("--instruction-set-features=")).data(); - if (instruction_set_features_.get() == nullptr) { - instruction_set_features_.reset( - InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg)); - if (instruction_set_features_.get() == nullptr) { - Usage("Problem initializing default instruction set features variant: %s", - error_msg.c_str()); - } - } - instruction_set_features_.reset( - instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg)); - if (instruction_set_features_.get() == nullptr) { - Usage("Error parsing '%s': %s", option.data(), error_msg.c_str()); - } - } else if (option.starts_with("--compiler-backend=")) { - requested_specific_compiler = true; - StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data(); - if (backend_str == "Quick") { - compiler_kind_ = Compiler::kQuick; - } else if (backend_str == "Optimizing") { - compiler_kind_ = Compiler::kOptimizing; - } else { - Usage("Unknown compiler backend: %s", backend_str.data()); - } - } else if (option.starts_with("--compiler-filter=")) { - compiler_filter_string = option.substr(strlen("--compiler-filter=")).data(); - } else if (option == "--compile-pic") { - compile_pic = true; - } 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.starts_with("--inline-depth-limit=")) { - const char* limit = option.substr(strlen("--inline-depth-limit=")).data(); - if (!ParseInt(limit, &inline_depth_limit)) { - Usage("Failed to parse --inline-depth-limit '%s' as an integer", limit); - } - if (inline_depth_limit < 0) { - Usage("--inline-depth-limit passed a negative value %s", inline_depth_limit); - } - } else if (option.starts_with("--inline-max-code-units=")) { - const char* code_units = option.substr(strlen("--inline-max-code-units=")).data(); - if (!ParseInt(code_units, &inline_max_code_units)) { - Usage("Failed to parse --inline-max-code-units '%s' as an integer", code_units); - } - if (inline_max_code_units < 0) { - Usage("--inline-max-code-units passed a negative value %s", inline_max_code_units); - } - } else if (option == "--host") { - is_host_ = true; - } else if (option == "--runtime-arg") { - if (++i >= argc) { - Usage("Missing required argument for --runtime-arg"); - } - if (log_options) { - LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i]; - } - runtime_args_.push_back(argv[i]); - } else if (option == "--dump-timing") { - dump_timing_ = true; - } else if (option == "--dump-passes") { - dump_passes_ = true; - } else if (option.starts_with("--dump-cfg=")) { - dump_cfg_file_name_ = option.substr(strlen("--dump-cfg=")).data(); - } else if (option == "--dump-stats") { - dump_stats_ = true; - } 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("--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, &top_k_profile_threshold); - } else if (option == "--print-pass-names") { - pass_manager_options.SetPrintPassNames(true); - } else if (option.starts_with("--disable-passes=")) { - const std::string disable_passes = option.substr(strlen("--disable-passes=")).data(); - pass_manager_options.SetDisablePassList(disable_passes); - } else if (option.starts_with("--print-passes=")) { - const std::string print_passes = option.substr(strlen("--print-passes=")).data(); - pass_manager_options.SetPrintPassList(print_passes); - } else if (option == "--print-all-passes") { - pass_manager_options.SetPrintAllPasses(); - } else if (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); - } else if (option == "--print-pass-options") { - pass_manager_options.SetPrintPassOptions(true); - } else if (option.starts_with("--pass-options=")) { - const std::string options = option.substr(strlen("--pass-options=")).data(); - pass_manager_options.SetOverriddenPassOptions(options); - } else if (option == "--include-patch-information") { - include_patch_information = true; - } else if (option == "--no-include-patch-information") { - include_patch_information = false; - } 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=")) { - 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(); - } - } else if (option.starts_with("--swap-file=")) { - swap_file_name_ = option.substr(strlen("--swap-file=")).data(); - } else if (option.starts_with("--swap-fd=")) { - const char* swap_fd_str = option.substr(strlen("--swap-fd=")).data(); - if (!ParseInt(swap_fd_str, &swap_fd_)) { - Usage("Failed to parse --swap-fd argument '%s' as an integer", swap_fd_str); - } - if (swap_fd_ < 0) { - Usage("--swap-fd passed a negative value %d", swap_fd_); - } - } else if (option == "--abort-on-hard-verifier-error") { - abort_on_hard_verifier_error = true; - } else { - Usage("Unknown argument %s", option.data()); + void ParseZipFd(const StringPiece& option) { + ParseUintOption(option, "--zip-fd", &zip_fd_); + } + + void ParseOatFd(const StringPiece& option) { + ParseUintOption(option, "--oat-fd", &oat_fd_); + } + + void ParseJ(const StringPiece& option) { + ParseUintOption(option, "-j", &thread_count_, /* is_long_option */ false); + } + + void ParseBase(const StringPiece& option) { + DCHECK(option.starts_with("--base=")); + const char* image_base_str = option.substr(strlen("--base=")).data(); + char* end; + image_base_ = strtoul(image_base_str, &end, 16); + if (end == image_base_str || *end != '\0') { + Usage("Failed to parse hexadecimal value for option %s", option.data()); + } + } + + void ParseInstructionSet(const StringPiece& option) { + DCHECK(option.starts_with("--instruction-set=")); + StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data(); + // StringPiece is not necessarily zero-terminated, so need to make a copy and ensure it. + std::unique_ptr buf(new char[instruction_set_str.length() + 1]); + strncpy(buf.get(), instruction_set_str.data(), instruction_set_str.length()); + buf.get()[instruction_set_str.length()] = 0; + instruction_set_ = GetInstructionSetFromString(buf.get()); + // arm actually means thumb2. + if (instruction_set_ == InstructionSet::kArm) { + instruction_set_ = InstructionSet::kThumb2; + } + } + + void ParseInstructionSetVariant(const StringPiece& option, ParserOptions* parser_options) { + DCHECK(option.starts_with("--instruction-set-variant=")); + StringPiece str = option.substr(strlen("--instruction-set-variant=")).data(); + instruction_set_features_.reset( + InstructionSetFeatures::FromVariant( + instruction_set_, str.as_string(), &parser_options->error_msg)); + if (instruction_set_features_.get() == nullptr) { + Usage("%s", parser_options->error_msg.c_str()); + } + } + + void ParseInstructionSetFeatures(const StringPiece& option, ParserOptions* parser_options) { + DCHECK(option.starts_with("--instruction-set-features=")); + StringPiece str = option.substr(strlen("--instruction-set-features=")).data(); + if (instruction_set_features_.get() == nullptr) { + instruction_set_features_.reset( + InstructionSetFeatures::FromVariant( + instruction_set_, "default", &parser_options->error_msg)); + if (instruction_set_features_.get() == nullptr) { + Usage("Problem initializing default instruction set features variant: %s", + parser_options->error_msg.c_str()); } } + instruction_set_features_.reset( + instruction_set_features_->AddFeaturesFromString(str.as_string(), + &parser_options->error_msg)); + if (instruction_set_features_.get() == nullptr) { + Usage("Error parsing '%s': %s", option.data(), parser_options->error_msg.c_str()); + } + } + + void ParseCompilerBackend(const StringPiece& option, ParserOptions* parser_options) { + DCHECK(option.starts_with("--compiler-backend=")); + parser_options->requested_specific_compiler = true; + StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data(); + if (backend_str == "Quick") { + compiler_kind_ = Compiler::kQuick; + } else if (backend_str == "Optimizing") { + compiler_kind_ = Compiler::kOptimizing; + } else { + Usage("Unknown compiler backend: %s", backend_str.data()); + } + } + + 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_); + } + + void ProcessOptions(ParserOptions* parser_options) { image_ = (!image_filename_.empty()); - if (!requested_specific_compiler && !kUseOptimizingCompiler) { + if (!parser_options->requested_specific_compiler && !kUseOptimizingCompiler) { // If no specific compiler is requested, the current behavior is // to compile the boot image with Quick, and the rest with Optimizing. compiler_kind_ = image_ ? Compiler::kQuick : Compiler::kOptimizing; } - if (compiler_kind_ == Compiler::kOptimizing) { // Optimizing only supports PIC mode. - compile_pic = true; + parser_options->compile_pic = true; } if (oat_filename_.empty() && oat_fd_ == -1) { @@ -861,11 +761,11 @@ class Dex2Oat FINAL { Usage("--oat-file should not be used with --oat-fd"); } - if (!oat_symbols.empty() && oat_fd_ != -1) { + if (!parser_options->oat_symbols.empty() && oat_fd_ != -1) { Usage("--oat-symbols should not be used with --oat-fd"); } - if (!oat_symbols.empty() && is_host_) { + if (!parser_options->oat_symbols.empty() && is_host_) { Usage("--oat-symbols should not be used with --host"); } @@ -881,13 +781,13 @@ class Dex2Oat FINAL { android_root_ += android_root_env_var; } - if (!image_ && boot_image_filename.empty()) { - boot_image_filename += android_root_; - boot_image_filename += "/framework/boot.art"; + if (!image_ && parser_options->boot_image_filename.empty()) { + parser_options->boot_image_filename += android_root_; + parser_options->boot_image_filename += "/framework/boot.art"; } - if (!boot_image_filename.empty()) { + if (!parser_options->boot_image_filename.empty()) { boot_image_option_ += "-Ximage:"; - boot_image_option_ += boot_image_filename; + boot_image_option_ += parser_options->boot_image_filename; } if (image_classes_filename_ != nullptr && !image_) { @@ -945,8 +845,8 @@ class Dex2Oat FINAL { } oat_stripped_ = oat_filename_; - if (!oat_symbols.empty()) { - oat_unstripped_ = oat_symbols; + if (!parser_options->oat_symbols.empty()) { + oat_unstripped_ = parser_options->oat_symbols; } else { oat_unstripped_ = oat_filename_; } @@ -955,10 +855,11 @@ class Dex2Oat FINAL { // instruction set. if (instruction_set_features_.get() == nullptr) { instruction_set_features_.reset( - InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg)); + InstructionSetFeatures::FromVariant( + instruction_set_, "default", &parser_options->error_msg)); if (instruction_set_features_.get() == nullptr) { Usage("Problem initializing default instruction set features variant: %s", - error_msg.c_str()); + parser_options->error_msg.c_str()); } } @@ -973,52 +874,50 @@ class Dex2Oat FINAL { } } - if (compiler_filter_string == nullptr) { - compiler_filter_string = "speed"; - } - - CHECK(compiler_filter_string != nullptr); - CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter; - 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; + 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", compiler_filter_string); + 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 (inline_depth_limit == kUnsetInlineDepthLimit) { - inline_depth_limit = (compiler_filter == CompilerOptions::kSpace) + if (parser_options->inline_depth_limit == ParserOptions::kUnsetInlineDepthLimit) { + parser_options->inline_depth_limit = + (parser_options->compiler_filter == CompilerOptions::kSpace) // Implementation of the space filter: limit inlining depth. ? CompilerOptions::kSpaceFilterInlineDepthLimit : CompilerOptions::kDefaultInlineDepthLimit; } - if (inline_max_code_units == kUnsetInlineMaxCodeUnits) { - inline_max_code_units = (compiler_filter == CompilerOptions::kSpace) + if (parser_options->inline_max_code_units == ParserOptions::kUnsetInlineMaxCodeUnits) { + parser_options->inline_max_code_units = + (parser_options->compiler_filter == CompilerOptions::kSpace) // Implementation of the space filter: limit inlining max code units. ? CompilerOptions::kSpaceFilterInlineMaxCodeUnits : CompilerOptions::kDefaultInlineMaxCodeUnits; } // Checks are all explicit until we know the architecture. - bool implicit_null_checks = false; - bool implicit_so_checks = false; - bool implicit_suspend_checks = false; // Set the compilation target's implicit checks options. switch (instruction_set_) { case kArm: @@ -1028,8 +927,8 @@ class Dex2Oat FINAL { case kX86_64: case kMips: case kMips64: - implicit_null_checks = true; - implicit_so_checks = true; + parser_options->implicit_null_checks = true; + parser_options->implicit_so_checks = true; break; default: @@ -1037,55 +936,224 @@ class Dex2Oat FINAL { break; } - compiler_options_.reset(new CompilerOptions(compiler_filter, - huge_method_threshold, - large_method_threshold, - small_method_threshold, - tiny_method_threshold, - num_dex_methods_threshold, - inline_depth_limit, - inline_max_code_units, - include_patch_information, - top_k_profile_threshold, - debuggable, - generate_debug_info, - implicit_null_checks, - implicit_so_checks, - implicit_suspend_checks, - compile_pic, + 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(pass_manager_options), + new PassManagerOptions( + parser_options->pass_manager_options), init_failure_output_.get(), - abort_on_hard_verifier_error)); + parser_options->abort_on_hard_verifier_error)); // Done with usage checks, enable watchdog if requested - if (watch_dog_enabled) { + if (parser_options->watch_dog_enabled) { watchdog_.reset(new WatchDog(true)); } // Fill some values into the key-value store for the oat header. key_value_store_.reset(new SafeMap()); + } - // Insert some compiler things. - { - std::ostringstream oss; - for (int i = 0; i < argc; ++i) { - if (i > 0) { - oss << ' '; + void InsertCompileOptions(int argc, char** argv, ParserOptions* parser_options) { + std::ostringstream oss; + for (int i = 0; i < argc; ++i) { + if (i > 0) { + oss << ' '; + } + oss << argv[i]; + } + key_value_store_->Put(OatHeader::kDex2OatCmdLineKey, oss.str()); + oss.str(""); // Reset. + oss << kRuntimeISA; + key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str()); + key_value_store_->Put( + OatHeader::kPicKey, + parser_options->compile_pic ? OatHeader::kTrueValue : OatHeader::kFalseValue); + key_value_store_->Put( + OatHeader::kDebuggableKey, + parser_options->debuggable ? OatHeader::kTrueValue : OatHeader::kFalseValue); + } + + // Parse the arguments from the command line. In case of an unrecognized option or impossible + // values/combinations, a usage error will be displayed and exit() is called. Thus, if the method + // returns, arguments have been successfully parsed. + void ParseArgs(int argc, char** argv) { + original_argc = argc; + original_argv = argv; + + InitLogging(argv); + + // Skip over argv[0]. + argv++; + argc--; + + if (argc == 0) { + Usage("No arguments specified"); + } + + std::unique_ptr parser_options(new ParserOptions()); + + for (int i = 0; i < argc; i++) { + const StringPiece option(argv[i]); + const bool log_options = false; + if (log_options) { + LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i]; + } + if (option.starts_with("--dex-file=")) { + dex_filenames_.push_back(option.substr(strlen("--dex-file=")).data()); + } else if (option.starts_with("--dex-location=")) { + dex_locations_.push_back(option.substr(strlen("--dex-location=")).data()); + } else if (option.starts_with("--zip-fd=")) { + ParseZipFd(option); + } else if (option.starts_with("--zip-location=")) { + zip_location_ = option.substr(strlen("--zip-location=")).data(); + } else if (option.starts_with("--oat-file=")) { + oat_filename_ = option.substr(strlen("--oat-file=")).data(); + } else if (option.starts_with("--oat-symbols=")) { + parser_options->oat_symbols = option.substr(strlen("--oat-symbols=")).data(); + } else if (option.starts_with("--oat-fd=")) { + ParseOatFd(option); + } else if (option == "--watch-dog") { + parser_options->watch_dog_enabled = true; + } else if (option == "--no-watch-dog") { + parser_options->watch_dog_enabled = false; + } else if (option.starts_with("-j")) { + ParseJ(option); + } else if (option.starts_with("--oat-location=")) { + oat_location_ = option.substr(strlen("--oat-location=")).data(); + } else if (option.starts_with("--image=")) { + image_filename_ = option.substr(strlen("--image=")).data(); + } else if (option.starts_with("--image-classes=")) { + 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("--compiled-classes=")) { + compiled_classes_filename_ = option.substr(strlen("--compiled-classes=")).data(); + } else if (option.starts_with("--compiled-classes-zip=")) { + compiled_classes_zip_filename_ = option.substr(strlen("--compiled-classes-zip=")).data(); + } else if (option.starts_with("--compiled-methods=")) { + compiled_methods_filename_ = option.substr(strlen("--compiled-methods=")).data(); + } else if (option.starts_with("--compiled-methods-zip=")) { + compiled_methods_zip_filename_ = option.substr(strlen("--compiled-methods-zip=")).data(); + } else if (option.starts_with("--base=")) { + ParseBase(option); + } else if (option.starts_with("--boot-image=")) { + parser_options->boot_image_filename = option.substr(strlen("--boot-image=")).data(); + } else if (option.starts_with("--android-root=")) { + android_root_ = option.substr(strlen("--android-root=")).data(); + } else if (option.starts_with("--instruction-set=")) { + ParseInstructionSet(option); + } else if (option.starts_with("--instruction-set-variant=")) { + ParseInstructionSetVariant(option, parser_options.get()); + } else if (option.starts_with("--instruction-set-features=")) { + 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 == "--host") { + is_host_ = true; + } else if (option == "--runtime-arg") { + if (++i >= argc) { + Usage("Missing required argument for --runtime-arg"); + } + if (log_options) { + LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i]; } - oss << argv[i]; + runtime_args_.push_back(argv[i]); + } else if (option == "--dump-timing") { + dump_timing_ = true; + } else if (option == "--dump-passes") { + dump_passes_ = true; + } else if (option.starts_with("--dump-cfg=")) { + dump_cfg_file_name_ = option.substr(strlen("--dump-cfg=")).data(); + } 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("--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 { + Usage("Unknown argument %s", option.data()); } - key_value_store_->Put(OatHeader::kDex2OatCmdLineKey, oss.str()); - oss.str(""); // Reset. - oss << kRuntimeISA; - key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str()); - key_value_store_->Put(OatHeader::kPicKey, - compile_pic ? OatHeader::kTrueValue : OatHeader::kFalseValue); - key_value_store_->Put(OatHeader::kDebuggableKey, - debuggable ? OatHeader::kTrueValue : OatHeader::kFalseValue); } + + ProcessOptions(parser_options.get()); + + // Insert some compiler things. + InsertCompileOptions(argc, argv, parser_options.get()); } // Check whether the oat output file is writable, and open it for later. Also open a swap file, -- 2.11.0