Delay entrypoint update until visibly initialized.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing --jit
Test: aosp_taimen-userdebug boots.
Test: run-gtests.sh
Test: testrunner.py --target --optimizing --jit
Bug: 18161648
Change-Id: Idde0cbc848f19236319426bc82ac10b8b8bb9ee9
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index ff23385..e1db1f6 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -119,6 +119,21 @@
     code_ = code;
   }
 
+  void UpdateEntryPoints(const void* entrypoint) REQUIRES_SHARED(Locks::mutator_lock_) {
+    DCHECK(IsCompiled());
+    DCHECK(entrypoint == OatQuickMethodHeader::FromCodePointer(GetCode())->GetEntryPoint());
+    instrumentation::Instrumentation* instrum = Runtime::Current()->GetInstrumentation();
+    for (ArtMethod* m : GetMethods()) {
+      // Because `m` might be in the process of being deleted:
+      // - Call the dedicated method instead of the more generic UpdateMethodsCode
+      // - Check the class status without a read barrier.
+      // TODO: Use ReadBarrier::IsMarked() if not null to check the class status.
+      if (!m->NeedsInitializationCheck<kWithoutReadBarrier>()) {
+        instrum->UpdateNativeMethodsCodeToJitCode(m, entrypoint);
+      }
+    }
+  }
+
   const void* GetCode() const {
     return code_;
   }
@@ -705,15 +720,7 @@
       DCHECK(ContainsElement(data->GetMethods(), method))
           << "Entry inserted in NotifyCompilationOf() should contain this method.";
       data->SetCode(code_ptr);
-      instrumentation::Instrumentation* instrum = Runtime::Current()->GetInstrumentation();
-      for (ArtMethod* m : data->GetMethods()) {
-        // Because `m` might be in the process of being deleted:
-        // - Call the dedicated method instead of the more generic UpdateMethodsCode
-        // - Check the class status without a read barrier.
-        if (!m->NeedsInitializationCheck<kWithoutReadBarrier>()) {
-          instrum->UpdateNativeMethodsCodeToJitCode(m, method_header->GetEntryPoint());
-        }
-      }
+      data->UpdateEntryPoints(method_header->GetEntryPoint());
     } else {
       if (method->IsPreCompiled() && IsSharedRegion(*region)) {
         zygote_map_.Put(code_ptr, method);
@@ -1555,6 +1562,12 @@
   if (method->NeedsInitializationCheck() && !prejit) {
     // Unless we're pre-jitting, we currently don't save the JIT compiled code if we cannot
     // update the entrypoint due to needing an initialization check.
+    if (method->GetDeclaringClass()->IsInitialized()) {
+      // Request visible initialization but do not block to allow compiling other methods.
+      // Hopefully, this will complete by the time the method becomes hot again.
+      Runtime::Current()->GetClassLinker()->MakeInitializedClassesVisiblyInitialized(
+          self, /*wait=*/ false);
+    }
     VLOG(jit) << "Not compiling "
               << method->PrettyMethod()
               << " because it has the resolution stub";
@@ -1587,15 +1600,7 @@
       // changed these entrypoints to GenericJNI in preparation for a full GC, we may
       // as well change them back as this stub shall not be collected anyway and this
       // can avoid a few expensive GenericJNI calls.
-      instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
-      for (ArtMethod* m : data->GetMethods()) {
-        // Because `m` might be in the process of being deleted:
-        // - Call the dedicated method instead of the more generic UpdateMethodsCode
-        // - Check the class status without a read barrier.
-        if (!m->NeedsInitializationCheck<kWithoutReadBarrier>()) {
-          instrumentation->UpdateNativeMethodsCodeToJitCode(m, entrypoint);
-        }
-      }
+      data->UpdateEntryPoints(entrypoint);
       if (collection_in_progress_) {
         if (!IsInZygoteExecSpace(data->GetCode())) {
           GetLiveBitmap()->AtomicTestAndSet(FromCodeToAllocation(data->GetCode()));