Special case JIT update for native methods.

The update might apply to ArtMethods that are going to be
unloaded, so ensure we don't do read barriers there.

Test: while ./art/test/run-test --host  --no-dex2oat --jit --host --no-prebuild \
        --compact-dex-level none --dex2oat-jobs 4 --no-relocate --runtime-option -Xcheck:jni \
        --build-with-javac-dx 674-hiddenapi ; do true; done

Change-Id: I95ec6107c65da25f4b98f7fb77647b3ab382a93f
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 4524448..2101f68 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -776,6 +776,17 @@
   UpdateEntrypoints(method, new_quick_code);
 }
 
+void Instrumentation::UpdateNativeMethodsCodeToJitCode(ArtMethod* method, const void* quick_code) {
+  // We don't do any read barrier on `method`'s declaring class in this code, as the JIT might
+  // enter here on a soon-to-be deleted ArtMethod. Updating the entrypoint is OK though, as
+  // the ArtMethod is still in memory.
+  const void* new_quick_code = quick_code;
+  if (UNLIKELY(instrumentation_stubs_installed_) && entry_exit_stubs_installed_) {
+    new_quick_code = GetQuickInstrumentationEntryPoint();
+  }
+  UpdateEntrypoints(method, new_quick_code);
+}
+
 void Instrumentation::UpdateMethodsCode(ArtMethod* method, const void* quick_code) {
   DCHECK(method->GetDeclaringClass()->IsResolved());
   UpdateMethodsCodeImpl(method, quick_code);
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index da63152..46b3f8d 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -280,6 +280,10 @@
   void UpdateMethodsCode(ArtMethod* method, const void* quick_code)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!deoptimized_methods_lock_);
 
+  // Update the code of a native method to a JITed stub.
+  void UpdateNativeMethodsCodeToJitCode(ArtMethod* method, const void* quick_code)
+      REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!deoptimized_methods_lock_);
+
   // Update the code of a method to the interpreter respecting any installed stubs from debugger.
   void UpdateMethodsCodeToInterpreterEntryPoint(ArtMethod* method)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!deoptimized_methods_lock_);
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 3d3e61b..7f04477 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -1699,7 +1699,9 @@
       // can avoid a few expensive GenericJNI calls.
       instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
       for (ArtMethod* m : data->GetMethods()) {
-        instrumentation->UpdateMethodsCode(m, entrypoint);
+        // Call the dedicated method instead of the more generic UpdateMethodsCode, because
+        // `m` might be in the process of being deleted.
+        instrumentation->UpdateNativeMethodsCodeToJitCode(m, entrypoint);
       }
       if (collection_in_progress_) {
         GetLiveBitmap()->AtomicTestAndSet(FromCodeToAllocation(data->GetCode()));