merge in nyc-release history after reset to nyc-dev
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 4594e2c..e366e07 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/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 37197af..0e0a30b 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -321,6 +321,7 @@
                             jobject class_loader,
                             const DexFile& dex_file,
                             Handle<mirror::DexCache> dex_cache,
+                            ArtMethod* method,
                             bool osr) const;
 
   std::unique_ptr<OptimizingCompilerStats> compilation_stats_;
@@ -614,6 +615,7 @@
                                               jobject class_loader,
                                               const DexFile& dex_file,
                                               Handle<mirror::DexCache> dex_cache,
+                                              ArtMethod* method,
                                               bool osr) const {
   MaybeRecordStat(MethodCompilationStat::kAttemptCompilation);
   CompilerDriver* compiler_driver = GetCompilerDriver();
@@ -679,18 +681,21 @@
       osr);
 
   const uint8_t* interpreter_metadata = nullptr;
-  {
+  if (method == nullptr) {
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<1> hs(soa.Self());
     Handle<mirror::ClassLoader> loader(hs.NewHandle(
         soa.Decode<mirror::ClassLoader*>(class_loader)));
-    ArtMethod* art_method = compiler_driver->ResolveMethod(
+    method = compiler_driver->ResolveMethod(
         soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type);
-    // We may not get a method, for example if its class is erroneous.
-    if (art_method != nullptr) {
-      graph->SetArtMethod(art_method);
-      interpreter_metadata = art_method->GetQuickenedInfo();
-    }
+  }
+  // For AOT compilation, we may not get a method, for example if its class is erroneous.
+  // JIT should always have a method.
+  DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr);
+  if (method != nullptr) {
+    graph->SetArtMethod(method);
+    ScopedObjectAccess soa(Thread::Current());
+    interpreter_metadata = method->GetQuickenedInfo();
   }
 
   std::unique_ptr<CodeGenerator> codegen(
@@ -798,6 +803,7 @@
                    jclass_loader,
                    dex_file,
                    dex_cache,
+                   nullptr,
                    /* osr */ false));
     if (codegen.get() != nullptr) {
       MaybeRecordStat(MethodCompilationStat::kCompiled);
@@ -884,6 +890,7 @@
                    jclass_loader,
                    *dex_file,
                    dex_cache,
+                   method,
                    osr));
     if (codegen.get() == nullptr) {
       return false;
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index f2394f6..15f4928 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -809,7 +809,11 @@
   // Make sure that we don't go over the bounded type.
   ReferenceTypeInfo upper_bound_rti = instr->GetUpperBound();
   if (!upper_bound_rti.IsSupertypeOf(new_rti)) {
-    new_rti = upper_bound_rti;
+    // Note that the input might be exact, in which case we know the branch leading
+    // to the bound type is dead. We play it safe by not marking the bound type as
+    // exact.
+    bool is_exact = upper_bound_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes();
+    new_rti = ReferenceTypeInfo::Create(upper_bound_rti.GetTypeHandle(), is_exact);
   }
   instr->SetReferenceTypeInfo(new_rti);
 }
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 1790df6..f86cb13 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -79,10 +79,10 @@
 
 InvokeType ArtMethod::GetInvokeType() {
   // TODO: kSuper?
-  if (GetDeclaringClass()->IsInterface()) {
-    return kInterface;
-  } else if (IsStatic()) {
+  if (IsStatic()) {
     return kStatic;
+  } else if (GetDeclaringClass()->IsInterface()) {
+    return kInterface;
   } else if (IsDirect()) {
     return kDirect;
   } else {
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);
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 9822f6e..794ea27 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -74,19 +74,6 @@
       total_number_of_hot_spikes_(0),
       total_number_of_wake_ups_(0) {
   AddTrackedLocations(output_filename, app_data_dir, code_paths);
-  if (!app_data_dir.empty()) {
-    // The application directory is used to determine which dex files are owned by app.
-    // Since it could be a symlink (e.g. /data/data instead of /data/user/0), and we
-    // don't have control over how the dex files are actually loaded (symlink or canonical path),
-    // store it's canonical form to be sure we use the same base when comparing.
-    UniqueCPtr<const char[]> app_data_dir_real_path(realpath(app_data_dir.c_str(), nullptr));
-    if (app_data_dir_real_path != nullptr) {
-      app_data_dirs_.emplace(app_data_dir_real_path.get());
-    } else {
-      LOG(WARNING) << "Failed to get the real path for app dir: " << app_data_dir
-          << ". The app dir will not be used to determine which dex files belong to the app";
-    }
-  }
 }
 
 void ProfileSaver::Run() {
@@ -503,12 +490,18 @@
   if (it == tracked_dex_base_locations_.end()) {
     tracked_dex_base_locations_.Put(output_filename,
                                     std::set<std::string>(code_paths.begin(), code_paths.end()));
-    app_data_dirs_.insert(app_data_dir);
+    if (!app_data_dir.empty()) {
+      app_data_dirs_.insert(app_data_dir);
+    }
   } else {
     it->second.insert(code_paths.begin(), code_paths.end());
   }
 }
 
+// TODO(calin): This may lead to several calls to realpath.
+// Consider moving the logic to the saver thread (i.e. when notified,
+// only cache the location, and then wake up the saver thread to do the
+// comparisons with the real file paths and to create the markers).
 void ProfileSaver::NotifyDexUse(const std::string& dex_location) {
   if (!ShouldProfileLocation(dex_location)) {
     return;
@@ -541,63 +534,32 @@
   }
 }
 
-bool ProfileSaver::MaybeRecordDexUseInternal(
-      const std::string& dex_location,
-      const std::set<std::string>& app_code_paths,
-      const std::string& foreign_dex_profile_path,
-      const std::set<std::string>& app_data_dirs) {
-  if (dex_location.empty()) {
-    LOG(WARNING) << "Asked to record foreign dex use with an empty dex location.";
-    return false;
-  }
-  if (foreign_dex_profile_path.empty()) {
-    LOG(WARNING) << "Asked to record foreign dex use without a valid profile path ";
-    return false;
-  }
-
-  UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr));
-  if (dex_location_real_path == nullptr) {
-    PLOG(WARNING) << "Could not get realpath for " << dex_location;
-  }
-  std::string dex_location_real_path_str((dex_location_real_path == nullptr)
-    ? dex_location.c_str()
-    : dex_location_real_path.get());
-
-  if (app_data_dirs.find(dex_location_real_path_str) != app_data_dirs.end()) {
-    // The dex location is under the application folder. Nothing to record.
-    return false;
-  }
-
-  if (app_code_paths.find(dex_location) != app_code_paths.end()) {
-    // The dex location belongs to the application code paths. Nothing to record.
-    return false;
-  }
-  // Do another round of checks with the real paths.
-  // Note that we could cache all the real locations in the saver (since it's an expensive
-  // operation). However we expect that app_code_paths is small (usually 1 element), and
-  // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise
-  // to save some bytes of memory usage.
-  for (const auto& app_code_location : app_code_paths) {
-    UniqueCPtr<const char[]> real_app_code_location(realpath(app_code_location.c_str(), nullptr));
-    if (real_app_code_location == nullptr) {
-      PLOG(WARNING) << "Could not get realpath for " << app_code_location;
+static bool CheckContainsWithRealPath(const std::set<std::string>& paths_set,
+                                      const std::string& path_to_check) {
+  for (const auto& path : paths_set) {
+    UniqueCPtr<const char[]> real_path(realpath(path.c_str(), nullptr));
+    if (real_path == nullptr) {
+      PLOG(WARNING) << "Could not get realpath for " << path;
+      continue;
     }
-    std::string real_app_code_location_str((real_app_code_location == nullptr)
-        ? app_code_location.c_str()
-        : real_app_code_location.get());
-    if (real_app_code_location_str == dex_location_real_path_str) {
-      // The dex location belongs to the application code paths. Nothing to record.
-      return false;
+    std::string real_path_str(real_path.get());
+    if (real_path_str == path_to_check) {
+      return true;
     }
   }
+  return false;
+}
 
+// After the call, dex_location_real_path will contain the marker's name.
+static bool CreateForeignDexMarker(const std::string& foreign_dex_profile_path,
+                                   /*in-out*/ std::string* dex_location_real_path) {
   // For foreign dex files we record a flag on disk. PackageManager will (potentially) take this
   // into account when deciding how to optimize the loaded dex file.
   // The expected flag name is the canonical path of the apk where '/' is substituted to '@'.
   // (it needs to be kept in sync with
   // frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java)
-  std::replace(dex_location_real_path_str.begin(), dex_location_real_path_str.end(), '/', '@');
-  std::string flag_path = foreign_dex_profile_path + "/" + dex_location_real_path_str;
+  std::replace(dex_location_real_path->begin(), dex_location_real_path->end(), '/', '@');
+  std::string flag_path = foreign_dex_profile_path + "/" + *dex_location_real_path;
   // We use O_RDONLY as the access mode because we must supply some access
   // mode, and there is no access mode that means 'create but do not read' the
   // file. We will not not actually read from the file.
@@ -619,6 +581,57 @@
   }
 }
 
+bool ProfileSaver::MaybeRecordDexUseInternal(
+      const std::string& dex_location,
+      const std::set<std::string>& app_code_paths,
+      const std::string& foreign_dex_profile_path,
+      const std::set<std::string>& app_data_dirs) {
+  if (dex_location.empty()) {
+    LOG(WARNING) << "Asked to record foreign dex use with an empty dex location.";
+    return false;
+  }
+  if (foreign_dex_profile_path.empty()) {
+    LOG(WARNING) << "Asked to record foreign dex use without a valid profile path ";
+    return false;
+  }
+
+  if (app_code_paths.find(dex_location) != app_code_paths.end()) {
+    // The dex location belongs to the application code paths. Nothing to record.
+    return false;
+  }
+
+  if (app_data_dirs.find(dex_location) != app_data_dirs.end()) {
+    // The dex location is under the application folder. Nothing to record.
+    return false;
+  }
+
+  // Do another round of checks with the real paths.
+  // Application directory could be a symlink (e.g. /data/data instead of /data/user/0), and we
+  // don't have control over how the dex files are actually loaded (symlink or canonical path),
+
+  // Note that we could cache all the real locations in the saver (since it's an expensive
+  // operation). However we expect that app_code_paths is small (usually 1 element), and
+  // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise
+  // to save some bytes of memory usage.
+
+  UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr));
+  if (dex_location_real_path == nullptr) {
+    PLOG(WARNING) << "Could not get realpath for " << dex_location;
+    return false;
+  }
+  std::string dex_location_real_path_str(dex_location_real_path.get());
+
+  if (CheckContainsWithRealPath(app_code_paths, dex_location_real_path_str)) {
+    return false;
+  }
+
+  if (CheckContainsWithRealPath(app_data_dirs, dex_location_real_path_str)) {
+    return false;
+  }
+
+  return CreateForeignDexMarker(foreign_dex_profile_path, &dex_location_real_path_str);
+}
+
 void ProfileSaver::DumpInstanceInfo(std::ostream& os) {
   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
   if (instance_ != nullptr) {
diff --git a/test/603-checker-instanceof/expected.txt b/test/603-checker-instanceof/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/603-checker-instanceof/expected.txt
diff --git a/test/603-checker-instanceof/info.txt b/test/603-checker-instanceof/info.txt
new file mode 100644
index 0000000..5907abc
--- /dev/null
+++ b/test/603-checker-instanceof/info.txt
@@ -0,0 +1,2 @@
+Regression test for the compiler that used to wrongly optimize
+an instanceof.
diff --git a/test/603-checker-instanceof/src/Main.java b/test/603-checker-instanceof/src/Main.java
new file mode 100644
index 0000000..ddf4b92
--- /dev/null
+++ b/test/603-checker-instanceof/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class SuperClass {
+}
+
+class ChildClass extends SuperClass {
+}
+
+public class Main {
+
+  /// CHECK-START:    void Main.main(java.lang.String[]) builder (after)
+  /// CHECK:          BoundType  klass:SuperClass can_be_null:false exact:false
+
+  /// CHECK-START:    void Main.main(java.lang.String[]) builder (after)
+  /// CHECK-NOT:      BoundType  klass:SuperClass can_be_null:false exact:true
+  public static void main(String[] args) {
+    Object obj = new ChildClass();
+
+    // We need a fixed point iteration to hit the bogus type update
+    // of 'obj' below, so create a loop that updates the type of 'obj'.
+    for (int i = 1; i < 1; i++) {
+      obj = new Object();
+    }
+
+    if (obj instanceof SuperClass) {
+      // We used to wrongly type obj as an exact SuperClass from this point,
+      // meaning we were statically determining that the following instanceof
+      // would always fail.
+      if (!(obj instanceof ChildClass)) {
+        throw new Error("Expected a ChildClass, got " + obj.getClass());
+      }
+    }
+  }
+}
diff --git a/test/604-hot-static-interface/build b/test/604-hot-static-interface/build
new file mode 100755
index 0000000..1ca2daf
--- /dev/null
+++ b/test/604-hot-static-interface/build
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# make us exit on a failure
+set -e
+
+if [[ $@ != *"--jvm"* ]]; then
+  # Don't do anything with jvm
+  # Hard-wired use of experimental jack.
+  # TODO: fix this temporary work-around for default-methods, see b/19467889
+  export USE_JACK=true
+fi
+
+./default-build "$@" --experimental default-methods
diff --git a/test/604-hot-static-interface/expected.txt b/test/604-hot-static-interface/expected.txt
new file mode 100644
index 0000000..6a5618e
--- /dev/null
+++ b/test/604-hot-static-interface/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/604-hot-static-interface/hot_static_interface.cc b/test/604-hot-static-interface/hot_static_interface.cc
new file mode 100644
index 0000000..9c51ca6
--- /dev/null
+++ b/test/604-hot-static-interface/hot_static_interface.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "art_method.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
+#include "oat_quick_method_header.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedUtfChars.h"
+#include "stack_map.h"
+
+namespace art {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_waitUntilJitted(JNIEnv* env,
+                                                            jclass,
+                                                            jclass itf,
+                                                            jstring method_name) {
+  jit::Jit* jit = Runtime::Current()->GetJit();
+  if (jit == nullptr) {
+    return;
+  }
+
+  ScopedObjectAccess soa(Thread::Current());
+
+  ScopedUtfChars chars(env, method_name);
+  CHECK(chars.c_str() != nullptr);
+
+  mirror::Class* klass = soa.Decode<mirror::Class*>(itf);
+  ArtMethod* method = klass->FindDeclaredDirectMethodByName(chars.c_str(), sizeof(void*));
+
+  jit::JitCodeCache* code_cache = jit->GetCodeCache();
+  OatQuickMethodHeader* header = nullptr;
+  while (true) {
+    header = OatQuickMethodHeader::FromEntryPoint(method->GetEntryPointFromQuickCompiledCode());
+    if (code_cache->ContainsPc(header->GetCode())) {
+      break;
+    } else {
+      // yield to scheduler to give time to the JIT compiler.
+      sched_yield();
+    }
+  }
+}
+
+}  // namespace art
diff --git a/test/604-hot-static-interface/info.txt b/test/604-hot-static-interface/info.txt
new file mode 100644
index 0000000..bc00bda
--- /dev/null
+++ b/test/604-hot-static-interface/info.txt
@@ -0,0 +1,2 @@
+Regression test for the JIT that used to crash when compiling
+a static method of an interface.
diff --git a/test/604-hot-static-interface/src/Main.java b/test/604-hot-static-interface/src/Main.java
new file mode 100644
index 0000000..559f15d
--- /dev/null
+++ b/test/604-hot-static-interface/src/Main.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    System.loadLibrary(args[0]);
+    // Loop enough to get Itf.foo JITed.
+    for (int i = 0; i < 100000; i++) {
+      Itf.foo(new Object());
+    }
+
+    waitUntilJitted(Itf.class, "foo");
+
+    if (!Itf.foo(new Object())) {
+      throw new Error("Unexpected result");
+    }
+  }
+
+  private static native void waitUntilJitted(Class itf, String method_name);
+}
+
+interface Itf {
+  public static boolean foo(Object o) {
+    return o.equals(o);
+  }
+}
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index 5b1af27..6d40cdf 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -44,7 +44,8 @@
   566-polymorphic-inlining/polymorphic_inline.cc \
   570-checker-osr/osr.cc \
   595-profile-saving/profile-saving.cc \
-  597-deopt-new-string/deopt.cc
+  597-deopt-new-string/deopt.cc \
+  604-hot-static-interface/hot_static_interface.cc
 
 ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
 ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttestd.so