Make instrumentation trampoline able to jump to jit code

In order to get the benefit of the instrumentation trampoline it must
be able to jump to jit code. This patch adds support for doing that
and adds code to ensure that we will not be jumping back and forth
between the trampoline and the interpreter all the time if the jit has
not yet compiled the current method.

Note we also disable the jit-gc when turning on these trampolines
since otherwise we could end up either sending instrumentation events
multiple times or running uninitialized memory.

Bug: 110263880
Test: ./test/testrunner/testrunner.py --host --runtime-option=-Xplugin:libtracefast-trampolined.so
Test: ./test/testrunner/testrunner.py --host --runtime-option=-Xplugin:libtracefast-trampolined.so --runtime-option=-Xjitthreshhold:0
Test: ./test.py --host

Change-Id: Ie6e92ec6367452fe4fde24d520d808b7af91d1b5
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index fe154a9..e635ad9 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -174,7 +174,10 @@
   bool use_ashmem = !generate_debug_info && !kIsTargetLinux && !kIsTargetFuchsia;
 
   // With 'perf', we want a 1-1 mapping between an address and a method.
-  bool garbage_collect_code = !generate_debug_info;
+  // We aren't able to keep method pointers live during the instrumentation method entry trampoline
+  // so we will just disable jit-gc if we are doing that.
+  bool garbage_collect_code = !generate_debug_info &&
+      !Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
 
   // We need to have 32 bit offsets from method headers in code cache which point to things
   // in the data cache. If the maps are more than 4G apart, having multiple maps wouldn't work.
@@ -316,6 +319,17 @@
   return code_map_->Begin() <= ptr && ptr < code_map_->End();
 }
 
+bool JitCodeCache::WillExecuteJitCode(ArtMethod* method) {
+  ScopedObjectAccess soa(art::Thread::Current());
+  ScopedAssertNoThreadSuspension sants(__FUNCTION__);
+  if (ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
+    return true;
+  } else if (method->GetEntryPointFromQuickCompiledCode() == GetQuickInstrumentationEntryPoint()) {
+    return FindCompiledCodeForInstrumentation(method) != nullptr;
+  }
+  return false;
+}
+
 bool JitCodeCache::ContainsMethod(ArtMethod* method) {
   MutexLock mu(Thread::Current(), lock_);
   if (UNLIKELY(method->IsNative())) {
@@ -348,6 +362,20 @@
   return nullptr;
 }
 
+const void* JitCodeCache::FindCompiledCodeForInstrumentation(ArtMethod* method) {
+  if (LIKELY(!GetGarbageCollectCode())) {
+    return nullptr;
+  }
+  ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
+  if (info == nullptr) {
+    return nullptr;
+  }
+  // When GC is disabled for trampoline tracing we will use SavedEntrypoint to hold the actual
+  // jit-compiled version of the method. If jit-gc is disabled for other reasons this will just be
+  // nullptr.
+  return info->GetSavedEntryPoint();
+}
+
 class ScopedCodeCacheWrite : ScopedTrace {
  public:
   explicit ScopedCodeCacheWrite(const JitCodeCache* const code_cache)
@@ -978,6 +1006,8 @@
     // checks should always pass.
     DCHECK(!info->IsInUseByCompiler());
     new_method->SetProfilingInfo(info);
+    // Get rid of the old saved entrypoint if it is there.
+    info->SetSavedEntryPoint(nullptr);
     info->method_ = new_method;
   }
   // Update method_code_map_ to point to the new method.
@@ -1321,7 +1351,8 @@
       if (GetLiveBitmap()->Test(allocation)) {
         ++it;
       } else {
-        method_headers.insert(OatQuickMethodHeader::FromCodePointer(code_ptr));
+        OatQuickMethodHeader* header = OatQuickMethodHeader::FromCodePointer(code_ptr);
+        method_headers.insert(header);
         it = method_code_map_.erase(it);
       }
     }
@@ -1786,13 +1817,18 @@
                                              const OatQuickMethodHeader* header) {
   DCHECK(!method->IsNative());
   ProfilingInfo* profiling_info = method->GetProfilingInfo(kRuntimePointerSize);
+  const void* method_entrypoint = method->GetEntryPointFromQuickCompiledCode();
   if ((profiling_info != nullptr) &&
       (profiling_info->GetSavedEntryPoint() == header->GetEntryPoint())) {
+    // When instrumentation is set, the actual entrypoint is the one in the profiling info.
+    method_entrypoint = profiling_info->GetSavedEntryPoint();
     // Prevent future uses of the compiled code.
     profiling_info->SetSavedEntryPoint(nullptr);
   }
 
-  if (method->GetEntryPointFromQuickCompiledCode() == header->GetEntryPoint()) {
+  // Clear the method counter if we are running jitted code since we might want to jit this again in
+  // the future.
+  if (method_entrypoint == header->GetEntryPoint()) {
     // The entrypoint is the one to invalidate, so we just update it to the interpreter entry point
     // and clear the counter to get the method Jitted again.
     Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(