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
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 976c002..4b66ad8 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -539,26 +539,11 @@
     }
   }
 
-  // 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 @@
     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;
+  };
 
-    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<char[]> 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());
+  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();
+    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;
+  }
+
+  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<char[]> 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 @@
       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 @@
       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 @@
     }
 
     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 @@
     // 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 @@
       }
     }
 
-    if (compiler_filter_string == nullptr) {
-      compiler_filter_string = "speed";
+    if (parser_options->compiler_filter_string == nullptr) {
+      parser_options->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;
+    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 @@
       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 @@
         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<std::string, std::string>());
+  }
+
+  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<ParserOptions> 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];
+        }
+        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());
+      }
+    }
+
+    ProcessOptions(parser_options.get());
 
     // Insert some compiler things.
-    {
-      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,
-                            compile_pic ? OatHeader::kTrueValue : OatHeader::kFalseValue);
-      key_value_store_->Put(OatHeader::kDebuggableKey,
-                            debuggable ? OatHeader::kTrueValue : OatHeader::kFalseValue);
-    }
+    InsertCompileOptions(argc, argv, parser_options.get());
   }
 
   // Check whether the oat output file is writable, and open it for later. Also open a swap file,