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_;