changeset 59737:ac646e22b4df

8245113: JFR Recorder Thread to run in thread state "_thread_in_native" Reviewed-by: egahlin
author mgronlun
date Thu, 11 Jun 2020 10:48:35 +0200
parents 5b7835c33b4d
children f88f43024fe0
files src/hotspot/share/jfr/jni/jfrJavaSupport.cpp src/hotspot/share/jfr/jni/jfrJniMethod.cpp src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp src/hotspot/share/jfr/recorder/repository/jfrChunkRotation.cpp src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp src/hotspot/share/jfr/utilities/jfrConcurrentLinkedListHost.hpp src/hotspot/share/jfr/utilities/jfrConcurrentLinkedListHost.inline.hpp src/hotspot/share/jfr/utilities/jfrVersionSystem.inline.hpp
diffstat 14 files changed, 154 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -723,18 +723,20 @@
   return true;
 }
 
-jlong JfrJavaSupport::jfr_thread_id(jobject thread) {
+static JavaThread* get_native(jobject thread) {
   ThreadsListHandle tlh;
   JavaThread* native_thread = NULL;
   (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
+  return native_thread;
+}
+
+jlong JfrJavaSupport::jfr_thread_id(jobject thread) {
+  JavaThread* native_thread = get_native(thread);
   return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0;
 }
 
 void JfrJavaSupport::exclude(jobject thread) {
-  HandleMark hm;
-  ThreadsListHandle tlh;
-  JavaThread* native_thread = NULL;
-  (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
+  JavaThread* native_thread = get_native(thread);
   if (native_thread != NULL) {
     JfrThreadLocal::exclude(native_thread);
   } else {
@@ -744,10 +746,7 @@
 }
 
 void JfrJavaSupport::include(jobject thread) {
-  HandleMark hm;
-  ThreadsListHandle tlh;
-  JavaThread* native_thread = NULL;
-  (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
+  JavaThread* native_thread = get_native(thread);
   if (native_thread != NULL) {
     JfrThreadLocal::include(native_thread);
   } else {
@@ -757,10 +756,7 @@
 }
 
 bool JfrJavaSupport::is_excluded(jobject thread) {
-  HandleMark hm;
-  ThreadsListHandle tlh;
-  JavaThread* native_thread = NULL;
-  (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);
+  JavaThread* native_thread = get_native(thread);
   return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread);
 }
 
--- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -179,6 +179,12 @@
   return JfrChunkRotation::should_rotate() ? JNI_TRUE : JNI_FALSE;
 NO_TRANSITION_END
 
+NO_TRANSITION(jlong, jfr_get_type_id_from_string(JNIEnv * env, jobject jvm, jstring type))
+  const char* type_name = env->GetStringUTFChars(type, NULL);
+  jlong id = JfrType::name_to_id(type_name);
+  env->ReleaseStringUTFChars(type, type_name);
+  return id;
+NO_TRANSITION_END
 /*
  * JVM_ENTRY_NO_ENV entries
  *
@@ -350,11 +356,3 @@
 JVM_ENTRY_NO_ENV(jboolean, jfr_set_handler(JNIEnv * env, jobject jvm, jobject clazz, jobject handler))
   return JfrJavaSupport::set_handler(clazz, handler, thread);
 JVM_END
-
-NO_TRANSITION(jlong, jfr_get_type_id_from_string(JNIEnv * env, jobject jvm, jstring type))
-  const char* type_name= env->GetStringUTFChars(type, NULL);
-  jlong id = JfrType::name_to_id(type_name);
-  env->ReleaseStringUTFChars(type, type_name);
-  return id;
-NO_TRANSITION_END
-
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "jfr/jfrEvents.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
 #include "jfr/leakprofiler/chains/edgeStore.hpp"
 #include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
@@ -40,10 +41,12 @@
 #include "jfr/utilities/jfrHashtable.hpp"
 #include "jfr/utilities/jfrPredicate.hpp"
 #include "jfr/utilities/jfrRelation.hpp"
+#include "memory/resourceArea.inline.hpp"
 #include "oops/instanceKlass.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/safepoint.hpp"
-#include "runtime/thread.hpp"
+#include "runtime/thread.inline.hpp"
 
 const int initial_array_size = 64;
 
@@ -248,17 +251,21 @@
   assert(sampler != NULL, "invariant");
   const ObjectSample* const last = sampler->last();
   if (last != sampler->last_resolved()) {
+    ResourceMark rm;
     JfrKlassUnloading::sort();
     StackTraceBlobInstaller installer(stack_trace_repo);
     iterate_samples(installer);
   }
 }
 
-// caller needs ResourceMark
 void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) {
   assert(JfrStream_lock->owned_by_self(), "invariant");
   assert(sampler != NULL, "invariant");
   assert(LeakProfiler::is_running(), "invariant");
+  Thread* const thread = Thread::current();
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread);)
+  // can safepoint here
+  ThreadInVMfromNative transition((JavaThread*)thread);
   MutexLocker lock(ClassLoaderDataGraph_lock);
   // the lock is needed to ensure the unload lists do not grow in the middle of inspection.
   install_stack_traces(sampler, stack_trace_repo);
@@ -416,6 +423,7 @@
 
 void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
   assert(LeakProfiler::is_running(), "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(Thread::current());)
   const ObjectSample* last = ObjectSampler::sampler()->last();
   if (writer.has_data() && last != NULL) {
     save_type_set_blob(writer);
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/javaClasses.inline.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
 #include "jfr/leakprofiler/leakProfiler.hpp"
 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
@@ -48,6 +49,7 @@
 #include "memory/resourceArea.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/handles.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/mutex.hpp"
 #include "runtime/os.inline.hpp"
 #include "runtime/safepoint.hpp"
@@ -325,6 +327,7 @@
 }
 
 size_t JfrCheckpointManager::write() {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
   assert(_mspace->free_list_is_empty(), "invariant");
   WriteOperation wo(_chunkwriter);
   MutexedWriteOperation mwo(wo);
@@ -357,6 +360,11 @@
 
 size_t JfrCheckpointManager::write_threads(Thread* thread) {
   assert(thread != NULL, "invariant");
+  // can safepoint here
+  ThreadInVMfromNative transition((JavaThread*)thread);
+  ResetNoHandleMark rnhm;
+  ResourceMark rm(thread);
+  HandleMark hm(thread);
   JfrCheckpointWriter writer(true, thread, THREADS);
   JfrTypeManager::write_threads(writer);
   return writer.used_size();
@@ -364,8 +372,7 @@
 
 size_t JfrCheckpointManager::write_static_type_set_and_threads() {
   Thread* const thread = Thread::current();
-  ResourceMark rm(thread);
-  HandleMark hm(thread);
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread));
   write_static_type_set(thread);
   write_threads(thread);
   return write();
@@ -380,7 +387,11 @@
 void JfrCheckpointManager::clear_type_set() {
   assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
   assert(!JfrRecorder::is_recording(), "invariant");
+  Thread* t = Thread::current();
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(t));
   // can safepoint here
+  ThreadInVMfromNative transition((JavaThread*)t);
+  ResetNoHandleMark rnhm;
   MutexLocker cld_lock(ClassLoaderDataGraph_lock);
   MutexLocker module_lock(Module_lock);
   JfrTypeSet::clear();
@@ -388,21 +399,23 @@
 
 void JfrCheckpointManager::write_type_set() {
   assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
-  Thread* const thread = Thread::current();
-  if (LeakProfiler::is_running()) {
+  {
+    Thread* const thread = Thread::current();
+    DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread));
     // can safepoint here
+    ThreadInVMfromNative transition((JavaThread*)thread);
+    ResetNoHandleMark rnhm;
     MutexLocker cld_lock(thread, ClassLoaderDataGraph_lock);
     MutexLocker module_lock(thread, Module_lock);
-    JfrCheckpointWriter leakp_writer(true, thread);
-    JfrCheckpointWriter writer(true, thread);
-    JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
-    ObjectSampleCheckpoint::on_type_set(leakp_writer);
-  } else {
-    // can safepoint here
-    MutexLocker cld_lock(ClassLoaderDataGraph_lock);
-    MutexLocker module_lock(Module_lock);
-    JfrCheckpointWriter writer(true, thread);
-    JfrTypeSet::serialize(&writer, NULL, false, false);
+    if (LeakProfiler::is_running()) {
+      JfrCheckpointWriter leakp_writer(true, thread);
+      JfrCheckpointWriter writer(true, thread);
+      JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
+      ObjectSampleCheckpoint::on_type_set(leakp_writer);
+    } else {
+      JfrCheckpointWriter writer(true, thread);
+      JfrTypeSet::serialize(&writer, NULL, false, false);
+    }
   }
   write();
 }
@@ -416,13 +429,33 @@
   }
 }
 
+class JavaThreadToVM : public StackObj {
+ private:
+  JavaThread* _jt;
+ public:
+  JavaThreadToVM(Thread* thread) : _jt(thread->is_Java_thread() ? (JavaThread*)thread : NULL) {
+    if (_jt != NULL) {
+      assert(_jt->thread_state() == _thread_in_native, "invariant");
+      _jt->set_thread_state(_thread_in_vm);
+    }
+  }
+  ~JavaThreadToVM() {
+    if (_jt != NULL) {
+      _jt->set_thread_state(_thread_in_native);
+    }
+  }
+};
+
 size_t JfrCheckpointManager::flush_type_set() {
   size_t elements = 0;
   if (JfrTraceIdEpoch::has_changed_tag_state()) {
-    JfrCheckpointWriter writer(Thread::current());
-    // can safepoint here
-    MutexLocker cld_lock(ClassLoaderDataGraph_lock);
-    MutexLocker module_lock(Module_lock);
+    Thread* const t = Thread::current();
+    // can safepoint here (if JavaThread)
+    JavaThreadToVM transition(t);
+    ResetNoHandleMark rnhm;
+    MutexLocker cld_lock(t, ClassLoaderDataGraph_lock);
+    MutexLocker module_lock(t, Module_lock);
+    JfrCheckpointWriter writer(t);
     elements = JfrTypeSet::serialize(&writer, NULL, false, true);
   }
   if (is_constant_pending()) {
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -29,14 +29,18 @@
 #include "oops/klass.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/typeArrayOop.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/thread.inline.hpp"
 
 static jbyteArray metadata_blob = NULL;
 static u8 metadata_id = 0;
 static u8 last_metadata_id = 0;
 
-static void write_metadata_blob(JfrChunkWriter& chunkwriter) {
+static void write_metadata_blob(JfrChunkWriter& chunkwriter, Thread* thread) {
+  assert(chunkwriter.is_valid(), "invariant");
+  assert(thread != NULL, "invariant");
   assert(metadata_blob != NULL, "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
   const typeArrayOop arr = (typeArrayOop)JfrJavaSupport::resolve_non_null(metadata_blob);
   assert(arr != NULL, "invariant");
   const int length = arr->length();
@@ -47,11 +51,15 @@
   chunkwriter.write_unbuffered(data_address, length);
 }
 
-bool JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) {
+void JfrMetadataEvent::write(JfrChunkWriter& chunkwriter) {
   assert(chunkwriter.is_valid(), "invariant");
   if (last_metadata_id == metadata_id && chunkwriter.has_metadata()) {
-    return false;
+    return;
   }
+  JavaThread* const jt = (JavaThread*)Thread::current();
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
+  // can safepoint here
+  ThreadInVMfromNative transition(jt);
   // header
   const int64_t metadata_offset = chunkwriter.reserve(sizeof(u4));
   chunkwriter.write<u8>(EVENT_METADATA); // ID 0
@@ -59,13 +67,12 @@
   chunkwriter.write(JfrTicks::now());
   chunkwriter.write((u8)0); // duration
   chunkwriter.write(metadata_id); // metadata id
-  write_metadata_blob(chunkwriter); // payload
+  write_metadata_blob(chunkwriter, jt); // payload
   // fill in size of metadata descriptor event
   const int64_t size_written = chunkwriter.current_offset() - metadata_offset;
   chunkwriter.write_padded_at_offset((u4)size_written, metadata_offset);
   chunkwriter.set_last_metadata_offset(metadata_offset);
   last_metadata_id = metadata_id;
-  return true;
 }
 
 void JfrMetadataEvent::update(jbyteArray metadata) {
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.hpp	Thu Jun 11 10:48:35 2020 +0200
@@ -36,7 +36,7 @@
 //
 class JfrMetadataEvent : AllStatic {
  public:
-  static bool write(JfrChunkWriter& writer);
+  static void write(JfrChunkWriter& writer);
   static void update(jbyteArray metadata);
 };
 
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -1038,6 +1038,7 @@
  * Clear all tags from the previous epoch.
  */
 void JfrTypeSet::clear() {
+  ResourceMark rm;
   JfrKlassUnloading::clear();
   clear_artifacts = true;
   setup(NULL, NULL, false, false);
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkRotation.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkRotation.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 #include "jfr/recorder/repository/jfrChunkRotation.hpp"
 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
 #include "runtime/handles.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
 
 static jobject chunk_monitor = NULL;
 static int64_t threshold = 0;
@@ -53,6 +54,9 @@
 
 static void notify() {
   Thread* const thread = Thread::current();
+  // can safepoint here
+  ThreadInVMfromNative transition((JavaThread*)thread);
+  ResetNoHandleMark rnhm;
   JfrJavaSupport::notify_all(get_chunk_monitor(thread), thread);
 }
 
--- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -33,6 +33,7 @@
 #include "logging/log.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/globals.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/os.hpp"
 #include "runtime/thread.inline.hpp"
@@ -422,7 +423,7 @@
 */
 static bool prepare_for_emergency_dump(Thread* thread) {
   assert(thread != NULL, "invariant");
-
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
   if (thread->is_Watcher_thread()) {
     // need WatcherThread as a safeguard against potential deadlocks
     return false;
@@ -501,29 +502,38 @@
   return Atomic::cmpxchg(&jfr_shutdown_lock, 0, 1) == 0;
 }
 
-class JavaThreadInVM : public StackObj {
+class JavaThreadInVMAndNative : public StackObj {
  private:
   JavaThread* const _jt;
   JavaThreadState _original_state;
  public:
 
-  JavaThreadInVM(Thread* t) : _jt(t->is_Java_thread() ? (JavaThread*)t : NULL),
-                              _original_state(_thread_max_state) {
-    if ((_jt != NULL) && (_jt->thread_state() != _thread_in_vm)) {
+  JavaThreadInVMAndNative(Thread* t) : _jt(t->is_Java_thread() ? (JavaThread*)t : NULL),
+                                       _original_state(_thread_max_state) {
+    if (_jt != NULL) {
       _original_state = _jt->thread_state();
-      _jt->set_thread_state(_thread_in_vm);
+      if (_original_state != _thread_in_vm) {
+        _jt->set_thread_state(_thread_in_vm);
+      }
     }
   }
 
-  ~JavaThreadInVM() {
+  ~JavaThreadInVMAndNative() {
     if (_original_state != _thread_max_state) {
       _jt->set_thread_state(_original_state);
     }
   }
 
+  void transition_to_native() {
+    if (_jt != NULL) {
+      assert(_jt->thread_state() == _thread_in_vm, "invariant");
+      _jt->set_thread_state(_thread_in_native);
+    }
+  }
 };
 
-static void post_events(bool exception_handler) {
+static void post_events(bool exception_handler, Thread* thread) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
   if (exception_handler) {
     EventShutdown e;
     e.set_reason("VM Error");
@@ -547,11 +557,14 @@
     return;
   }
   // Ensure a JavaThread is _thread_in_vm when we make this call
-  JavaThreadInVM jtivm(thread);
+  JavaThreadInVMAndNative jtivm(thread);
   if (!prepare_for_emergency_dump(thread)) {
     return;
   }
-  post_events(exception_handler);
+  post_events(exception_handler, thread);
+  // if JavaThread, transition to _thread_in_native to issue a final flushpoint
+  NoHandleMark nhm;
+  jtivm.transition_to_native();
   const int messages = MSGBIT(MSG_VM_ERROR);
   JfrRecorderService service;
   service.rotate(messages);
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -45,9 +45,8 @@
 #include "jfr/writers/jfrJavaEventWriter.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
 #include "logging/log.hpp"
-#include "memory/resourceArea.hpp"
 #include "runtime/atomic.hpp"
-#include "runtime/handles.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/os.hpp"
 #include "runtime/safepoint.hpp"
@@ -373,8 +372,6 @@
 }
 
 void JfrRecorderService::clear() {
-  ResourceMark rm;
-  HandleMark hm;
   pre_safepoint_clear();
   invoke_safepoint_clear();
   post_safepoint_clear();
@@ -388,6 +385,7 @@
 
 void JfrRecorderService::invoke_safepoint_clear() {
   JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_clear> safepoint_task(*this);
+  ThreadInVMfromNative transition((JavaThread*)Thread::current());
   VMThread::execute(&safepoint_task);
 }
 
@@ -474,6 +472,7 @@
 
 void JfrRecorderService::rotate(int msgs) {
   assert(!JfrStream_lock->owned_by_self(), "invariant");
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
   if (msgs & MSGBIT(MSG_VM_ERROR)) {
     // emergency dump
     if (!prepare_for_vm_error_rotation()) {
@@ -521,8 +520,6 @@
 }
 
 void JfrRecorderService::write() {
-  ResourceMark rm;
-  HandleMark hm;
   pre_safepoint_write();
   invoke_safepoint_write();
   post_safepoint_write();
@@ -547,6 +544,8 @@
 
 void JfrRecorderService::invoke_safepoint_write() {
   JfrVMOperation<JfrRecorderService, &JfrRecorderService::safepoint_write> safepoint_task(*this);
+  // can safepoint here
+  ThreadInVMfromNative transition((JavaThread*)Thread::current());
   VMThread::execute(&safepoint_task);
 }
 
@@ -632,8 +631,6 @@
   assert(JfrStream_lock->owned_by_self(), "invariant");
   assert(_chunkwriter.is_valid(), "invariant");
   Thread* const t = Thread::current();
-  ResourceMark rm(t);
-  HandleMark hm(t);
   ++flushpoint_id;
   reset_thread_local_buffer(t);
   FlushFunctor flushpoint(*this);
@@ -644,6 +641,7 @@
 }
 
 void JfrRecorderService::flushpoint() {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
   MutexLocker lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
   if (_chunkwriter.is_valid()) {
     invoke_flush();
@@ -651,11 +649,13 @@
 }
 
 void JfrRecorderService::process_full_buffers() {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
   if (_chunkwriter.is_valid()) {
     _storage.write_full();
   }
 }
 
 void JfrRecorderService::evaluate_chunk_size_for_rotation() {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(Thread::current()));
   JfrChunkRotation::evaluate(_chunkwriter);
 }
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp	Thu Jun 11 10:48:35 2020 +0200
@@ -23,11 +23,15 @@
  */
 
 #include "precompiled.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
 #include "jfr/recorder/jfrRecorder.hpp"
 #include "jfr/recorder/service/jfrPostBox.hpp"
 #include "jfr/recorder/service/jfrRecorderService.hpp"
 #include "jfr/recorder/service/jfrRecorderThread.hpp"
+#include "jfr/recorder/jfrRecorder.hpp"
 #include "logging/log.hpp"
+#include "runtime/handles.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/thread.inline.hpp"
 
@@ -59,18 +63,24 @@
       }
       msgs = post_box.collect();
       JfrMsg_lock->unlock();
-      if (PROCESS_FULL_BUFFERS) {
-        service.process_full_buffers();
-      }
-      // Check amount of data written to chunk already
-      // if it warrants asking for a new chunk
-      service.evaluate_chunk_size_for_rotation();
-      if (START) {
-        service.start();
-      } else if (ROTATE) {
-        service.rotate(msgs);
-      } else if (FLUSHPOINT) {
-        service.flushpoint();
+      {
+        // Run as _thread_in_native as much a possible
+        // to minimize impact on safepoint synchronizations.
+        NoHandleMark nhm;
+        ThreadToNativeFromVM transition(thread);
+        if (PROCESS_FULL_BUFFERS) {
+          service.process_full_buffers();
+        }
+        // Check amount of data written to chunk already
+        // if it warrants asking for a new chunk.
+        service.evaluate_chunk_size_for_rotation();
+        if (START) {
+          service.start();
+        } else if (ROTATE) {
+          service.rotate(msgs);
+        } else if (FLUSHPOINT) {
+          service.flushpoint();
+        }
       }
       JfrMsg_lock->lock();
       post_box.notify_waiters();
--- a/src/hotspot/share/jfr/utilities/jfrConcurrentLinkedListHost.hpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrConcurrentLinkedListHost.hpp	Thu Jun 11 10:48:35 2020 +0200
@@ -65,11 +65,11 @@
 *
 * We say that the FIFO solution is "mostly" concurrent, in certain situations.
 *
-* Safe memory reclamation is based on a reference tracking scheme based on versions, implemented using JfrVersion.
-* An access to the list is "version controlled", with clients checking out the latest version of the list.
-* Destructive modifications made by clients, i.e. deletions, are committed to describe new versions of the list.
-* Before reclamation, a client inspects the versioning system to ensure checkouts for versions strictly
-* less than the version of the modification have all been relinquished. See utilities/JfrVersion.hpp.
+* Safe memory reclamation is based on a reference tracking scheme based on versioning, implemented using JfrVersionSystem.
+* An access to the list is "versioned", with clients checking out the latest version describing the list.
+* Destructive modifications made by clients, i.e. deletions, are signalled by incrementing the version.
+* Before reclamation, a client inspects JfrVersionSystem to ensure checkouts with versions strictly
+* less than the version of the modification have been relinquished. See utilities/JfrVersionSystem.hpp.
 *
 * Insertions can only take place from one end of the list, head or tail, exclusively.
 * Specializations, a.k.a clients, must ensure this requirement.
--- a/src/hotspot/share/jfr/utilities/jfrConcurrentLinkedListHost.inline.hpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrConcurrentLinkedListHost.inline.hpp	Thu Jun 11 10:48:35 2020 +0200
@@ -222,7 +222,7 @@
   assert(is_marked_for_removal(successor->_next), "invariant");
   // Now attempt to physically excise the successor node.
   // If the cas fails, we can optimize for the slow path if we know we are not performing
-  // insertions from the head. Then a failed cas results not from new a node being inserted,
+  // insertions from the head. Then a failed cas results not from a new node being inserted,
   // but only because another thread excised us already.
   if (!cas(&predecessor->_next, successor, successor_next) && insert_is_head) {
     // Physically excise using slow path, can be completed asynchronously by other threads.
--- a/src/hotspot/share/jfr/utilities/jfrVersionSystem.inline.hpp	Thu Jun 11 08:23:09 2020 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrVersionSystem.inline.hpp	Thu Jun 11 10:48:35 2020 +0200
@@ -25,11 +25,9 @@
 #ifndef SHARE_JFR_UTILITIES_JFRVERSIONSYSTEM_INLINE_HPP
 #define SHARE_JFR_UTILITIES_JFRVERSIONSYSTEM_INLINE_HPP
 
-#include "jfr/utilities/jfrSpinlockHelper.hpp"
 #include "jfr/utilities/jfrVersionSystem.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/os.inline.hpp"
-#include "runtime/vm_version.hpp"
 
 inline JfrVersionSystem::Node::Node() : _next(NULL), _version(0), _live(true) {}
 
@@ -65,10 +63,6 @@
 }
 
 inline JfrVersionSystem::Type JfrVersionSystem::increment() {
-  if (!VM_Version::supports_cx8()) {
-    JfrSpinlockHelper lock(&_spinlock);
-    return ++_tip._value;
-  }
   traceid cmp;
   traceid xchg;
   do {