Delay dex-to-dex compilation until Optimizing is done.

This fixes a race between inlining in the Optimizing
backend and dex-to-dex quickening where the Optimizing can
read the non-quickened opcode and then the quickened field
index or vtable index and look up the wrong field or method.
Even if we such tearing of the dex instruction does not
happen, the possible reordering of dex-to-dex and Optimizing
compilation makes the final oat file non-deterministic.

Also, remove VerificationResults::RemoveVerifiedMethod() as
we have only the Optimizing backend now and as such it was
dead code and would have interfered with this change.

Bug: 29043547
Bug: 29089975
Change-Id: I8389927d35dcacaf2f99c2153f055857036c8129
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 03c94a4..d87762d 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -80,15 +80,6 @@
   return (it != verified_methods_.end()) ? it->second : nullptr;
 }
 
-void VerificationResults::RemoveVerifiedMethod(MethodReference ref) {
-  WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
-  auto it = verified_methods_.find(ref);
-  if (it != verified_methods_.end()) {
-    delete it->second;
-    verified_methods_.erase(it);
-  }
-}
-
 void VerificationResults::AddRejectedClass(ClassReference ref) {
   {
     WriterMutexLock mu(Thread::Current(), rejected_classes_lock_);
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index da80bf0..1af11a8 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -48,7 +48,6 @@
 
     const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
         REQUIRES(!verified_methods_lock_);
-    void RemoveVerifiedMethod(MethodReference ref) REQUIRES(!verified_methods_lock_);
 
     void AddRejectedClass(ClassReference ref) REQUIRES(!rejected_classes_lock_);
     bool IsClassRejected(ClassReference ref) REQUIRES(!rejected_classes_lock_);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index d20f510..7708b97 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -26,6 +26,7 @@
 
 #include "art_field-inl.h"
 #include "art_method-inl.h"
+#include "base/bit_vector.h"
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/time_utils.h"
@@ -66,6 +67,7 @@
 #include "thread_pool.h"
 #include "trampolines/trampoline_compiler.h"
 #include "transaction.h"
+#include "utils/array_ref.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
 #include "utils/swap_space.h"
 #include "verifier/method_verifier.h"
@@ -333,6 +335,24 @@
   DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);
 };
 
+class CompilerDriver::DexFileMethodSet {
+ public:
+  explicit DexFileMethodSet(const DexFile& dex_file)
+    : dex_file_(dex_file),
+      method_indexes_(dex_file.NumMethodIds(), false, Allocator::GetMallocAllocator()) {
+  }
+  DexFileMethodSet(DexFileMethodSet&& other) = default;
+
+  const DexFile& GetDexFile() const { return dex_file_; }
+
+  BitVector& GetMethodIndexes() { return method_indexes_; }
+  const BitVector& GetMethodIndexes() const { return method_indexes_; }
+
+ private:
+  const DexFile& dex_file_;
+  BitVector method_indexes_;
+};
+
 CompilerDriver::CompilerDriver(
     const CompilerOptions* compiler_options,
     VerificationResults* verification_results,
@@ -379,7 +399,10 @@
       dex_files_for_oat_file_(nullptr),
       compiled_method_storage_(swap_fd),
       profile_compilation_info_(profile_compilation_info),
-      max_arena_alloc_(0) {
+      max_arena_alloc_(0),
+      dex_to_dex_references_lock_("dex-to-dex references lock"),
+      dex_to_dex_references_(),
+      current_dex_to_dex_methods_(nullptr) {
   DCHECK(compiler_options_ != nullptr);
   DCHECK(method_inliner_map_ != nullptr);
 
@@ -552,7 +575,29 @@
   uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
   MethodReference method_ref(&dex_file, method_idx);
 
-  if ((access_flags & kAccNative) != 0) {
+  if (driver->GetCurrentDexToDexMethods() != nullptr) {
+    // This is the second pass when we dex-to-dex compile previously marked methods.
+    // TODO: Refactor the compilation to avoid having to distinguish the two passes
+    // here. That should be done on a higher level. http://b/29089975
+    if (driver->GetCurrentDexToDexMethods()->IsBitSet(method_idx)) {
+      const VerifiedMethod* verified_method =
+          driver->GetVerificationResults()->GetVerifiedMethod(method_ref);
+      // Do not optimize if a VerifiedMethod is missing. SafeCast elision,
+      // for example, relies on it.
+      compiled_method = optimizer::ArtCompileDEX(
+          driver,
+          code_item,
+          access_flags,
+          invoke_type,
+          class_def_idx,
+          method_idx,
+          class_loader,
+          dex_file,
+          (verified_method != nullptr)
+              ? dex_to_dex_compilation_level
+              : optimizer::DexToDexCompilationLevel::kRequired);
+    }
+  } else if ((access_flags & kAccNative) != 0) {
     // Are we extracting only and have support for generic JNI down calls?
     if (!driver->GetCompilerOptions().IsJniCompilationEnabled() &&
         InstructionSetHasGenericJniStub(driver->GetInstructionSet())) {
@@ -588,21 +633,9 @@
     }
     if (compiled_method == nullptr &&
         dex_to_dex_compilation_level != optimizer::DexToDexCompilationLevel::kDontDexToDexCompile) {
+      DCHECK(!Runtime::Current()->UseJitCompilation());
       // TODO: add a command-line option to disable DEX-to-DEX compilation ?
-      // Do not optimize if a VerifiedMethod is missing. SafeCast elision, for example, relies on
-      // it.
-      compiled_method = optimizer::ArtCompileDEX(
-          driver,
-          code_item,
-          access_flags,
-          invoke_type,
-          class_def_idx,
-          method_idx,
-          class_loader,
-          dex_file,
-          (verified_method != nullptr)
-              ? dex_to_dex_compilation_level
-              : optimizer::DexToDexCompilationLevel::kRequired);
+      driver->MarkForDexToDexCompilation(self, method_ref);
     }
   }
   if (kTimeCompileMethod) {
@@ -628,12 +661,6 @@
     driver->AddCompiledMethod(method_ref, compiled_method, non_relative_linker_patch_count);
   }
 
-  // Done compiling, delete the verified method to reduce native memory usage. Do not delete in
-  // optimizing compiler, which may need the verified method again for inlining.
-  if (driver->GetCompilerKind() != Compiler::kOptimizing) {
-    driver->GetVerificationResults()->RemoveVerifiedMethod(method_ref);
-  }
-
   if (self->IsExceptionPending()) {
     ScopedObjectAccess soa(self);
     LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n"
@@ -680,6 +707,7 @@
                                   *dex_file,
                                   dex_file->GetClassDef(class_def_idx));
 
+  DCHECK(current_dex_to_dex_methods_ == nullptr);
   CompileMethod(self,
                 this,
                 code_item,
@@ -693,6 +721,34 @@
                 true,
                 dex_cache);
 
+  ArrayRef<DexFileMethodSet> dex_to_dex_references;
+  {
+    // From this point on, we shall not modify dex_to_dex_references_, so
+    // just grab a reference to it that we use without holding the mutex.
+    MutexLock lock(Thread::Current(), dex_to_dex_references_lock_);
+    dex_to_dex_references = ArrayRef<DexFileMethodSet>(dex_to_dex_references_);
+  }
+  if (!dex_to_dex_references.empty()) {
+    DCHECK_EQ(dex_to_dex_references.size(), 1u);
+    DCHECK(&dex_to_dex_references[0].GetDexFile() == dex_file);
+    current_dex_to_dex_methods_ = &dex_to_dex_references.front().GetMethodIndexes();
+    DCHECK(current_dex_to_dex_methods_->IsBitSet(method_idx));
+    DCHECK_EQ(current_dex_to_dex_methods_->NumSetBits(), 1u);
+    CompileMethod(self,
+                  this,
+                  code_item,
+                  access_flags,
+                  invoke_type,
+                  class_def_idx,
+                  method_idx,
+                  jclass_loader,
+                  *dex_file,
+                  dex_to_dex_compilation_level,
+                  true,
+                  dex_cache);
+    current_dex_to_dex_methods_ = nullptr;
+  }
+
   FreeThreadPools();
 
   self->GetJniEnv()->DeleteGlobalRef(jclass_loader);
@@ -1285,6 +1341,17 @@
   return IsImageClass(descriptor);
 }
 
+void CompilerDriver::MarkForDexToDexCompilation(Thread* self, const MethodReference& method_ref) {
+  MutexLock lock(self, dex_to_dex_references_lock_);
+  // Since we're compiling one dex file at a time, we need to look for the
+  // current dex file entry only at the end of dex_to_dex_references_.
+  if (dex_to_dex_references_.empty() ||
+      &dex_to_dex_references_.back().GetDexFile() != method_ref.dex_file) {
+    dex_to_dex_references_.emplace_back(*method_ref.dex_file);
+  }
+  dex_to_dex_references_.back().GetMethodIndexes().SetBit(method_ref.dex_method_index);
+}
+
 bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(Handle<mirror::DexCache> dex_cache,
                                                       uint32_t type_idx) {
   bool result = false;
@@ -2496,8 +2563,9 @@
             ? "null"
             : profile_compilation_info_->DumpInfo(&dex_files));
   }
-  for (size_t i = 0; i != dex_files.size(); ++i) {
-    const DexFile* dex_file = dex_files[i];
+
+  DCHECK(current_dex_to_dex_methods_ == nullptr);
+  for (const DexFile* dex_file : dex_files) {
     CHECK(dex_file != nullptr);
     CompileDexFile(class_loader,
                    *dex_file,
@@ -2510,6 +2578,25 @@
     max_arena_alloc_ = std::max(arena_alloc, max_arena_alloc_);
     Runtime::Current()->ReclaimArenaPoolMemory();
   }
+
+  ArrayRef<DexFileMethodSet> dex_to_dex_references;
+  {
+    // From this point on, we shall not modify dex_to_dex_references_, so
+    // just grab a reference to it that we use without holding the mutex.
+    MutexLock lock(Thread::Current(), dex_to_dex_references_lock_);
+    dex_to_dex_references = ArrayRef<DexFileMethodSet>(dex_to_dex_references_);
+  }
+  for (const auto& method_set : dex_to_dex_references) {
+    current_dex_to_dex_methods_ = &method_set.GetMethodIndexes();
+    CompileDexFile(class_loader,
+                   method_set.GetDexFile(),
+                   dex_files,
+                   parallel_thread_pool_.get(),
+                   parallel_thread_count_,
+                   timings);
+  }
+  current_dex_to_dex_methods_ = nullptr;
+
   VLOG(compiler) << "Compile: " << GetMemoryUsageString(false);
 }
 
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 19a1ecc..2dd4651 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -52,6 +52,7 @@
 class MethodVerifier;
 }  // namespace verifier
 
+class BitVector;
 class CompiledClass;
 class CompiledMethod;
 class CompilerOptions;
@@ -120,12 +121,12 @@
   void CompileAll(jobject class_loader,
                   const std::vector<const DexFile*>& dex_files,
                   TimingLogger* timings)
-      REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_);
+      REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_, !dex_to_dex_references_lock_);
 
   // Compile a single Method.
   void CompileOne(Thread* self, ArtMethod* method, TimingLogger* timings)
       SHARED_REQUIRES(Locks::mutator_lock_)
-      REQUIRES(!compiled_methods_lock_, !compiled_classes_lock_);
+      REQUIRES(!compiled_methods_lock_, !compiled_classes_lock_, !dex_to_dex_references_lock_);
 
   VerificationResults* GetVerificationResults() const {
     DCHECK(Runtime::Current()->IsAotCompiler());
@@ -475,6 +476,13 @@
     return true;
   }
 
+  void MarkForDexToDexCompilation(Thread* self, const MethodReference& method_ref)
+      REQUIRES(!dex_to_dex_references_lock_);
+
+  const BitVector* GetCurrentDexToDexMethods() const {
+    return current_dex_to_dex_methods_;
+  }
+
  private:
   // Return whether the declaring class of `resolved_member` is
   // available to `referrer_class` for read or write access using two
@@ -601,7 +609,7 @@
 
   void Compile(jobject class_loader,
                const std::vector<const DexFile*>& dex_files,
-               TimingLogger* timings);
+               TimingLogger* timings) REQUIRES(!dex_to_dex_references_lock_);
   void CompileDexFile(jobject class_loader,
                       const DexFile& dex_file,
                       const std::vector<const DexFile*>& dex_files,
@@ -702,6 +710,16 @@
   const ProfileCompilationInfo* const profile_compilation_info_;
 
   size_t max_arena_alloc_;
+
+  // Data for delaying dex-to-dex compilation.
+  Mutex dex_to_dex_references_lock_;
+  // In the first phase, dex_to_dex_references_ collects methods for dex-to-dex compilation.
+  class DexFileMethodSet;
+  std::vector<DexFileMethodSet> dex_to_dex_references_ GUARDED_BY(dex_to_dex_references_lock_);
+  // In the second phase, current_dex_to_dex_methods_ points to the BitVector with method
+  // indexes for dex-to-dex compilation in the current dex file.
+  const BitVector* current_dex_to_dex_methods_;
+
   friend class CompileClassVisitor;
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
diff --git a/runtime/base/bit_vector.h b/runtime/base/bit_vector.h
index 424ebb7..5609067 100644
--- a/runtime/base/bit_vector.h
+++ b/runtime/base/bit_vector.h
@@ -111,6 +111,20 @@
     const BitVector* const bit_vector_;
   };
 
+  // MoveConstructible but not MoveAssignable, CopyConstructible or CopyAssignable.
+
+  BitVector(const BitVector& other) = delete;
+  BitVector& operator=(const BitVector& other) = delete;
+
+  BitVector(BitVector&& other)
+      : storage_(other.storage_),
+        storage_size_(other.storage_size_),
+        allocator_(other.allocator_),
+        expandable_(other.expandable_) {
+    other.storage_ = nullptr;
+    other.storage_size_ = 0u;
+  }
+
   BitVector(uint32_t start_bits,
             bool expandable,
             Allocator* allocator);