Revert "JIT JNI stubs."

Seems to break 998-redefine-use-after-free in
some --no-image configuration.

Bug: 65574695
Bug: 69843562

This reverts commit 3417eaefe4e714c489a6fb0cb89b4810d81bdf4d.

Change-Id: I2dd157b931c17c791522ea2544c1982ed3519b86
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index b6d3294..5a9e2c5 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1196,69 +1196,7 @@
 
   Runtime* runtime = Runtime::Current();
   ArenaAllocator allocator(runtime->GetJitArenaPool());
-
-  if (UNLIKELY(method->IsNative())) {
-    JniCompiledMethod jni_compiled_method = ArtQuickJniCompileMethod(
-        GetCompilerDriver(), access_flags, method_idx, *dex_file);
-    ScopedNullHandle<mirror::ObjectArray<mirror::Object>> roots;
-    ArenaSet<ArtMethod*, std::less<ArtMethod*>> cha_single_implementation_list(
-        allocator.Adapter(kArenaAllocCHA));
-    const void* code = code_cache->CommitCode(
-        self,
-        method,
-        /* stack_map_data */ nullptr,
-        /* method_info_data */ nullptr,
-        /* roots_data */ nullptr,
-        jni_compiled_method.GetFrameSize(),
-        jni_compiled_method.GetCoreSpillMask(),
-        jni_compiled_method.GetFpSpillMask(),
-        jni_compiled_method.GetCode().data(),
-        jni_compiled_method.GetCode().size(),
-        /* data_size */ 0u,
-        osr,
-        roots,
-        /* has_should_deoptimize_flag */ false,
-        cha_single_implementation_list);
-    if (code == nullptr) {
-      return false;
-    }
-
-    const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
-    if (compiler_options.GetGenerateDebugInfo()) {
-      const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code);
-      const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode());
-      debug::MethodDebugInfo info = {};
-      DCHECK(info.trampoline_name.empty());
-      info.dex_file = dex_file;
-      info.class_def_index = class_def_idx;
-      info.dex_method_index = method_idx;
-      info.access_flags = access_flags;
-      info.code_item = code_item;
-      info.isa = jni_compiled_method.GetInstructionSet();
-      info.deduped = false;
-      info.is_native_debuggable = compiler_options.GetNativeDebuggable();
-      info.is_optimized = true;
-      info.is_code_address_text_relative = false;
-      info.code_address = code_address;
-      info.code_size = jni_compiled_method.GetCode().size();
-      info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
-      info.code_info = nullptr;
-      info.cfi = jni_compiled_method.GetCfi();
-      std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForMethods(
-          GetCompilerDriver()->GetInstructionSet(),
-          GetCompilerDriver()->GetInstructionSetFeatures(),
-          ArrayRef<const debug::MethodDebugInfo>(&info, 1));
-      CreateJITCodeEntryForAddress(code_address, std::move(elf_file));
-    }
-
-    Runtime::Current()->GetJit()->AddMemoryUsage(method, allocator.BytesUsed());
-    if (jit_logger != nullptr) {
-      jit_logger->WriteLog(code, jni_compiled_method.GetCode().size(), method);
-    }
-    return true;
-  }
-
-  ArenaStack arena_stack(runtime->GetJitArenaPool());
+  ArenaStack arena_stack(Runtime::Current()->GetJitArenaPool());
   CodeVectorAllocator code_allocator(&allocator);
   VariableSizedHandleScope handles(self);
 
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 6ec9c48..6ff8dd6 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1783,9 +1783,7 @@
     .cfi_adjust_cfa_offset FRAME_SIZE_SAVE_REFS_AND_ARGS-FRAME_SIZE_SAVE_REFS_ONLY
 
 .Lexception_in_native:
-    ldr ip, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]
-    add ip, ip, #-1  // Remove the GenericJNI tag. ADD/SUB writing directly to SP is UNPREDICTABLE.
-    mov sp, ip
+    ldr sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]
     .cfi_def_cfa_register sp
     # This will create a new save-all frame, required by the runtime.
     DELIVER_PENDING_EXCEPTION
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 47efeb9..280e593 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -2299,7 +2299,7 @@
 .Lexception_in_native:
     // Move to x1 then sp to please assembler.
     ldr x1, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
-    add sp, x1, #-1  // Remove the GenericJNI tag.
+    mov sp, x1
     .cfi_def_cfa_register sp
     # This will create a new save-all frame, required by the runtime.
     DELIVER_PENDING_EXCEPTION
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index fc77a64..489c52c 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -2283,8 +2283,7 @@
     nop
 
 2:
-    lw      $t0, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
-    addiu   $sp, $t0, -1  // Remove the GenericJNI tag.
+    lw      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
     move    $gp, $s3               # restore $gp from $s3
     # This will create a new save-all frame, required by the runtime.
     DELIVER_PENDING_EXCEPTION
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 3fb83d9..98ffe65 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -2158,8 +2158,7 @@
     dmtc1   $v0, $f0               # place return value to FP return value
 
 1:
-    ld      $t0, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
-    daddiu  $sp, $t0, -1  // Remove the GenericJNI tag.
+    ld      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
     # This will create a new save-all frame, required by the runtime.
     DELIVER_PENDING_EXCEPTION
 END art_quick_generic_jni_trampoline
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index a46ceeb..25716dc 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1969,9 +1969,7 @@
     punpckldq %xmm1, %xmm0
     ret
 .Lexception_in_native:
-    pushl %fs:THREAD_TOP_QUICK_FRAME_OFFSET
-    addl LITERAL(-1), (%esp)  // Remove the GenericJNI tag.
-    movl (%esp), %esp
+    movl %fs:THREAD_TOP_QUICK_FRAME_OFFSET, %esp
     // Do a call to push a new save-all frame required by the runtime.
     call .Lexception_call
 .Lexception_call:
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 463e5a2..2c3da90 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1958,9 +1958,7 @@
     movq %rax, %xmm0
     ret
 .Lexception_in_native:
-    pushq %gs:THREAD_TOP_QUICK_FRAME_OFFSET
-    addq LITERAL(-1), (%rsp)  // Remove the GenericJNI tag.
-    movq (%rsp), %rsp
+    movq %gs:THREAD_TOP_QUICK_FRAME_OFFSET, %rsp
     CFI_DEF_CFA_REGISTER(rsp)
     // Do a call to push a new save-all frame required by the runtime.
     call .Lexception_call
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index bdbc450..fa0c501 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -587,6 +587,11 @@
   CHECK(existing_entry_point != nullptr) << PrettyMethod() << "@" << this;
   ClassLinker* class_linker = runtime->GetClassLinker();
 
+  if (class_linker->IsQuickGenericJniStub(existing_entry_point)) {
+    // The generic JNI does not have any method header.
+    return nullptr;
+  }
+
   if (existing_entry_point == GetQuickProxyInvokeHandler()) {
     DCHECK(IsProxyMethod() && !IsConstructor());
     // The proxy entry point does not have any method header.
@@ -594,8 +599,7 @@
   }
 
   // Check whether the current entry point contains this pc.
-  if (!class_linker->IsQuickGenericJniStub(existing_entry_point) &&
-      !class_linker->IsQuickResolutionStub(existing_entry_point) &&
+  if (!class_linker->IsQuickResolutionStub(existing_entry_point) &&
       !class_linker->IsQuickToInterpreterBridge(existing_entry_point)) {
     OatQuickMethodHeader* method_header =
         OatQuickMethodHeader::FromEntryPoint(existing_entry_point);
@@ -628,13 +632,19 @@
   OatFile::OatMethod oat_method =
       FindOatMethodFor(this, class_linker->GetImagePointerSize(), &found);
   if (!found) {
-    if (IsNative()) {
-      // We are running the GenericJNI stub. The entrypoint may point
-      // to different entrypoints or to a JIT-compiled JNI stub.
-      DCHECK(class_linker->IsQuickGenericJniStub(existing_entry_point) ||
-             class_linker->IsQuickResolutionStub(existing_entry_point) ||
-             existing_entry_point == GetQuickInstrumentationEntryPoint() ||
-             (jit != nullptr && jit->GetCodeCache()->ContainsPc(existing_entry_point)));
+    if (class_linker->IsQuickResolutionStub(existing_entry_point)) {
+      // We are running the generic jni stub, but the entry point of the method has not
+      // been updated yet.
+      DCHECK_EQ(pc, 0u) << "Should be a downcall";
+      DCHECK(IsNative());
+      return nullptr;
+    }
+    if (existing_entry_point == GetQuickInstrumentationEntryPoint()) {
+      // We are running the generic jni stub, but the method is being instrumented.
+      // NB We would normally expect the pc to be zero but we can have non-zero pc's if
+      // instrumentation is installed or removed during the call which is using the generic jni
+      // trampoline.
+      DCHECK(IsNative());
       return nullptr;
     }
     // Only for unit tests.
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 6c3bb10..dca6f37 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -460,11 +460,12 @@
   }
 
   ProfilingInfo* GetProfilingInfo(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_) {
-    // Don't do a read barrier in the DCHECK() inside GetAccessFlags() called by IsNative(),
-    // as GetProfilingInfo is called in places where the declaring class is treated as a weak
-    // reference (accessing it with a read barrier would either prevent unloading the class,
-    // or crash the runtime if the GC wants to unload it).
-    if (UNLIKELY(IsNative<kWithoutReadBarrier>()) || UNLIKELY(IsProxyMethod())) {
+    // Don't do a read barrier in the DCHECK, as GetProfilingInfo is called in places
+    // where the declaring class is treated as a weak reference (accessing it with
+    // a read barrier would either prevent unloading the class, or crash the runtime if
+    // the GC wants to unload it).
+    DCHECK(!IsNative<kWithoutReadBarrier>());
+    if (UNLIKELY(IsProxyMethod())) {
       return nullptr;
     }
     return reinterpret_cast<ProfilingInfo*>(GetDataPtrSize(pointer_size));
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index f3450da..2bf4372 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -245,7 +245,7 @@
 CallerAndOuterMethod GetCalleeSaveMethodCallerAndOuterMethod(Thread* self, CalleeSaveType type) {
   CallerAndOuterMethod result;
   ScopedAssertNoThreadSuspension ants(__FUNCTION__);
-  ArtMethod** sp = self->GetManagedStack()->GetTopQuickFrameKnownNotTagged();
+  ArtMethod** sp = self->GetManagedStack()->GetTopQuickFrame();
   auto outer_caller_and_pc = DoGetCalleeSaveMethodOuterCallerAndPc(sp, type);
   result.outer_method = outer_caller_and_pc.first;
   uintptr_t caller_pc = outer_caller_and_pc.second;
@@ -256,7 +256,7 @@
 
 ArtMethod* GetCalleeSaveOuterMethod(Thread* self, CalleeSaveType type) {
   ScopedAssertNoThreadSuspension ants(__FUNCTION__);
-  ArtMethod** sp = self->GetManagedStack()->GetTopQuickFrameKnownNotTagged();
+  ArtMethod** sp = self->GetManagedStack()->GetTopQuickFrame();
   return DoGetCalleeSaveMethodOuterCallerAndPc(sp, type).first;
 }
 
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 0a76cdd..2496aa0 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -31,7 +31,6 @@
 #include "index_bss_mapping.h"
 #include "instrumentation.h"
 #include "interpreter/interpreter.h"
-#include "jit/jit.h"
 #include "linear_alloc.h"
 #include "method_handles.h"
 #include "method_reference.h"
@@ -2168,11 +2167,6 @@
   // Note: We cannot walk the stack properly until fixed up below.
   ArtMethod* called = *sp;
   DCHECK(called->IsNative()) << called->PrettyMethod(true);
-  Runtime* runtime = Runtime::Current();
-  jit::Jit* jit = runtime->GetJit();
-  if (jit != nullptr) {
-    jit->AddSamples(self, called, 1u, /*with_backedges*/ false);
-  }
   uint32_t shorty_len = 0;
   const char* shorty = called->GetShorty(&shorty_len);
   bool critical_native = called->IsCriticalNative();
@@ -2194,7 +2188,7 @@
   }
 
   // Fix up managed-stack things in Thread. After this we can walk the stack.
-  self->SetTopOfStackTagged(sp);
+  self->SetTopOfStack(sp);
 
   self->VerifyStack();
 
@@ -2314,7 +2308,6 @@
   // anything that requires a mutator lock before that would cause problems as GC may have the
   // exclusive mutator lock and may be moving objects, etc.
   ArtMethod** sp = self->GetManagedStack()->GetTopQuickFrame();
-  DCHECK(self->GetManagedStack()->GetTopQuickFrameTag());
   uint32_t* sp32 = reinterpret_cast<uint32_t*>(sp);
   ArtMethod* called = *sp;
   uint32_t cookie = *(sp32 - 1);
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 0d95bc6..953e195 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -643,7 +643,7 @@
     return;
   }
 
-  if (method->IsClassInitializer() || !method->IsCompilable()) {
+  if (method->IsClassInitializer() || method->IsNative() || !method->IsCompilable()) {
     // We do not want to compile such methods.
     return;
   }
@@ -659,8 +659,7 @@
     count *= priority_thread_weight_;
   }
   int32_t new_count = starting_count + count;   // int32 here to avoid wrap-around;
-  // Note: Native method have no "warm" state or profiling info.
-  if (LIKELY(!method->IsNative()) && starting_count < warm_method_threshold_) {
+  if (starting_count < warm_method_threshold_) {
     if ((new_count >= warm_method_threshold_) &&
         (method->GetProfilingInfo(kRuntimePointerSize) == nullptr)) {
       bool success = ProfilingInfo::Create(self, method, /* retry_allocation */ false);
@@ -697,7 +696,6 @@
         // If the samples don't contain any back edge, we don't increment the hotness.
         return;
       }
-      DCHECK(!method->IsNative());  // No back edges reported for native methods.
       if ((new_count >= osr_method_threshold_) &&  !code_cache_->IsOsrCompiled(method)) {
         DCHECK(thread_pool_ != nullptr);
         thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompileOsr));
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index a5c167e..3220513 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -55,107 +55,6 @@
 static constexpr size_t kCodeSizeLogThreshold = 50 * KB;
 static constexpr size_t kStackMapSizeLogThreshold = 50 * KB;
 
-class JitCodeCache::JniStubKey {
- public:
-  explicit JniStubKey(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_)
-      : shorty_(method->GetShorty()),
-        is_static_(method->IsStatic()),
-        is_fast_native_(method->IsFastNative()),
-        is_critical_native_(method->IsCriticalNative()),
-        is_synchronized_(method->IsSynchronized()) {
-    DCHECK(!(is_fast_native_ && is_critical_native_));
-  }
-
-  bool operator<(const JniStubKey& rhs) const {
-    if (is_static_ != rhs.is_static_) {
-      return rhs.is_static_;
-    }
-    if (is_synchronized_ != rhs.is_synchronized_) {
-      return rhs.is_synchronized_;
-    }
-    if (is_fast_native_ != rhs.is_fast_native_) {
-      return rhs.is_fast_native_;
-    }
-    if (is_critical_native_ != rhs.is_critical_native_) {
-      return rhs.is_critical_native_;
-    }
-    return strcmp(shorty_, rhs.shorty_) < 0;
-  }
-
-  // Update the shorty to point to another method's shorty. Call this function when removing
-  // the method that references the old shorty from JniCodeData and not removing the entire
-  // JniCodeData; the old shorty may become a dangling pointer when that method is unloaded.
-  void UpdateShorty(ArtMethod* method) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    const char* shorty = method->GetShorty();
-    DCHECK_STREQ(shorty_, shorty);
-    shorty_ = shorty;
-  }
-
- private:
-  // The shorty points to a DexFile data and may need to change
-  // to point to the same shorty in a different DexFile.
-  mutable const char* shorty_;
-
-  const bool is_static_;
-  const bool is_fast_native_;
-  const bool is_critical_native_;
-  const bool is_synchronized_;
-};
-
-class JitCodeCache::JniStubData {
- public:
-  JniStubData() : code_(nullptr), methods_() {}
-
-  void SetCode(const void* code) {
-    DCHECK(code != nullptr);
-    code_ = code;
-  }
-
-  const void* GetCode() const {
-    return code_;
-  }
-
-  bool IsCompiled() const {
-    return GetCode() != nullptr;
-  }
-
-  void AddMethod(ArtMethod* method) {
-    if (!ContainsElement(methods_, method)) {
-      methods_.push_back(method);
-    }
-  }
-
-  const std::vector<ArtMethod*>& GetMethods() const {
-    return methods_;
-  }
-
-  void RemoveMethodsIn(const LinearAlloc& alloc) {
-    auto kept_end = std::remove_if(
-        methods_.begin(),
-        methods_.end(),
-        [&alloc](ArtMethod* method) { return alloc.ContainsUnsafe(method); });
-    methods_.erase(kept_end, methods_.end());
-  }
-
-  bool RemoveMethod(ArtMethod* method) {
-    auto it = std::find(methods_.begin(), methods_.end(), method);
-    if (it != methods_.end()) {
-      methods_.erase(it);
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  void MoveObsoleteMethod(ArtMethod* old_method, ArtMethod* new_method) {
-    std::replace(methods_.begin(), methods_.end(), old_method, new_method);
-  }
-
- private:
-  const void* code_;
-  std::vector<ArtMethod*> methods_;
-};
-
 JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
                                    size_t max_capacity,
                                    bool generate_debug_info,
@@ -294,36 +193,14 @@
 
 bool JitCodeCache::ContainsMethod(ArtMethod* method) {
   MutexLock mu(Thread::Current(), lock_);
-  if (UNLIKELY(method->IsNative())) {
-    auto it = jni_stubs_map_.find(JniStubKey(method));
-    if (it != jni_stubs_map_.end() &&
-        it->second.IsCompiled() &&
-        ContainsElement(it->second.GetMethods(), method)) {
+  for (auto& it : method_code_map_) {
+    if (it.second == method) {
       return true;
     }
-  } else {
-    for (const auto& it : method_code_map_) {
-      if (it.second == method) {
-        return true;
-      }
-    }
   }
   return false;
 }
 
-const void* JitCodeCache::GetJniStubCode(ArtMethod* method) {
-  DCHECK(method->IsNative());
-  MutexLock mu(Thread::Current(), lock_);
-  auto it = jni_stubs_map_.find(JniStubKey(method));
-  if (it != jni_stubs_map_.end()) {
-    JniStubData& data = it->second;
-    if (data.IsCompiled() && ContainsElement(data.GetMethods(), method)) {
-      return data.GetCode();
-    }
-  }
-  return nullptr;
-}
-
 class ScopedCodeCacheWrite : ScopedTrace {
  public:
   explicit ScopedCodeCacheWrite(MemMap* code_map, bool only_for_tlb_shootdown = false)
@@ -549,9 +426,7 @@
   // Notify native debugger that we are about to remove the code.
   // It does nothing if we are not using native debugger.
   DeleteJITCodeEntryForAddress(reinterpret_cast<uintptr_t>(code_ptr));
-  if (OatQuickMethodHeader::FromCodePointer(code_ptr)->IsOptimized()) {
-    FreeData(GetRootTable(code_ptr));
-  }  // else this is a JNI stub without any data.
+  FreeData(GetRootTable(code_ptr));
   FreeCode(reinterpret_cast<uint8_t*>(allocation));
 }
 
@@ -588,16 +463,6 @@
     // lead to a deadlock.
     {
       ScopedCodeCacheWrite scc(code_map_.get());
-      for (auto it = jni_stubs_map_.begin(); it != jni_stubs_map_.end();) {
-        it->second.RemoveMethodsIn(alloc);
-        if (it->second.GetMethods().empty()) {
-          method_headers.insert(OatQuickMethodHeader::FromCodePointer(it->second.GetCode()));
-          it = jni_stubs_map_.erase(it);
-        } else {
-          it->first.UpdateShorty(it->second.GetMethods().front());
-          ++it;
-        }
-      }
       for (auto it = method_code_map_.begin(); it != method_code_map_.end();) {
         if (alloc.ContainsUnsafe(it->second)) {
           method_headers.insert(OatQuickMethodHeader::FromCodePointer(it->first));
@@ -707,8 +572,7 @@
                                           bool has_should_deoptimize_flag,
                                           const ArenaSet<ArtMethod*>&
                                               cha_single_implementation_list) {
-  DCHECK_NE(stack_map != nullptr, method->IsNative());
-  DCHECK(!method->IsNative() || !osr);
+  DCHECK(stack_map != nullptr);
   size_t alignment = GetInstructionSetAlignment(kRuntimeISA);
   // Ensure the header ends up at expected instruction alignment.
   size_t header_size = RoundUp(sizeof(OatQuickMethodHeader), alignment);
@@ -732,8 +596,8 @@
       std::copy(code, code + code_size, code_ptr);
       method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
       new (method_header) OatQuickMethodHeader(
-          (stack_map != nullptr) ? code_ptr - stack_map : 0u,
-          (method_info != nullptr) ? code_ptr - method_info : 0u,
+          code_ptr - stack_map,
+          code_ptr - method_info,
           frame_size_in_bytes,
           core_spill_mask,
           fp_spill_mask,
@@ -788,40 +652,24 @@
     // possible that the compiled code is considered invalidated by some class linking,
     // but below we still make the compiled code valid for the method.
     MutexLock mu(self, lock_);
-    if (UNLIKELY(method->IsNative())) {
-      DCHECK(stack_map == nullptr);
-      DCHECK(roots_data == nullptr);
-      auto it = jni_stubs_map_.find(JniStubKey(method));
-      DCHECK(it != jni_stubs_map_.end())
-          << "Entry inserted in NotifyCompilationOf() should be alive.";
-      JniStubData* data = &it->second;
-      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()) {
-        instrum->UpdateMethodsCode(m, method_header->GetEntryPoint());
-      }
+    // Fill the root table before updating the entry point.
+    DCHECK_EQ(FromStackMapToRoots(stack_map), roots_data);
+    DCHECK_LE(roots_data, stack_map);
+    FillRootTable(roots_data, roots);
+    {
+      // Flush data cache, as compiled code references literals in it.
+      // We also need a TLB shootdown to act as memory barrier across cores.
+      ScopedCodeCacheWrite ccw(code_map_.get(), /* only_for_tlb_shootdown */ true);
+      FlushDataCache(reinterpret_cast<char*>(roots_data),
+                     reinterpret_cast<char*>(roots_data + data_size));
+    }
+    method_code_map_.Put(code_ptr, method);
+    if (osr) {
+      number_of_osr_compilations_++;
+      osr_code_map_.Put(method, code_ptr);
     } else {
-      // Fill the root table before updating the entry point.
-      DCHECK_EQ(FromStackMapToRoots(stack_map), roots_data);
-      DCHECK_LE(roots_data, stack_map);
-      FillRootTable(roots_data, roots);
-      {
-        // Flush data cache, as compiled code references literals in it.
-        // We also need a TLB shootdown to act as memory barrier across cores.
-        ScopedCodeCacheWrite ccw(code_map_.get(), /* only_for_tlb_shootdown */ true);
-        FlushDataCache(reinterpret_cast<char*>(roots_data),
-                       reinterpret_cast<char*>(roots_data + data_size));
-      }
-      method_code_map_.Put(code_ptr, method);
-      if (osr) {
-        number_of_osr_compilations_++;
-        osr_code_map_.Put(method, code_ptr);
-      } else {
-        Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
-            method, method_header->GetEntryPoint());
-      }
+      Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
+          method, method_header->GetEntryPoint());
     }
     if (collection_in_progress_) {
       // We need to update the live bitmap if there is a GC to ensure it sees this new
@@ -855,18 +703,45 @@
 }
 
 bool JitCodeCache::RemoveMethod(ArtMethod* method, bool release_memory) {
-  // This function is used only for testing and only with non-native methods.
-  CHECK(!method->IsNative());
-
   MutexLock mu(Thread::Current(), lock_);
+  if (method->IsNative()) {
+    return false;
+  }
 
-  bool osr = osr_code_map_.find(method) != osr_code_map_.end();
-  bool in_cache = RemoveMethodLocked(method, release_memory);
+  bool in_cache = false;
+  {
+    ScopedCodeCacheWrite ccw(code_map_.get());
+    for (auto code_iter = method_code_map_.begin(); code_iter != method_code_map_.end();) {
+      if (code_iter->second == method) {
+        if (release_memory) {
+          FreeCode(code_iter->first);
+        }
+        code_iter = method_code_map_.erase(code_iter);
+        in_cache = true;
+        continue;
+      }
+      ++code_iter;
+    }
+  }
+
+  bool osr = false;
+  auto code_map = osr_code_map_.find(method);
+  if (code_map != osr_code_map_.end()) {
+    osr_code_map_.erase(code_map);
+    osr = true;
+  }
 
   if (!in_cache) {
     return false;
   }
 
+  ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
+  if (info != nullptr) {
+    auto profile = std::find(profiling_infos_.begin(), profiling_infos_.end(), info);
+    DCHECK(profile != profiling_infos_.end());
+    profiling_infos_.erase(profile);
+  }
+  method->SetProfilingInfo(nullptr);
   method->ClearCounter();
   Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
       method, GetQuickToInterpreterBridge());
@@ -878,58 +753,34 @@
   return true;
 }
 
-bool JitCodeCache::RemoveMethodLocked(ArtMethod* method, bool release_memory) {
-  if (LIKELY(!method->IsNative())) {
-    ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
-    if (info != nullptr) {
-      RemoveElement(profiling_infos_, info);
-    }
-    method->SetProfilingInfo(nullptr);
-  }
-
-  bool in_cache = false;
-  ScopedCodeCacheWrite ccw(code_map_.get());
-  if (UNLIKELY(method->IsNative())) {
-    auto it = jni_stubs_map_.find(JniStubKey(method));
-    if (it != jni_stubs_map_.end() && it->second.RemoveMethod(method)) {
-      in_cache = true;
-      if (it->second.GetMethods().empty()) {
-        if (release_memory) {
-          FreeCode(it->second.GetCode());
-        }
-        jni_stubs_map_.erase(it);
-      } else {
-        it->first.UpdateShorty(it->second.GetMethods().front());
-      }
-    }
-  } else {
-    for (auto it = method_code_map_.begin(); it != method_code_map_.end();) {
-      if (it->second == method) {
-        in_cache = true;
-        if (release_memory) {
-          FreeCode(it->first);
-        }
-        it = method_code_map_.erase(it);
-      } else {
-        ++it;
-      }
-    }
-
-    auto osr_it = osr_code_map_.find(method);
-    if (osr_it != osr_code_map_.end()) {
-      osr_code_map_.erase(osr_it);
-    }
-  }
-
-  return in_cache;
-}
-
 // This notifies the code cache that the given method has been redefined and that it should remove
 // any cached information it has on the method. All threads must be suspended before calling this
 // method. The compiled code for the method (if there is any) must not be in any threads call stack.
 void JitCodeCache::NotifyMethodRedefined(ArtMethod* method) {
   MutexLock mu(Thread::Current(), lock_);
-  RemoveMethodLocked(method, /* release_memory */ true);
+  if (method->IsNative()) {
+    return;
+  }
+  ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
+  if (info != nullptr) {
+    auto profile = std::find(profiling_infos_.begin(), profiling_infos_.end(), info);
+    DCHECK(profile != profiling_infos_.end());
+    profiling_infos_.erase(profile);
+  }
+  method->SetProfilingInfo(nullptr);
+  ScopedCodeCacheWrite ccw(code_map_.get());
+  for (auto code_iter = method_code_map_.begin(); code_iter != method_code_map_.end();) {
+    if (code_iter->second == method) {
+      FreeCode(code_iter->first);
+      code_iter = method_code_map_.erase(code_iter);
+      continue;
+    }
+    ++code_iter;
+  }
+  auto code_map = osr_code_map_.find(method);
+  if (code_map != osr_code_map_.end()) {
+    osr_code_map_.erase(code_map);
+  }
 }
 
 // This invalidates old_method. Once this function returns one can no longer use old_method to
@@ -939,15 +790,11 @@
 // shouldn't be used since it is no longer logically in the jit code cache.
 // TODO We should add DCHECKS that validate that the JIT is paused when this method is entered.
 void JitCodeCache::MoveObsoleteMethod(ArtMethod* old_method, ArtMethod* new_method) {
-  MutexLock mu(Thread::Current(), lock_);
+  // Native methods have no profiling info and need no special handling from the JIT code cache.
   if (old_method->IsNative()) {
-    // Update methods in jni_stubs_map_.
-    for (auto& entry : jni_stubs_map_) {
-      JniStubData& data = entry.second;
-      data.MoveObsoleteMethod(old_method, new_method);
-    }
     return;
   }
+  MutexLock mu(Thread::Current(), lock_);
   // Update ProfilingInfo to the new one and remove it from the old_method.
   if (old_method->GetProfilingInfo(kRuntimePointerSize) != nullptr) {
     DCHECK_EQ(old_method->GetProfilingInfo(kRuntimePointerSize)->GetMethod(), old_method);
@@ -1089,7 +936,7 @@
         // its stack frame, it is not the method owning return_pc_. We just pass null to
         // LookupMethodHeader: the method is only checked against in debug builds.
         OatQuickMethodHeader* method_header =
-            code_cache_->LookupMethodHeader(frame.return_pc_, /* method */ nullptr);
+            code_cache_->LookupMethodHeader(frame.return_pc_, nullptr);
         if (method_header != nullptr) {
           const void* code = method_header->GetCode();
           CHECK(code_cache_->GetLiveBitmap()->Test(FromCodeToAllocation(code)));
@@ -1242,7 +1089,7 @@
           const void* entry_point = info->GetMethod()->GetEntryPointFromQuickCompiledCode();
           if (ContainsPc(entry_point)) {
             info->SetSavedEntryPoint(entry_point);
-            // Don't call Instrumentation::UpdateMethodsCode(), as it can check the declaring
+            // Don't call Instrumentation::UpdateMethods, as it can check the declaring
             // class of the method. We may be concurrently running a GC which makes accessing
             // the class unsafe. We know it is OK to bypass the instrumentation as we've just
             // checked that the current entry point is JIT compiled code.
@@ -1251,25 +1098,6 @@
         }
 
         DCHECK(CheckLiveCompiledCodeHasProfilingInfo());
-
-        // Change entry points of native methods back to the GenericJNI entrypoint.
-        for (const auto& entry : jni_stubs_map_) {
-          const JniStubData& data = entry.second;
-          if (!data.IsCompiled()) {
-            continue;
-          }
-          // Make sure a single invocation of the GenericJNI trampoline tries to recompile.
-          uint16_t new_counter = Runtime::Current()->GetJit()->HotMethodThreshold() - 1u;
-          const OatQuickMethodHeader* method_header =
-              OatQuickMethodHeader::FromCodePointer(data.GetCode());
-          for (ArtMethod* method : data.GetMethods()) {
-            if (method->GetEntryPointFromQuickCompiledCode() == method_header->GetEntryPoint()) {
-              // Don't call Instrumentation::UpdateMethodsCode(), same as for normal methods above.
-              method->SetCounter(new_counter);
-              method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
-            }
-          }
-        }
       }
       live_bitmap_.reset(nullptr);
       NotifyCollectionDone(self);
@@ -1285,22 +1113,13 @@
     MutexLock mu(self, lock_);
     ScopedCodeCacheWrite scc(code_map_.get());
     // Iterate over all compiled code and remove entries that are not marked.
-    for (auto it = jni_stubs_map_.begin(); it != jni_stubs_map_.end();) {
-      JniStubData* data = &it->second;
-      if (!data->IsCompiled() || GetLiveBitmap()->Test(FromCodeToAllocation(data->GetCode()))) {
-        ++it;
-      } else {
-        method_headers.insert(OatQuickMethodHeader::FromCodePointer(data->GetCode()));
-        it = jni_stubs_map_.erase(it);
-      }
-    }
     for (auto it = method_code_map_.begin(); it != method_code_map_.end();) {
       const void* code_ptr = it->first;
       uintptr_t allocation = FromCodeToAllocation(code_ptr);
       if (GetLiveBitmap()->Test(allocation)) {
         ++it;
       } else {
-        method_headers.insert(OatQuickMethodHeader::FromCodePointer(code_ptr));
+        method_headers.insert(OatQuickMethodHeader::FromCodePointer(it->first));
         it = method_code_map_.erase(it);
       }
     }
@@ -1339,17 +1158,6 @@
     // an entry point is either:
     // - an osr compiled code, that will be removed if not in a thread call stack.
     // - discarded compiled code, that will be removed if not in a thread call stack.
-    for (const auto& entry : jni_stubs_map_) {
-      const JniStubData& data = entry.second;
-      const void* code_ptr = data.GetCode();
-      const OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
-      for (ArtMethod* method : data.GetMethods()) {
-        if (method_header->GetEntryPoint() == method->GetEntryPointFromQuickCompiledCode()) {
-          GetLiveBitmap()->AtomicTestAndSet(FromCodeToAllocation(code_ptr));
-          break;
-        }
-      }
-    }
     for (const auto& it : method_code_map_) {
       ArtMethod* method = it.second;
       const void* code_ptr = it.first;
@@ -1429,51 +1237,19 @@
     return nullptr;
   }
 
-  if (!kIsDebugBuild) {
-    // Called with null `method` only from MarkCodeClosure::Run() in debug build.
-    CHECK(method != nullptr);
-  }
-
   MutexLock mu(Thread::Current(), lock_);
-  OatQuickMethodHeader* method_header = nullptr;
-  ArtMethod* found_method = nullptr;  // Only for DCHECK(), not for JNI stubs.
-  if (method != nullptr && UNLIKELY(method->IsNative())) {
-    auto it = jni_stubs_map_.find(JniStubKey(method));
-    if (it == jni_stubs_map_.end() || !ContainsElement(it->second.GetMethods(), method)) {
-      return nullptr;
-    }
-    const void* code_ptr = it->second.GetCode();
-    method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
-    if (!method_header->Contains(pc)) {
-      return nullptr;
-    }
-  } else {
-    auto it = method_code_map_.lower_bound(reinterpret_cast<const void*>(pc));
-    if (it != method_code_map_.begin()) {
-      --it;
-      const void* code_ptr = it->first;
-      if (OatQuickMethodHeader::FromCodePointer(code_ptr)->Contains(pc)) {
-        method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
-        found_method = it->second;
-      }
-    }
-    if (method_header == nullptr && method == nullptr) {
-      // Scan all compiled JNI stubs as well. This slow search is used only
-      // for checks in debug build, for release builds the `method` is not null.
-      for (auto&& entry : jni_stubs_map_) {
-        const JniStubData& data = entry.second;
-        if (data.IsCompiled() &&
-            OatQuickMethodHeader::FromCodePointer(data.GetCode())->Contains(pc)) {
-          method_header = OatQuickMethodHeader::FromCodePointer(data.GetCode());
-        }
-      }
-    }
-    if (method_header == nullptr) {
-      return nullptr;
-    }
+  if (method_code_map_.empty()) {
+    return nullptr;
   }
+  auto it = method_code_map_.lower_bound(reinterpret_cast<const void*>(pc));
+  --it;
 
-  if (kIsDebugBuild && method != nullptr && !method->IsNative()) {
+  const void* code_ptr = it->first;
+  OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
+  if (!method_header->Contains(pc)) {
+    return nullptr;
+  }
+  if (kIsDebugBuild && method != nullptr) {
     // When we are walking the stack to redefine classes and creating obsolete methods it is
     // possible that we might have updated the method_code_map by making this method obsolete in a
     // previous frame. Therefore we should just check that the non-obsolete version of this method
@@ -1482,9 +1258,9 @@
     // occur when we are in the process of allocating and setting up obsolete methods. Otherwise
     // method and it->second should be identical. (See openjdkjvmti/ti_redefine.cc for more
     // information.)
-    DCHECK_EQ(found_method->GetNonObsoleteMethod(), method->GetNonObsoleteMethod())
+    DCHECK_EQ(it->second->GetNonObsoleteMethod(), method->GetNonObsoleteMethod())
         << ArtMethod::PrettyMethod(method->GetNonObsoleteMethod()) << " "
-        << ArtMethod::PrettyMethod(found_method->GetNonObsoleteMethod()) << " "
+        << ArtMethod::PrettyMethod(it->second->GetNonObsoleteMethod()) << " "
         << std::hex << pc;
   }
   return method_header;
@@ -1673,51 +1449,21 @@
     return false;
   }
 
-  if (UNLIKELY(method->IsNative())) {
-    JniStubKey key(method);
-    auto it = jni_stubs_map_.find(key);
-    bool new_compilation = false;
-    if (it == jni_stubs_map_.end()) {
-      // Create a new entry to mark the stub as being compiled.
-      it = jni_stubs_map_.Put(key, JniStubData{});
-      new_compilation = true;
-    }
-    JniStubData* data = &it->second;
-    data->AddMethod(method);
-    if (data->IsCompiled()) {
-      OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(data->GetCode());
-      const void* entrypoint = method_header->GetEntryPoint();
-      // Update also entrypoints of other methods held by the JniStubData.
-      // We could simply update the entrypoint of `method` but if the last JIT GC has
-      // 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()) {
-        instrumentation->UpdateMethodsCode(m, entrypoint);
-      }
-      if (collection_in_progress_) {
-        GetLiveBitmap()->AtomicTestAndSet(FromCodeToAllocation(data->GetCode()));
-      }
-    }
-    return new_compilation;
-  } else {
-    ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
-    if (info == nullptr) {
-      VLOG(jit) << method->PrettyMethod() << " needs a ProfilingInfo to be compiled";
-      // Because the counter is not atomic, there are some rare cases where we may not hit the
-      // threshold for creating the ProfilingInfo. Reset the counter now to "correct" this.
-      ClearMethodCounter(method, /*was_warm*/ false);
-      return false;
-    }
-
-    if (info->IsMethodBeingCompiled(osr)) {
-      return false;
-    }
-
-    info->SetIsMethodBeingCompiled(true, osr);
-    return true;
+  ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
+  if (info == nullptr) {
+    VLOG(jit) << method->PrettyMethod() << " needs a ProfilingInfo to be compiled";
+    // Because the counter is not atomic, there are some rare cases where we may not hit the
+    // threshold for creating the ProfilingInfo. Reset the counter now to "correct" this.
+    ClearMethodCounter(method, /*was_warm*/ false);
+    return false;
   }
+
+  if (info->IsMethodBeingCompiled(osr)) {
+    return false;
+  }
+
+  info->SetIsMethodBeingCompiled(true, osr);
+  return true;
 }
 
 ProfilingInfo* JitCodeCache::NotifyCompilerUse(ArtMethod* method, Thread* self) {
@@ -1739,23 +1485,10 @@
   info->DecrementInlineUse();
 }
 
-void JitCodeCache::DoneCompiling(ArtMethod* method, Thread* self, bool osr) {
-  DCHECK_EQ(Thread::Current(), self);
-  MutexLock mu(self, lock_);
-  if (UNLIKELY(method->IsNative())) {
-    auto it = jni_stubs_map_.find(JniStubKey(method));
-    DCHECK(it != jni_stubs_map_.end());
-    JniStubData* data = &it->second;
-    DCHECK(ContainsElement(data->GetMethods(), method));
-    if (UNLIKELY(!data->IsCompiled())) {
-      // Failed to compile; the JNI compiler never fails, but the cache may be full.
-      jni_stubs_map_.erase(it);  // Remove the entry added in NotifyCompilationOf().
-    }  // else CommitCodeInternal() updated entrypoints of all methods in the JniStubData.
-  } else {
-    ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
-    DCHECK(info->IsMethodBeingCompiled(osr));
-    info->SetIsMethodBeingCompiled(false, osr);
-  }
+void JitCodeCache::DoneCompiling(ArtMethod* method, Thread* self ATTRIBUTE_UNUSED, bool osr) {
+  ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
+  DCHECK(info->IsMethodBeingCompiled(osr));
+  info->SetIsMethodBeingCompiled(false, osr);
 }
 
 size_t JitCodeCache::GetMemorySizeOfCodePointer(const void* ptr) {
@@ -1765,7 +1498,6 @@
 
 void JitCodeCache::InvalidateCompiledCodeFor(ArtMethod* method,
                                              const OatQuickMethodHeader* header) {
-  DCHECK(!method->IsNative());
   ProfilingInfo* profiling_info = method->GetProfilingInfo(kRuntimePointerSize);
   if ((profiling_info != nullptr) &&
       (profiling_info->GetSavedEntryPoint() == header->GetEntryPoint())) {
@@ -1821,7 +1553,6 @@
   os << "Current JIT code cache size: " << PrettySize(used_memory_for_code_) << "\n"
      << "Current JIT data cache size: " << PrettySize(used_memory_for_data_) << "\n"
      << "Current JIT capacity: " << PrettySize(current_capacity_) << "\n"
-     << "Current number of JIT JNI stub entries: " << jni_stubs_map_.size() << "\n"
      << "Current number of JIT code cache entries: " << method_code_map_.size() << "\n"
      << "Total number of JIT compilations: " << number_of_compilations_ << "\n"
      << "Total number of JIT compilations for on stack replacement: "
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index fc011dd..46a4085 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -35,23 +35,9 @@
 class LinearAlloc;
 class InlineCache;
 class IsMarkedVisitor;
-class JitJniStubTestHelper;
 class OatQuickMethodHeader;
 struct ProfileMethodInfo;
 class ProfilingInfo;
-class Thread;
-
-namespace gc {
-namespace accounting {
-template<size_t kAlignment> class MemoryRangeBitmap;
-}  // namespace accounting
-}  // namespace gc
-
-namespace mirror {
-class Class;
-class Object;
-template<class T> class ObjectArray;
-}  // namespace mirror
 
 namespace gc {
 namespace accounting {
@@ -151,9 +137,6 @@
   // Return true if the code cache contains this method.
   bool ContainsMethod(ArtMethod* method) REQUIRES(!lock_);
 
-  // Return the code pointer for a JNI-compiled stub if the method is in the cache, null otherwise.
-  const void* GetJniStubCode(ArtMethod* method) REQUIRES(!lock_);
-
   // Allocate a region of data that contain `size` bytes, and potentially space
   // for storing `number_of_roots` roots. Returns null if there is no more room.
   // Return the number of bytes allocated.
@@ -177,6 +160,11 @@
     return live_bitmap_.get();
   }
 
+  // Return whether we should do a full collection given the current state of the cache.
+  bool ShouldDoFullCollection()
+      REQUIRES(lock_)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Perform a collection on the code cache.
   void GarbageCollectCache(Thread* self)
       REQUIRES(!lock_)
@@ -308,12 +296,6 @@
       REQUIRES(!lock_)
       REQUIRES(!Locks::cha_lock_);
 
-  // Removes method from the cache. The caller must ensure that all threads
-  // are suspended and the method should not be in any thread's stack.
-  bool RemoveMethodLocked(ArtMethod* method, bool release_memory)
-      REQUIRES(lock_)
-      REQUIRES(Locks::mutator_lock_);
-
   // Free in the mspace allocations for `code_ptr`.
   void FreeCode(const void* code_ptr) REQUIRES(lock_);
 
@@ -333,11 +315,6 @@
   // Set the footprint limit of the code cache.
   void SetFootprintLimit(size_t new_footprint) REQUIRES(lock_);
 
-  // Return whether we should do a full collection given the current state of the cache.
-  bool ShouldDoFullCollection()
-      REQUIRES(lock_)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   void DoCollection(Thread* self, bool collect_profiling_info)
       REQUIRES(!lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
@@ -364,9 +341,6 @@
       REQUIRES(!lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  class JniStubKey;
-  class JniStubData;
-
   // Lock for guarding allocations, collections, and the method_code_map_.
   Mutex lock_;
   // Condition to wait on during collection.
@@ -383,8 +357,6 @@
   void* data_mspace_ GUARDED_BY(lock_);
   // Bitmap for collecting code and data.
   std::unique_ptr<CodeCacheBitmap> live_bitmap_;
-  // Holds compiled code associated with the shorty for a JNI stub.
-  SafeMap<JniStubKey, JniStubData> jni_stubs_map_ GUARDED_BY(lock_);
   // Holds compiled code associated to the ArtMethod.
   SafeMap<const void*, ArtMethod*> method_code_map_ GUARDED_BY(lock_);
   // Holds osr compiled code associated to the ArtMethod.
@@ -446,7 +418,6 @@
   // Condition to wait on for accessing inline caches.
   ConditionVariable inline_cache_cond_ GUARDED_BY(lock_);
 
-  friend class art::JitJniStubTestHelper;
   DISALLOW_IMPLICIT_CONSTRUCTORS(JitCodeCache);
 };
 
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index acbc6e6..01853de 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -357,8 +357,8 @@
             sampled_methods->AddReference(method.GetDexFile(), method.GetDexMethodIndex());
           }
         } else {
-          // We do not record native methods. Once we AOT-compile the app, all native
-          // methods shall have their thunks compiled.
+          CHECK_EQ(method.GetCounter(), 0u) << method.PrettyMethod()
+              << " access_flags=" << method.GetAccessFlags();
         }
       }
     }
diff --git a/runtime/managed_stack-inl.h b/runtime/managed_stack-inl.h
index 678be8e..689dd80 100644
--- a/runtime/managed_stack-inl.h
+++ b/runtime/managed_stack-inl.h
@@ -24,7 +24,7 @@
 namespace art {
 
 inline ShadowFrame* ManagedStack::PushShadowFrame(ShadowFrame* new_top_frame) {
-  DCHECK(!HasTopQuickFrame());
+  DCHECK(top_quick_frame_ == nullptr);
   ShadowFrame* old_frame = top_shadow_frame_;
   top_shadow_frame_ = new_top_frame;
   new_top_frame->SetLink(old_frame);
@@ -32,7 +32,7 @@
 }
 
 inline ShadowFrame* ManagedStack::PopShadowFrame() {
-  DCHECK(!HasTopQuickFrame());
+  DCHECK(top_quick_frame_ == nullptr);
   CHECK(top_shadow_frame_ != nullptr);
   ShadowFrame* frame = top_shadow_frame_;
   top_shadow_frame_ = frame->GetLink();
diff --git a/runtime/managed_stack.h b/runtime/managed_stack.h
index 07078ec..4f1984d 100644
--- a/runtime/managed_stack.h
+++ b/runtime/managed_stack.h
@@ -24,7 +24,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "base/bit_utils.h"
 
 namespace art {
 
@@ -43,9 +42,7 @@
 class PACKED(4) ManagedStack {
  public:
   ManagedStack()
-      : tagged_top_quick_frame_(TaggedTopQuickFrame::CreateNotTagged(nullptr)),
-        link_(nullptr),
-        top_shadow_frame_(nullptr) {}
+      : top_quick_frame_(nullptr), link_(nullptr), top_shadow_frame_(nullptr) {}
 
   void PushManagedStackFragment(ManagedStack* fragment) {
     // Copy this top fragment into given fragment.
@@ -66,36 +63,17 @@
     return link_;
   }
 
-  ArtMethod** GetTopQuickFrameKnownNotTagged() const {
-    return tagged_top_quick_frame_.GetSpKnownNotTagged();
-  }
-
   ArtMethod** GetTopQuickFrame() const {
-    return tagged_top_quick_frame_.GetSp();
-  }
-
-  bool GetTopQuickFrameTag() const {
-    return tagged_top_quick_frame_.GetTag();
-  }
-
-  bool HasTopQuickFrame() const {
-    return tagged_top_quick_frame_.GetTaggedSp() != 0u;
+    return top_quick_frame_;
   }
 
   void SetTopQuickFrame(ArtMethod** top) {
     DCHECK(top_shadow_frame_ == nullptr);
-    DCHECK_ALIGNED(top, 4u);
-    tagged_top_quick_frame_ = TaggedTopQuickFrame::CreateNotTagged(top);
+    top_quick_frame_ = top;
   }
 
-  void SetTopQuickFrameTagged(ArtMethod** top) {
-    DCHECK(top_shadow_frame_ == nullptr);
-    DCHECK_ALIGNED(top, 4u);
-    tagged_top_quick_frame_ = TaggedTopQuickFrame::CreateTagged(top);
-  }
-
-  static size_t TaggedTopQuickFrameOffset() {
-    return OFFSETOF_MEMBER(ManagedStack, tagged_top_quick_frame_);
+  static size_t TopQuickFrameOffset() {
+    return OFFSETOF_MEMBER(ManagedStack, top_quick_frame_);
   }
 
   ALWAYS_INLINE ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame);
@@ -105,12 +83,8 @@
     return top_shadow_frame_;
   }
 
-  bool HasTopShadowFrame() const {
-    return GetTopShadowFrame() != nullptr;
-  }
-
   void SetTopShadowFrame(ShadowFrame* top) {
-    DCHECK_EQ(tagged_top_quick_frame_.GetTaggedSp(), 0u);
+    DCHECK(top_quick_frame_ == nullptr);
     top_shadow_frame_ = top;
   }
 
@@ -123,47 +97,7 @@
   bool ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const;
 
  private:
-  // Encodes the top quick frame (which must be at least 4-byte aligned)
-  // and a flag that marks the GenericJNI trampoline.
-  class TaggedTopQuickFrame {
-   public:
-    static TaggedTopQuickFrame CreateNotTagged(ArtMethod** sp) {
-      DCHECK_ALIGNED(sp, 4u);
-      return TaggedTopQuickFrame(reinterpret_cast<uintptr_t>(sp));
-    }
-
-    static TaggedTopQuickFrame CreateTagged(ArtMethod** sp) {
-      DCHECK_ALIGNED(sp, 4u);
-      return TaggedTopQuickFrame(reinterpret_cast<uintptr_t>(sp) | 1u);
-    }
-
-    // Get SP known to be not tagged and non-null.
-    ArtMethod** GetSpKnownNotTagged() const {
-      DCHECK(!GetTag());
-      DCHECK_NE(tagged_sp_, 0u);
-      return reinterpret_cast<ArtMethod**>(tagged_sp_);
-    }
-
-    ArtMethod** GetSp() const {
-      return reinterpret_cast<ArtMethod**>(tagged_sp_ & ~static_cast<uintptr_t>(1u));
-    }
-
-    bool GetTag() const {
-      return (tagged_sp_ & 1u) != 0u;
-    }
-
-    uintptr_t GetTaggedSp() const {
-      return tagged_sp_;
-    }
-
-   private:
-    explicit TaggedTopQuickFrame(uintptr_t tagged_sp) : tagged_sp_(tagged_sp) { }
-
-    uintptr_t tagged_sp_;
-  };
-  static_assert(sizeof(TaggedTopQuickFrame) == sizeof(uintptr_t), "TaggedTopQuickFrame size check");
-
-  TaggedTopQuickFrame tagged_top_quick_frame_;
+  ArtMethod** top_quick_frame_;
   ManagedStack* link_;
   ShadowFrame* top_shadow_frame_;
 };
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 5ad1f7c..ab9fb0d 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -735,19 +735,12 @@
     return runtime->GetCalleeSaveMethodFrameInfo(CalleeSaveType::kSaveRefsAndArgs);
   }
 
-  // The only remaining case is if the method is native and uses the generic JNI stub,
-  // called either directly or through some (resolution, instrumentation) trampoline.
+  // The only remaining case is if the method is native and uses the generic JNI stub.
   DCHECK(method->IsNative());
-  if (kIsDebugBuild) {
-    ClassLinker* class_linker = runtime->GetClassLinker();
-    const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(method,
-                                                                             kRuntimePointerSize);
-    CHECK(class_linker->IsQuickGenericJniStub(entry_point) ||
-          // The current entrypoint (after filtering out trampolines) may have changed
-          // from GenericJNI to JIT-compiled stub since we have entered this frame.
-          (runtime->GetJit() != nullptr &&
-           runtime->GetJit()->GetCodeCache()->ContainsPc(entry_point))) << method->PrettyMethod();
-  }
+  ClassLinker* class_linker = runtime->GetClassLinker();
+  const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(method,
+                                                                           kRuntimePointerSize);
+  DCHECK(class_linker->IsQuickGenericJniStub(entry_point)) << method->PrettyMethod();
   // Generic JNI frame.
   uint32_t handle_refs = GetNumberOfReferenceArgsWithoutReceiver(method) + 1;
   size_t scope_size = HandleScope::SizeOf(handle_refs);
@@ -783,48 +776,8 @@
       // Can't be both a shadow and a quick fragment.
       DCHECK(current_fragment->GetTopShadowFrame() == nullptr);
       ArtMethod* method = *cur_quick_frame_;
-      DCHECK(method != nullptr);
-      bool header_retrieved = false;
-      if (method->IsNative()) {
-        // We do not have a PC for the first frame, so we cannot simply use
-        // ArtMethod::GetOatQuickMethodHeader() as we're unable to distinguish there
-        // between GenericJNI frame and JIT-compiled JNI stub; the entrypoint may have
-        // changed since the frame was entered. The top quick frame tag indicates
-        // GenericJNI here, otherwise it's either AOT-compiled or JNI-compiled JNI stub.
-        if (UNLIKELY(current_fragment->GetTopQuickFrameTag())) {
-          // The generic JNI does not have any method header.
-          cur_oat_quick_method_header_ = nullptr;
-        } else {
-          const void* existing_entry_point = method->GetEntryPointFromQuickCompiledCode();
-          CHECK(existing_entry_point != nullptr);
-          Runtime* runtime = Runtime::Current();
-          ClassLinker* class_linker = runtime->GetClassLinker();
-          // Check whether we can quickly get the header from the current entrypoint.
-          if (!class_linker->IsQuickGenericJniStub(existing_entry_point) &&
-              !class_linker->IsQuickResolutionStub(existing_entry_point) &&
-              existing_entry_point != GetQuickInstrumentationEntryPoint()) {
-            cur_oat_quick_method_header_ =
-                OatQuickMethodHeader::FromEntryPoint(existing_entry_point);
-          } else {
-            const void* code = method->GetOatMethodQuickCode(class_linker->GetImagePointerSize());
-            if (code != nullptr) {
-              cur_oat_quick_method_header_ = OatQuickMethodHeader::FromEntryPoint(code);
-            } else {
-              // This must be a JITted JNI stub frame.
-              CHECK(runtime->GetJit() != nullptr);
-              code = runtime->GetJit()->GetCodeCache()->GetJniStubCode(method);
-              CHECK(code != nullptr) << method->PrettyMethod();
-              cur_oat_quick_method_header_ = OatQuickMethodHeader::FromCodePointer(code);
-            }
-          }
-        }
-        header_retrieved = true;
-      }
       while (method != nullptr) {
-        if (!header_retrieved) {
-          cur_oat_quick_method_header_ = method->GetOatQuickMethodHeader(cur_quick_frame_pc_);
-        }
-        header_retrieved = false;  // Force header retrieval in next iteration.
+        cur_oat_quick_method_header_ = method->GetOatQuickMethodHeader(cur_quick_frame_pc_);
         SanityCheckFrame();
 
         if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames)
diff --git a/runtime/stack.h b/runtime/stack.h
index a16930b..bd6204f 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -140,7 +140,8 @@
   };
 
   template <CountTransitions kCount = CountTransitions::kYes>
-  void WalkStack(bool include_transitions = false) REQUIRES_SHARED(Locks::mutator_lock_);
+  void WalkStack(bool include_transitions = false)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   Thread* GetThread() const {
     return thread_;
diff --git a/runtime/thread.cc b/runtime/thread.cc
index bec1c90..712eabc 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1884,7 +1884,9 @@
   }
 
   // Threads with no managed stack frames should be shown.
-  if (!thread->HasManagedStack()) {
+  const ManagedStack* managed_stack = thread->GetManagedStack();
+  if (managed_stack == nullptr || (managed_stack->GetTopQuickFrame() == nullptr &&
+      managed_stack->GetTopShadowFrame() == nullptr)) {
     return true;
   }
 
diff --git a/runtime/thread.h b/runtime/thread.h
index 0803975..39be66d 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -474,16 +474,13 @@
     tlsPtr_.managed_stack.SetTopQuickFrame(top_method);
   }
 
-  void SetTopOfStackTagged(ArtMethod** top_method) {
-    tlsPtr_.managed_stack.SetTopQuickFrameTagged(top_method);
-  }
-
   void SetTopOfShadowStack(ShadowFrame* top) {
     tlsPtr_.managed_stack.SetTopShadowFrame(top);
   }
 
   bool HasManagedStack() const {
-    return tlsPtr_.managed_stack.HasTopQuickFrame() || tlsPtr_.managed_stack.HasTopShadowFrame();
+    return (tlsPtr_.managed_stack.GetTopQuickFrame() != nullptr) ||
+        (tlsPtr_.managed_stack.GetTopShadowFrame() != nullptr);
   }
 
   // If 'msg' is null, no detail message is set.
@@ -836,7 +833,7 @@
   static ThreadOffset<pointer_size> TopOfManagedStackOffset() {
     return ThreadOffsetFromTlsPtr<pointer_size>(
         OFFSETOF_MEMBER(tls_ptr_sized_values, managed_stack) +
-        ManagedStack::TaggedTopQuickFrameOffset());
+        ManagedStack::TopQuickFrameOffset());
   }
 
   const ManagedStack* GetManagedStack() const {
diff --git a/test/655-jit-clinit/src/Main.java b/test/655-jit-clinit/src/Main.java
index 2fb8f2a..44b3154 100644
--- a/test/655-jit-clinit/src/Main.java
+++ b/test/655-jit-clinit/src/Main.java
@@ -23,7 +23,7 @@
     Foo.hotMethod();
   }
 
-  public native static boolean hasJitCompiledEntrypoint(Class<?> cls, String methodName);
+  public native static boolean isJitCompiled(Class<?> cls, String methodName);
   private native static boolean hasJit();
 }
 
@@ -36,7 +36,7 @@
 
   static {
     array = new Object[10000];
-    while (!Main.hasJitCompiledEntrypoint(Foo.class, "hotMethod")) {
+    while (!Main.isJitCompiled(Foo.class, "hotMethod")) {
       Foo.hotMethod();
       try {
         // Sleep to give a chance for the JIT to compile `hotMethod`.
diff --git a/test/667-jit-jni-stub/expected.txt b/test/667-jit-jni-stub/expected.txt
deleted file mode 100644
index 6a5618e..0000000
--- a/test/667-jit-jni-stub/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-JNI_OnLoad called
diff --git a/test/667-jit-jni-stub/info.txt b/test/667-jit-jni-stub/info.txt
deleted file mode 100644
index 6f25c44..0000000
--- a/test/667-jit-jni-stub/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Tests for JITting and collecting JNI stubs.
diff --git a/test/667-jit-jni-stub/jit_jni_stub_test.cc b/test/667-jit-jni-stub/jit_jni_stub_test.cc
deleted file mode 100644
index 82e06fc..0000000
--- a/test/667-jit-jni-stub/jit_jni_stub_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2017 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 <jni.h>
-
-#include "jit/jit.h"
-#include "jit/jit_code_cache.h"
-#include "mirror/class.h"
-#include "mirror/string.h"
-#include "runtime.h"
-#include "scoped_thread_state_change-inl.h"
-
-namespace art {
-
-// Local class declared as a friend of JitCodeCache so that we can access its internals.
-class JitJniStubTestHelper {
- public:
-  static bool isNextJitGcFull(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
-    CHECK(Runtime::Current()->GetJit() != nullptr);
-    jit::JitCodeCache* cache = Runtime::Current()->GetJit()->GetCodeCache();
-    MutexLock mu(self, cache->lock_);
-    return cache->ShouldDoFullCollection();
-  }
-};
-
-// Calls through to a static method with signature "()V".
-extern "C" JNIEXPORT
-void Java_Main_callThrough(JNIEnv* env, jclass, jclass klass, jstring methodName) {
-  ScopedObjectAccess soa(Thread::Current());
-  std::string name = soa.Decode<mirror::String>(methodName)->ToModifiedUtf8();
-  jmethodID method = env->GetStaticMethodID(klass, name.c_str(), "()V");
-  CHECK(method != nullptr) << soa.Decode<mirror::Class>(klass)->PrettyDescriptor() << "." << name;
-  env->CallStaticVoidMethod(klass, method);
-}
-
-extern "C" JNIEXPORT
-void Java_Main_jitGc(JNIEnv*, jclass) {
-  CHECK(Runtime::Current()->GetJit() != nullptr);
-  jit::JitCodeCache* cache = Runtime::Current()->GetJit()->GetCodeCache();
-  ScopedObjectAccess soa(Thread::Current());
-  cache->GarbageCollectCache(Thread::Current());
-}
-
-extern "C" JNIEXPORT
-jboolean Java_Main_isNextJitGcFull(JNIEnv*, jclass) {
-  ScopedObjectAccess soa(Thread::Current());
-  return JitJniStubTestHelper::isNextJitGcFull(soa.Self());
-}
-
-}  // namespace art
diff --git a/test/667-jit-jni-stub/run b/test/667-jit-jni-stub/run
deleted file mode 100755
index 1877be4..0000000
--- a/test/667-jit-jni-stub/run
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 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.
-
-# Disable AOT compilation of JNI stubs.
-${RUN} "${@}" --no-prebuild --no-dex2oat
diff --git a/test/667-jit-jni-stub/src/Main.java b/test/667-jit-jni-stub/src/Main.java
deleted file mode 100644
index b867970..0000000
--- a/test/667-jit-jni-stub/src/Main.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2017 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]);
-    if (isAotCompiled(Main.class, "hasJit")) {
-      throw new Error("This test must be run with --no-prebuild --no-dex2oat!");
-    }
-    if (!hasJit()) {
-      return;
-    }
-
-    testCompilationUseAndCollection();
-    testMixedFramesOnStack();
-  }
-
-  public static void testCompilationUseAndCollection() {
-    // Test that callThrough() can be JIT-compiled.
-    assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-    assertFalse(hasJitCompiledCode(Main.class, "callThrough"));
-    ensureCompiledCallThroughEntrypoint(/* call */ true);
-    assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-    assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
-
-    // Use callThrough() once again now that the method has a JIT-compiled stub.
-    callThrough(Main.class, "doNothing");
-
-    // Test that GC with the JIT-compiled stub on the stack does not collect it.
-    // Also tests stack walk over the JIT-compiled stub.
-    callThrough(Main.class, "testGcWithCallThroughStubOnStack");
-
-    // Test that, when marking used methods before a full JIT GC, a single execution
-    // of the GenericJNI trampoline can save the compiled stub from being collected.
-    testSingleInvocationTriggersRecompilation();
-
-    // Test that the JNI compiled stub can actually be collected.
-    testStubCanBeCollected();
-  }
-
-  public static void testGcWithCallThroughStubOnStack() {
-    // Check that this method was called via JIT-compiled callThrough() stub.
-    assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-    // This assertion also exercises stack walk over the JIT-compiled callThrough() stub.
-    assertTrue(new Throwable().getStackTrace()[1].getMethodName().equals("callThrough"));
-
-    doJitGcsUntilFullJitGcIsScheduled();
-    // The callThrough() on the stack above this method is using the compiled stub,
-    // so the JIT GC should not remove the compiled code.
-    jitGc();
-    assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
-  }
-
-  public static void testSingleInvocationTriggersRecompilation() {
-    // After scheduling a full JIT GC, single call through the GenericJNI
-    // trampoline should ensure that the compiled stub is used again.
-    doJitGcsUntilFullJitGcIsScheduled();
-    callThrough(Main.class, "doNothing");
-    ensureCompiledCallThroughEntrypoint(/* call */ false);  // Wait for the compilation task to run.
-    assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-    jitGc();  // This JIT GC should not collect the callThrough() stub.
-    assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
-  }
-
-  public static void testMixedFramesOnStack() {
-    // Starts without a compiled JNI stub for callThrough().
-    assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-    assertFalse(hasJitCompiledCode(Main.class, "callThrough"));
-    callThrough(Main.class, "testMixedFramesOnStackStage2");
-    // We have just returned through the JIT-compiled JNI stub, so it must still
-    // be compiled (though not necessarily with the entrypoint pointing to it).
-    assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
-    // Though the callThrough() is on the stack, that frame is using the GenericJNI
-    // and does not prevent the collection of the JNI stub.
-    testStubCanBeCollected();
-  }
-
-  public static void testMixedFramesOnStackStage2() {
-    // We cannot assert that callThrough() has no JIT compiled stub as that check
-    // may race against the compilation task. Just check the caller.
-    assertTrue(new Throwable().getStackTrace()[1].getMethodName().equals("callThrough"));
-    // Now ensure that the JNI stub is compiled and used.
-    ensureCompiledCallThroughEntrypoint(/* call */ true);
-    callThrough(Main.class, "testMixedFramesOnStackStage3");
-  }
-
-  public static void testMixedFramesOnStackStage3() {
-    // Check that this method was called via JIT-compiled callThrough() stub.
-    assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-    // This assertion also exercises stack walk over the JIT-compiled callThrough() stub.
-    assertTrue(new Throwable().getStackTrace()[1].getMethodName().equals("callThrough"));
-    // For a good measure, try a JIT GC.
-    jitGc();
-  }
-
-  public static void testStubCanBeCollected() {
-    assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
-    doJitGcsUntilFullJitGcIsScheduled();
-    assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-    assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
-    jitGc();  // JIT GC without callThrough() on the stack should collect the callThrough() stub.
-    assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-    assertFalse(hasJitCompiledCode(Main.class, "callThrough"));
-  }
-
-  public static void doJitGcsUntilFullJitGcIsScheduled() {
-    // We enter with a compiled stub for callThrough() but we also need the entrypoint to be set.
-    assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
-    ensureCompiledCallThroughEntrypoint(/* call */ true);
-    // Perform JIT GC until the next GC is marked to do full collection.
-    do {
-      assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-      callThrough(Main.class, "jitGc");  // JIT GC with callThrough() safely on the stack.
-    } while (!isNextJitGcFull());
-    // The JIT GC before the full collection resets entrypoints and waits to see
-    // if the methods are still in use.
-    assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));
-    assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
-  }
-
-  public static void ensureCompiledCallThroughEntrypoint(boolean call) {
-    int count = 0;
-    while (!hasJitCompiledEntrypoint(Main.class, "callThrough")) {
-      // If `call` is true, also exercise the `callThrough()` method to increase hotness.
-      int limit = call ? 1 << Math.min(count, 12) : 0;
-      for (int i = 0; i < limit; ++i) {
-        callThrough(Main.class, "doNothing");
-      }
-      try {
-        // Sleep to give a chance for the JIT to compile `hasJit` stub.
-        Thread.sleep(100);
-      } catch (Exception e) {
-        // Ignore
-      }
-      if (++count == 50) {
-        throw new Error("TIMEOUT");
-      }
-    };
-  }
-
-  public static void assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected true!");
-    }
-  }
-
-  public static void assertFalse(boolean value) {
-    if (value) {
-      throw new AssertionError("Expected false!");
-    }
-  }
-
-  public static void doNothing() { }
-  public static void throwError() { throw new Error(); }
-
-  // Note that the callThrough()'s shorty differs from shorties of the other
-  // native methods used in this test because of the return type `void.`
-  public native static void callThrough(Class<?> cls, String methodName);
-
-  public native static void jitGc();
-  public native static boolean isNextJitGcFull();
-
-  public native static boolean isAotCompiled(Class<?> cls, String methodName);
-  public native static boolean hasJitCompiledEntrypoint(Class<?> cls, String methodName);
-  public native static boolean hasJitCompiledCode(Class<?> cls, String methodName);
-  private native static boolean hasJit();
-}
diff --git a/test/Android.bp b/test/Android.bp
index 2d526d2..8f29251 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -384,7 +384,6 @@
         "656-annotation-lookup-generic-jni/test.cc",
         "661-oat-writer-layout/oat_writer_layout.cc",
         "664-aget-verifier/aget-verifier.cc",
-        "667-jit-jni-stub/jit_jni_stub_test.cc",
         "708-jit-cache-churn/jit.cc",
     ],
     shared_libs: [
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 3458080..df497c1 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -152,10 +152,10 @@
   return method->GetOatMethodQuickCode(kRuntimePointerSize) != nullptr;
 }
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledEntrypoint(JNIEnv* env,
-                                                                         jclass,
-                                                                         jclass cls,
-                                                                         jstring method_name) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isJitCompiled(JNIEnv* env,
+                                                              jclass,
+                                                              jclass cls,
+                                                              jstring method_name) {
   jit::Jit* jit = GetJitIfEnabled();
   if (jit == nullptr) {
     return false;
@@ -169,23 +169,6 @@
   return jit->GetCodeCache()->ContainsPc(method->GetEntryPointFromQuickCompiledCode());
 }
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledCode(JNIEnv* env,
-                                                                   jclass,
-                                                                   jclass cls,
-                                                                   jstring method_name) {
-  jit::Jit* jit = GetJitIfEnabled();
-  if (jit == nullptr) {
-    return false;
-  }
-  Thread* self = Thread::Current();
-  ScopedObjectAccess soa(self);
-  ScopedUtfChars chars(env, method_name);
-  CHECK(chars.c_str() != nullptr);
-  ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
-        chars.c_str(), kRuntimePointerSize);
-  return jit->GetCodeCache()->ContainsMethod(method);
-}
-
 extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
                                                              jclass,
                                                              jclass cls,