Dex2oat support for multiple oat file and image file outputs.
Multiple changes to dex2oat and the runtime to support a --multi-image
option. This generates a separate oat file and image file output for
each dex file input.
Change-Id: Ie1d6f0b8afa8aed5790065b8c2eb177990c60129
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
index c6dbd24..84fb432 100644
--- a/compiler/driver/compiled_method_storage_test.cc
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -45,7 +45,8 @@
false,
nullptr,
-1,
- "");
+ "",
+ nullptr);
CompiledMethodStorage* storage = driver.GetCompiledMethodStorage();
ASSERT_TRUE(storage->DedupeEnabled()); // The default.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5630b08..afb4b71 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -334,19 +334,21 @@
DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);
};
-CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
- VerificationResults* verification_results,
- DexFileToMethodInlinerMap* method_inliner_map,
- Compiler::Kind compiler_kind,
- InstructionSet instruction_set,
- const InstructionSetFeatures* instruction_set_features,
- bool boot_image, std::unordered_set<std::string>* image_classes,
- std::unordered_set<std::string>* compiled_classes,
- std::unordered_set<std::string>* compiled_methods,
- size_t thread_count, bool dump_stats, bool dump_passes,
- const std::string& dump_cfg_file_name, bool dump_cfg_append,
- CumulativeLogger* timer, int swap_fd,
- const std::string& profile_file)
+CompilerDriver::CompilerDriver(
+ const CompilerOptions* compiler_options,
+ VerificationResults* verification_results,
+ DexFileToMethodInlinerMap* method_inliner_map,
+ Compiler::Kind compiler_kind,
+ InstructionSet instruction_set,
+ const InstructionSetFeatures* instruction_set_features,
+ bool boot_image, std::unordered_set<std::string>* image_classes,
+ std::unordered_set<std::string>* compiled_classes,
+ std::unordered_set<std::string>* compiled_methods,
+ size_t thread_count, bool dump_stats, bool dump_passes,
+ const std::string& dump_cfg_file_name, bool dump_cfg_append,
+ CumulativeLogger* timer, int swap_fd,
+ const std::string& profile_file,
+ const std::unordered_map<const DexFile*, const char*>* dex_to_oat_map)
: compiler_options_(compiler_options),
verification_results_(verification_results),
method_inliner_map_(method_inliner_map),
@@ -374,6 +376,7 @@
compiler_context_(nullptr),
support_boot_image_fixup_(instruction_set != kMips && instruction_set != kMips64),
dex_files_for_oat_file_(nullptr),
+ dex_file_oat_filename_map_(dex_to_oat_map),
compiled_method_storage_(swap_fd) {
DCHECK(compiler_options_ != nullptr);
DCHECK(verification_results_ != nullptr);
@@ -1538,6 +1541,12 @@
use_dex_cache = true;
}
}
+ if (!use_dex_cache && IsBootImage()) {
+ if (!AreInSameOatFile(&(const_cast<mirror::Class*>(referrer_class)->GetDexFile()),
+ &declaring_class->GetDexFile())) {
+ use_dex_cache = true;
+ }
+ }
// The method is defined not within this dex file. We need a dex cache slot within the current
// dex file or direct pointers.
bool must_use_direct_pointers = false;
@@ -1571,12 +1580,14 @@
*type = sharp_type;
}
} else {
- auto* image_space = heap->GetBootImageSpace();
bool method_in_image = false;
- if (image_space != nullptr) {
+ const std::vector<gc::space::ImageSpace*> image_spaces = heap->GetBootImageSpaces();
+ for (gc::space::ImageSpace* image_space : image_spaces) {
const auto& method_section = image_space->GetImageHeader().GetMethodsSection();
- method_in_image = method_section.Contains(
- reinterpret_cast<uint8_t*>(method) - image_space->Begin());
+ if (method_section.Contains(reinterpret_cast<uint8_t*>(method) - image_space->Begin())) {
+ method_in_image = true;
+ break;
+ }
}
if (method_in_image || compiling_boot || runtime->UseJit()) {
// We know we must be able to get to the method in the image, so use that pointer.
@@ -2572,4 +2583,15 @@
return inliner->IsStringInitMethodIndex(method_index);
}
+bool CompilerDriver::MayInlineInternal(const DexFile* inlined_from,
+ const DexFile* inlined_into) const {
+ // We're not allowed to inline across dex files if we're the no-inline-from dex file.
+ if (inlined_from != inlined_into &&
+ compiler_options_->GetNoInlineFromDexFile() == inlined_from) {
+ return false;
+ }
+
+ return true;
+}
+
} // namespace art
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index f0360ce..fa0cb9a 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -97,7 +97,8 @@
size_t thread_count, bool dump_stats, bool dump_passes,
const std::string& dump_cfg_file_name, bool dump_cfg_append,
CumulativeLogger* timer, int swap_fd,
- const std::string& profile_file);
+ const std::string& profile_file,
+ const std::unordered_map<const DexFile*, const char*>* dex_to_oat_map);
~CompilerDriver();
@@ -113,6 +114,18 @@
: ArrayRef<const DexFile* const>();
}
+ // Are the given dex files compiled into the same oat file? Should only be called after
+ // GetDexFilesForOatFile, as the conservative answer (when we don't have a map) is true.
+ bool AreInSameOatFile(const DexFile* d1, const DexFile* d2) {
+ if (dex_file_oat_filename_map_ == nullptr) {
+ // TODO: Check for this wrt/ apps and boot image calls.
+ return true;
+ }
+ auto it1 = dex_file_oat_filename_map_->find(d1);
+ auto it2 = dex_file_oat_filename_map_->find(d2);
+ return it1 == it2;
+ }
+
void CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings)
@@ -471,6 +484,13 @@
bool CanAssumeClassIsLoaded(mirror::Class* klass)
SHARED_REQUIRES(Locks::mutator_lock_);
+ bool MayInline(const DexFile* inlined_from, const DexFile* inlined_into) const {
+ if (!kIsTargetBuild) {
+ return MayInlineInternal(inlined_from, inlined_into);
+ }
+ return true;
+ }
+
private:
// Return whether the declaring class of `resolved_member` is
// available to `referrer_class` for read or write access using two
@@ -587,6 +607,8 @@
ThreadPool* thread_pool, TimingLogger* timings)
REQUIRES(!Locks::mutator_lock_);
+ bool MayInlineInternal(const DexFile* inlined_from, const DexFile* inlined_into) const;
+
const CompilerOptions* const compiler_options_;
VerificationResults* const verification_results_;
DexFileToMethodInlinerMap* const method_inliner_map_;
@@ -621,9 +643,8 @@
const bool boot_image_;
- // If image_ is true, specifies the classes that will be included in
- // the image. Note if image_classes_ is null, all classes are
- // included in the image.
+ // If image_ is true, specifies the classes that will be included in the image.
+ // Note if image_classes_ is null, all classes are included in the image.
std::unique_ptr<std::unordered_set<std::string>> image_classes_;
// Specifies the classes that will be compiled. Note that if classes_to_compile_ is null,
@@ -663,6 +684,9 @@
// List of dex files that will be stored in the oat file.
const std::vector<const DexFile*>* dex_files_for_oat_file_;
+ // Map from dex files to the oat file (name) they will be compiled into.
+ const std::unordered_map<const DexFile*, const char*>* dex_file_oat_filename_map_;
+
CompiledMethodStorage compiled_method_storage_;
friend class CompileClassVisitor;
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 8c38cf2..209bb5a 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -31,6 +31,7 @@
num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
inline_depth_limit_(kUnsetInlineDepthLimit),
inline_max_code_units_(kUnsetInlineMaxCodeUnits),
+ no_inline_from_(nullptr),
include_patch_information_(kDefaultIncludePatchInformation),
top_k_profile_threshold_(kDefaultTopKProfileThreshold),
debuggable_(false),
@@ -59,6 +60,7 @@
size_t num_dex_methods_threshold,
size_t inline_depth_limit,
size_t inline_max_code_units,
+ const DexFile* no_inline_from,
bool include_patch_information,
double top_k_profile_threshold,
bool debuggable,
@@ -79,6 +81,7 @@
num_dex_methods_threshold_(num_dex_methods_threshold),
inline_depth_limit_(inline_depth_limit),
inline_max_code_units_(inline_max_code_units),
+ no_inline_from_(no_inline_from),
include_patch_information_(include_patch_information),
top_k_profile_threshold_(top_k_profile_threshold),
debuggable_(debuggable),
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 2b047a2..9ad1bee 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -72,6 +72,7 @@
size_t num_dex_methods_threshold,
size_t inline_depth_limit,
size_t inline_max_code_units,
+ const DexFile* no_inline_from,
bool include_patch_information,
double top_k_profile_threshold,
bool debuggable,
@@ -217,6 +218,10 @@
return abort_on_hard_verifier_failure_;
}
+ const DexFile* GetNoInlineFromDexFile() const {
+ return no_inline_from_;
+ }
+
bool ParseCompilerOption(const StringPiece& option, UsageFn Usage);
private:
@@ -241,6 +246,10 @@
size_t num_dex_methods_threshold_;
size_t inline_depth_limit_;
size_t inline_max_code_units_;
+
+ // A dex file from which we should not inline code.
+ const DexFile* no_inline_from_;
+
bool include_patch_information_;
// When using a profile file only the top K% of the profiled samples will be compiled.
double top_k_profile_threshold_;