in dex2oat/dex2oat.cc [679:903]
void ProcessOptions(ParserOptions* parser_options) {
boot_image_ = !image_filenames_.empty();
app_image_ = app_image_fd_ != -1 || !app_image_file_name_.empty();
if (IsAppImage() && IsBootImage()) {
Usage("Can't have both --image and (--app-image-fd or --app-image-file)");
}
if (IsBootImage()) {
// We need the boot image to always be debuggable.
// TODO: Remove this once we better deal with full frame deoptimization.
compiler_options_->debuggable_ = true;
}
if (oat_filenames_.empty() && oat_fd_ == -1) {
Usage("Output must be supplied with either --oat-file or --oat-fd");
}
if (!oat_filenames_.empty() && oat_fd_ != -1) {
Usage("--oat-file should not be used with --oat-fd");
}
if (!parser_options->oat_symbols.empty() && oat_fd_ != -1) {
Usage("--oat-symbols should not be used with --oat-fd");
}
if (!parser_options->oat_symbols.empty() && is_host_) {
Usage("--oat-symbols should not be used with --host");
}
if (oat_fd_ != -1 && !image_filenames_.empty()) {
Usage("--oat-fd should not be used with --image");
}
if (!parser_options->oat_symbols.empty() &&
parser_options->oat_symbols.size() != oat_filenames_.size()) {
Usage("--oat-file arguments do not match --oat-symbols arguments");
}
if (!image_filenames_.empty() && image_filenames_.size() != oat_filenames_.size()) {
Usage("--oat-file arguments do not match --image arguments");
}
if (android_root_.empty()) {
const char* android_root_env_var = getenv("ANDROID_ROOT");
if (android_root_env_var == nullptr) {
Usage("--android-root unspecified and ANDROID_ROOT not set");
}
android_root_ += android_root_env_var;
}
if (!boot_image_ && parser_options->boot_image_filename.empty()) {
parser_options->boot_image_filename += android_root_;
parser_options->boot_image_filename += "/framework/boot.art";
}
if (!parser_options->boot_image_filename.empty()) {
boot_image_filename_ = parser_options->boot_image_filename;
}
if (image_classes_filename_ != nullptr && !IsBootImage()) {
Usage("--image-classes should only be used with --image");
}
if (image_classes_filename_ != nullptr && !boot_image_filename_.empty()) {
Usage("--image-classes should not be used with --boot-image");
}
if (image_classes_zip_filename_ != nullptr && image_classes_filename_ == nullptr) {
Usage("--image-classes-zip should be used with --image-classes");
}
if (compiled_classes_filename_ != nullptr && !IsBootImage()) {
Usage("--compiled-classes should only be used with --image");
}
if (compiled_classes_filename_ != nullptr && !boot_image_filename_.empty()) {
Usage("--compiled-classes should not be used with --boot-image");
}
if (compiled_classes_zip_filename_ != nullptr && compiled_classes_filename_ == nullptr) {
Usage("--compiled-classes-zip should be used with --compiled-classes");
}
if (dex_filenames_.empty() && zip_fd_ == -1) {
Usage("Input must be supplied with either --dex-file or --zip-fd");
}
if (!dex_filenames_.empty() && zip_fd_ != -1) {
Usage("--dex-file should not be used with --zip-fd");
}
if (!dex_filenames_.empty() && !zip_location_.empty()) {
Usage("--dex-file should not be used with --zip-location");
}
if (dex_locations_.empty()) {
for (const char* dex_file_name : dex_filenames_) {
dex_locations_.push_back(dex_file_name);
}
} else if (dex_locations_.size() != dex_filenames_.size()) {
Usage("--dex-location arguments do not match --dex-file arguments");
}
if (!dex_filenames_.empty() && !oat_filenames_.empty()) {
if (oat_filenames_.size() != 1 && oat_filenames_.size() != dex_filenames_.size()) {
Usage("--oat-file arguments must be singular or match --dex-file arguments");
}
}
if (zip_fd_ != -1 && zip_location_.empty()) {
Usage("--zip-location should be supplied with --zip-fd");
}
if (boot_image_filename_.empty()) {
if (image_base_ == 0) {
Usage("Non-zero --base not specified");
}
}
const bool have_profile_file = !profile_file_.empty();
const bool have_profile_fd = profile_file_fd_ != kInvalidFd;
if (have_profile_file && have_profile_fd) {
Usage("Profile file should not be specified with both --profile-file-fd and --profile-file");
}
if (!parser_options->oat_symbols.empty()) {
oat_unstripped_ = std::move(parser_options->oat_symbols);
}
// If no instruction set feature was given, use the default one for the target
// instruction set.
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());
}
}
if (instruction_set_ == kRuntimeISA) {
std::unique_ptr<const InstructionSetFeatures> runtime_features(
InstructionSetFeatures::FromCppDefines());
if (!instruction_set_features_->Equals(runtime_features.get())) {
LOG(WARNING) << "Mismatch between dex2oat instruction set features ("
<< *instruction_set_features_ << ") and those of dex2oat executable ("
<< *runtime_features <<") for the command line:\n"
<< CommandLine();
}
}
// 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 (compiler_options_->inline_depth_limit_ == CompilerOptions::kUnsetInlineDepthLimit) {
compiler_options_->inline_depth_limit_ =
(compiler_options_->compiler_filter_ == CompilerFilter::kSpace)
// Implementation of the space filter: limit inlining depth.
? CompilerOptions::kSpaceFilterInlineDepthLimit
: CompilerOptions::kDefaultInlineDepthLimit;
}
if (compiler_options_->inline_max_code_units_ == CompilerOptions::kUnsetInlineMaxCodeUnits) {
compiler_options_->inline_max_code_units_ =
(compiler_options_->compiler_filter_ == CompilerFilter::kSpace)
// Implementation of the space filter: limit inlining max code units.
? CompilerOptions::kSpaceFilterInlineMaxCodeUnits
: CompilerOptions::kDefaultInlineMaxCodeUnits;
}
// Checks are all explicit until we know the architecture.
// Set the compilation target's implicit checks options.
switch (instruction_set_) {
case kArm:
case kThumb2:
case kArm64:
case kX86:
case kX86_64:
case kMips:
case kMips64:
compiler_options_->implicit_null_checks_ = true;
compiler_options_->implicit_so_checks_ = true;
break;
default:
// Defaults are correct.
break;
}
compiler_options_->verbose_methods_ = verbose_methods_.empty() ? nullptr : &verbose_methods_;
if (!IsBootImage() && multi_image_) {
Usage("--multi-image can only be used when creating boot images");
}
if (IsBootImage() && multi_image_ && image_filenames_.size() > 1) {
Usage("--multi-image cannot be used with multiple image names");
}
// For now, if we're on the host and compile the boot image, *always* use multiple image files.
if (!kIsTargetBuild && IsBootImage()) {
if (image_filenames_.size() == 1) {
multi_image_ = true;
}
}
// Done with usage checks, enable watchdog if requested
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>());
// Automatically force determinism for the boot image in a host build if the default GC is CMS
// or MS and read barriers are not enabled, as the former switches the GC to a non-concurrent
// one by passing the option `-Xgc:nonconcurrent` (see below).
if (!kIsTargetBuild && IsBootImage()) {
if (SupportsDeterministicCompilation()) {
force_determinism_ = true;
} else {
LOG(WARNING) << "Deterministic compilation is disabled.";
}
}
compiler_options_->force_determinism_ = force_determinism_;
}