8234086: VM operation can be simplified
authorrehn
Fri, 29 Nov 2019 12:09:25 +0100
changeset 59325 3636bab5e81e
parent 59324 5e8f9713e343
child 59326 851a389fc54d
8234086: VM operation can be simplified Reviewed-by: kbarrett, dholmes, dcubed
src/hotspot/share/jfr/leakprofiler/utilities/vmOperation.hpp
src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp
src/hotspot/share/runtime/biasedLocking.cpp
src/hotspot/share/runtime/handshake.cpp
src/hotspot/share/runtime/safepoint.cpp
src/hotspot/share/runtime/safepoint.hpp
src/hotspot/share/runtime/synchronizer.cpp
src/hotspot/share/runtime/synchronizer.hpp
src/hotspot/share/runtime/thread.cpp
src/hotspot/share/runtime/vmOperations.cpp
src/hotspot/share/runtime/vmOperations.hpp
src/hotspot/share/runtime/vmThread.cpp
src/hotspot/share/runtime/vmThread.hpp
test/hotspot/gtest/threadHelper.inline.hpp
--- a/src/hotspot/share/jfr/leakprofiler/utilities/vmOperation.hpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/jfr/leakprofiler/utilities/vmOperation.hpp	Fri Nov 29 12:09:25 2019 +0100
@@ -29,10 +29,6 @@
 
 class OldObjectVMOperation : public VM_Operation {
  public:
-  Mode evaluation_mode() const {
-    return _safepoint;
-  }
-
   VMOp_Type type() const {
     return VMOp_JFROldObject;
   }
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp	Fri Nov 29 12:09:25 2019 +0100
@@ -337,7 +337,6 @@
   JfrVMOperation(Instance& instance) : _instance(instance) {}
   void doit() { (_instance.*func)(); }
   VMOp_Type type() const { return VMOp_JFRCheckpoint; }
-  Mode evaluation_mode() const { return _safepoint; } // default
 };
 
 JfrRecorderService::JfrRecorderService() :
--- a/src/hotspot/share/runtime/biasedLocking.cpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/biasedLocking.cpp	Fri Nov 29 12:09:25 2019 +0100
@@ -61,8 +61,6 @@
  public:
   VM_EnableBiasedLocking() {}
   VMOp_Type type() const          { return VMOp_EnableBiasedLocking; }
-  Mode evaluation_mode() const    { return _async_safepoint; }
-  bool is_cheap_allocated() const { return true; }
 
   void doit() {
     // Iterate the class loader data dictionaries enabling biased locking for all
@@ -82,10 +80,8 @@
   EnableBiasedLockingTask(size_t interval_time) : PeriodicTask(interval_time) {}
 
   virtual void task() {
-    // Use async VM operation to avoid blocking the Watcher thread.
-    // VM Thread will free C heap storage.
-    VM_EnableBiasedLocking *op = new VM_EnableBiasedLocking();
-    VMThread::execute(op);
+    VM_EnableBiasedLocking op;
+    VMThread::execute(&op);
 
     // Reclaim our storage and disenroll ourself
     delete this;
--- a/src/hotspot/share/runtime/handshake.cpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/handshake.cpp	Fri Nov 29 12:09:25 2019 +0100
@@ -67,8 +67,6 @@
  public:
   bool evaluate_at_safepoint() const { return false; }
 
-  bool evaluate_concurrently() const { return false; }
-
  protected:
   HandshakeThreadsOperation* const _op;
 
--- a/src/hotspot/share/runtime/safepoint.cpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/safepoint.cpp	Fri Nov 29 12:09:25 2019 +0100
@@ -532,6 +532,10 @@
   return false;
 }
 
+bool SafepointSynchronize::is_forced_cleanup_needed() {
+  return ObjectSynchronizer::needs_monitor_scavenge();
+}
+
 class ParallelSPCleanupThreadClosure : public ThreadClosure {
 private:
   CodeBlobClosure* _nmethod_cl;
--- a/src/hotspot/share/runtime/safepoint.hpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/safepoint.hpp	Fri Nov 29 12:09:25 2019 +0100
@@ -163,6 +163,7 @@
   static void handle_polling_page_exception(JavaThread *thread);
 
   static bool is_cleanup_needed();
+  static bool is_forced_cleanup_needed();
   static void do_cleanup_tasks();
 
   static void set_is_at_safepoint()             { _state = _synchronized; }
--- a/src/hotspot/share/runtime/synchronizer.cpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/synchronizer.cpp	Fri Nov 29 12:09:25 2019 +0100
@@ -529,8 +529,7 @@
 };
 
 static SharedGlobals GVars;
-static int MonitorScavengeThreshold = 1000000;
-static volatile int ForceMonitorScavenge = 0; // Scavenge required and pending
+static int _forceMonitorScavenge = 0; // Scavenge required and pending
 
 static markWord read_stable_mark(oop obj) {
   markWord mark = obj->mark();
@@ -915,7 +914,17 @@
 
 bool ObjectSynchronizer::is_cleanup_needed() {
   if (MonitorUsedDeflationThreshold > 0) {
-    return monitors_used_above_threshold();
+    if (monitors_used_above_threshold()) {
+      return true;
+    }
+  }
+  return needs_monitor_scavenge();
+}
+
+bool ObjectSynchronizer::needs_monitor_scavenge() {
+  if (Atomic::load(&_forceMonitorScavenge) == 1) {
+    log_info(monitorinflation)("Monitor scavenge needed, triggering safepoint cleanup.");
+    return true;
   }
   return false;
 }
@@ -983,8 +992,6 @@
 // we'll incur more safepoints, which are harmful to performance.
 // See also: GuaranteedSafepointInterval
 //
-// The current implementation uses asynchronous VM operations.
-//
 // If MonitorBound is set, the boundry applies to
 //     (g_om_population - g_om_free_count)
 // i.e., if there are not enough ObjectMonitors on the global free list,
@@ -994,16 +1001,12 @@
 static void InduceScavenge(Thread* self, const char * Whence) {
   // Induce STW safepoint to trim monitors
   // Ultimately, this results in a call to deflate_idle_monitors() in the near future.
-  // More precisely, trigger an asynchronous STW safepoint as the number
+  // More precisely, trigger a cleanup safepoint as the number
   // of active monitors passes the specified threshold.
   // TODO: assert thread state is reasonable
 
-  if (ForceMonitorScavenge == 0 && Atomic::xchg(&ForceMonitorScavenge, 1) == 0) {
-    // Induce a 'null' safepoint to scavenge monitors
-    // Must VM_Operation instance be heap allocated as the op will be enqueue and posted
-    // to the VMthread and have a lifespan longer than that of this activation record.
-    // The VMThread will delete the op when completed.
-    VMThread::execute(new VM_ScavengeMonitors());
+  if (Atomic::xchg (&_forceMonitorScavenge, 1) == 0) {
+    VMThread::check_for_forced_cleanup();
   }
 }
 
@@ -1681,7 +1684,7 @@
     Thread::muxRelease(&gListLock);
   }
 
-  ForceMonitorScavenge = 0;    // Reset
+  Atomic::store(&_forceMonitorScavenge, 0);    // Reset
 
   OM_PERFDATA_OP(Deflations, inc(counters->n_scavenged));
   OM_PERFDATA_OP(MonExtant, set_value(counters->n_in_circulation));
--- a/src/hotspot/share/runtime/synchronizer.hpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/synchronizer.hpp	Fri Nov 29 12:09:25 2019 +0100
@@ -138,6 +138,7 @@
                               ObjectMonitor** free_head_p,
                               ObjectMonitor** free_tail_p);
   static bool is_cleanup_needed();
+  static bool needs_monitor_scavenge();
   static void oops_do(OopClosure* f);
   // Process oops in thread local used monitors
   static void thread_local_used_oops_do(Thread* thread, OopClosure* f);
--- a/src/hotspot/share/runtime/thread.cpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/thread.cpp	Fri Nov 29 12:09:25 2019 +0100
@@ -524,10 +524,9 @@
   }
 }
 
-// Enqueue a VM_Operation to do the job for us - sometime later
 void Thread::send_async_exception(oop java_thread, oop java_throwable) {
-  VM_ThreadStop* vm_stop = new VM_ThreadStop(java_thread, java_throwable);
-  VMThread::execute(vm_stop);
+  VM_ThreadStop vm_stop(java_thread, java_throwable);
+  VMThread::execute(&vm_stop);
 }
 
 
--- a/src/hotspot/share/runtime/vmOperations.cpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/vmOperations.cpp	Fri Nov 29 12:09:25 2019 +0100
@@ -73,22 +73,12 @@
   }
 }
 
-const char* VM_Operation::mode_to_string(Mode mode) {
-  switch(mode) {
-    case _safepoint      : return "safepoint";
-    case _no_safepoint   : return "no safepoint";
-    case _concurrent     : return "concurrent";
-    case _async_safepoint: return "async safepoint";
-    default              : return "unknown";
-  }
-}
 // Called by fatal error handler.
 void VM_Operation::print_on_error(outputStream* st) const {
   st->print("VM_Operation (" PTR_FORMAT "): ", p2i(this));
   st->print("%s", name());
 
-  const char* mode = mode_to_string(evaluation_mode());
-  st->print(", mode: %s", mode);
+  st->print(", mode: %s", evaluate_at_safepoint() ? "safepoint" : "no safepoint");
 
   if (calling_thread()) {
     st->print(", requested by thread " PTR_FORMAT, p2i(calling_thread()));
--- a/src/hotspot/share/runtime/vmOperations.hpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/vmOperations.hpp	Fri Nov 29 12:09:25 2019 +0100
@@ -128,15 +128,8 @@
   template(GTestExecuteAtSafepoint)               \
   template(JFROldObject)                          \
 
-class VM_Operation: public CHeapObj<mtInternal> {
+class VM_Operation : public StackObj {
  public:
-  enum Mode {
-    _safepoint,       // blocking,        safepoint, vm_op C-heap allocated
-    _no_safepoint,    // blocking,     no safepoint, vm_op C-Heap allocated
-    _concurrent,      // non-blocking, no safepoint, vm_op C-Heap allocated
-    _async_safepoint  // non-blocking,    safepoint, vm_op C-Heap allocated
-  };
-
   enum VMOp_Type {
     VM_OPS_DO(VM_OP_ENUM)
     VMOp_Terminating
@@ -152,8 +145,7 @@
   static const char* _names[];
 
  public:
-  VM_Operation()  { _calling_thread = NULL; _next = NULL; _prev = NULL; }
-  virtual ~VM_Operation() {}
+  VM_Operation() : _calling_thread(NULL), _timestamp(0),  _next(NULL), _prev(NULL) {}
 
   // VM operation support (used by VM thread)
   Thread* calling_thread() const                 { return _calling_thread; }
@@ -174,10 +166,7 @@
   // completes. If doit_prologue() returns false the VM operation is cancelled.
   virtual void doit()                            = 0;
   virtual bool doit_prologue()                   { return true; };
-  virtual void doit_epilogue()                   {}; // Note: Not called if mode is: _concurrent
-
-  // Type test
-  virtual bool is_methodCompiler() const         { return false; }
+  virtual void doit_epilogue()                   {};
 
   // Linking
   VM_Operation *next() const                     { return _next; }
@@ -187,28 +176,12 @@
 
   // Configuration. Override these appropriately in subclasses.
   virtual VMOp_Type type() const = 0;
-  virtual Mode evaluation_mode() const            { return _safepoint; }
   virtual bool allow_nested_vm_operations() const { return false; }
-  virtual bool is_cheap_allocated() const         { return false; }
   virtual void oops_do(OopClosure* f)              { /* do nothing */ };
 
-  // CAUTION: <don't hang yourself with following rope>
-  // If you override these methods, make sure that the evaluation
-  // of these methods is race-free and non-blocking, since these
-  // methods may be evaluated either by the mutators or by the
-  // vm thread, either concurrently with mutators or with the mutators
-  // stopped. In other words, taking locks is verboten, and if there
-  // are any races in evaluating the conditions, they'd better be benign.
-  virtual bool evaluate_at_safepoint() const {
-    return evaluation_mode() == _safepoint  ||
-           evaluation_mode() == _async_safepoint;
-  }
-  virtual bool evaluate_concurrently() const {
-    return evaluation_mode() == _concurrent ||
-           evaluation_mode() == _async_safepoint;
-  }
-
-  static const char* mode_to_string(Mode mode);
+  // An operation can either be done inside a safepoint
+  // or concurrently with Java threads running.
+  virtual bool evaluate_at_safepoint() const { return true; }
 
   // Debugging
   virtual void print_on_error(outputStream* st) const;
@@ -254,8 +227,6 @@
   void doit();
   // We deoptimize if top-most frame is compiled - this might require a C2I adapter to be generated
   bool allow_nested_vm_operations() const        { return true; }
-  Mode evaluation_mode() const                   { return _async_safepoint; }
-  bool is_cheap_allocated() const                { return true; }
 
   // GC support
   void oops_do(OopClosure* f) {
@@ -297,14 +268,6 @@
   VMOp_Type type() const { return VMOp_ICBufferFull; }
 };
 
-// empty asynchronous vm op, when forcing a safepoint to scavenge monitors
-class VM_ScavengeMonitors: public VM_ForceSafepoint {
- public:
-  VMOp_Type type() const                         { return VMOp_ScavengeMonitors; }
-  Mode evaluation_mode() const                   { return _async_safepoint; }
-  bool is_cheap_allocated() const                { return true; }
-};
-
 // Base class for invoking parts of a gtest in a safepoint.
 // Derived classes provide the doit method.
 // Typically also need to transition the gtest thread from native to VM.
@@ -498,7 +461,6 @@
  public:
   VM_PrintCompileQueue(outputStream* st) : _out(st) {}
   VMOp_Type type() const { return VMOp_PrintCompileQueue; }
-  Mode evaluation_mode() const { return _safepoint; }
   void doit();
 };
 
--- a/src/hotspot/share/runtime/vmThread.cpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/vmThread.cpp	Fri Nov 29 12:09:25 2019 +0100
@@ -50,13 +50,15 @@
 #include "utilities/vmError.hpp"
 #include "utilities/xmlstream.hpp"
 
+VM_QueueHead VMOperationQueue::_queue_head[VMOperationQueue::nof_priorities];
+
 VMOperationQueue::VMOperationQueue() {
   // The queue is a circular doubled-linked list, which always contains
   // one element (i.e., one element means empty).
   for(int i = 0; i < nof_priorities; i++) {
     _queue_length[i] = 0;
     _queue_counter = 0;
-    _queue[i] = new VM_None("QueueHead");
+    _queue[i] = &_queue_head[i];
     _queue[i]->set_next(_queue[i]);
     _queue[i]->set_prev(_queue[i]);
   }
@@ -81,12 +83,7 @@
   q->set_next(n);
 }
 
-void VMOperationQueue::queue_add_front(int prio, VM_Operation *op) {
-  _queue_length[prio]++;
-  insert(_queue[prio]->next(), op);
-}
-
-void VMOperationQueue::queue_add_back(int prio, VM_Operation *op) {
+void VMOperationQueue::queue_add(int prio, VM_Operation *op) {
   _queue_length[prio]++;
   insert(_queue[prio]->prev(), op);
 }
@@ -154,11 +151,11 @@
 
   HOTSPOT_VMOPS_REQUEST(
                    (char *) op->name(), strlen(op->name()),
-                   op->evaluation_mode());
+                   op->evaluate_at_safepoint() ? 0 : 1);
 
   // Encapsulates VM queue policy. Currently, that
   // only involves putting them on the right list
-  queue_add_back(op->evaluate_at_safepoint() ? SafepointPriority : MediumPriority, op);
+  queue_add(op->evaluate_at_safepoint() ? SafepointPriority : MediumPriority, op);
 }
 
 VM_Operation* VMOperationQueue::remove_next() {
@@ -380,15 +377,11 @@
   assert(event != NULL, "invariant");
   assert(event->should_commit(), "invariant");
   assert(op != NULL, "invariant");
-  const bool is_concurrent = op->evaluate_concurrently();
   const bool evaluate_at_safepoint = op->evaluate_at_safepoint();
   event->set_operation(op->type());
   event->set_safepoint(evaluate_at_safepoint);
-  event->set_blocking(!is_concurrent);
-  // Only write caller thread information for non-concurrent vm operations.
-  // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown.
-  // This is because the caller thread could have exited already.
-  event->set_caller(is_concurrent ? 0 : JFR_THREAD_ID(op->calling_thread()));
+  event->set_blocking(true);
+  event->set_caller(JFR_THREAD_ID(op->calling_thread()));
   event->set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_id() : 0);
   event->commit();
 }
@@ -400,7 +393,7 @@
     PerfTraceTime vm_op_timer(perf_accumulated_vm_operation_time());
     HOTSPOT_VMOPS_BEGIN(
                      (char *) op->name(), strlen(op->name()),
-                     op->evaluation_mode());
+                     op->evaluate_at_safepoint() ? 0 : 1);
 
     EventExecuteVMOperation event;
     op->evaluate();
@@ -410,21 +403,11 @@
 
     HOTSPOT_VMOPS_END(
                      (char *) op->name(), strlen(op->name()),
-                     op->evaluation_mode());
+                     op->evaluate_at_safepoint() ? 0 : 1);
   }
 
-  // Last access of info in _cur_vm_operation!
-  bool c_heap_allocated = op->is_cheap_allocated();
-
   // Mark as completed
-  if (!op->evaluate_concurrently()) {
-    op->calling_thread()->increment_vm_operation_completed_count();
-  }
-  // It is unsafe to access the _cur_vm_operation after the 'increment_vm_operation_completed_count' call,
-  // since if it is stack allocated the calling thread might have deallocated
-  if (c_heap_allocated) {
-    delete _cur_vm_operation;
-  }
+  op->calling_thread()->increment_vm_operation_completed_count();
 }
 
 static VM_None    safepointALot_op("SafepointALot");
@@ -441,6 +424,11 @@
   }
 };
 
+void VMThread::check_for_forced_cleanup() {
+  MonitorLocker mq(VMOperationQueue_lock,  Mutex::_no_safepoint_check_flag);
+  mq.notify();
+}
+
 VM_Operation* VMThread::no_op_safepoint() {
   // Check for handshakes first since we may need to return a VMop.
   if (HandshakeALot) {
@@ -451,7 +439,8 @@
   long interval_ms = SafepointTracing::time_since_last_safepoint_ms();
   bool max_time_exceeded = GuaranteedSafepointInterval != 0 &&
                            (interval_ms >= GuaranteedSafepointInterval);
-  if (max_time_exceeded && SafepointSynchronize::is_cleanup_needed()) {
+  if ((max_time_exceeded && SafepointSynchronize::is_cleanup_needed()) ||
+      SafepointSynchronize::is_forced_cleanup_needed()) {
     return &cleanup_op;
   }
   if (SafepointALot) {
@@ -480,8 +469,7 @@
       _cur_vm_operation = _vm_queue->remove_next();
 
       // Stall time tracking code
-      if (PrintVMQWaitTime && _cur_vm_operation != NULL &&
-          !_cur_vm_operation->evaluate_concurrently()) {
+      if (PrintVMQWaitTime && _cur_vm_operation != NULL) {
         long stall = os::javaTimeMillis() - _cur_vm_operation->timestamp();
         if (stall > 0)
           tty->print_cr("%s stall: %ld",  _cur_vm_operation->name(), stall);
@@ -489,8 +477,8 @@
 
       while (!should_terminate() && _cur_vm_operation == NULL) {
         // wait with a timeout to guarantee safepoints at regular intervals
-        bool timedout =
-          mu_queue.wait(GuaranteedSafepointInterval);
+        // (if there is cleanup work to do)
+        (void)mu_queue.wait(GuaranteedSafepointInterval);
 
         // Support for self destruction
         if ((SelfDestructTimer != 0) && !VMError::is_error_reported() &&
@@ -499,9 +487,12 @@
           exit(-1);
         }
 
-        if (timedout) {
+        // If the queue contains a safepoint VM op,
+        // clean up will be done so we can skip this part.
+        if (!_vm_queue->peek_at_safepoint_priority()) {
+
           // Have to unlock VMOperationQueue_lock just in case no_op_safepoint()
-          // has to do a handshake.
+          // has to do a handshake when HandshakeALot is enabled.
           MutexUnlocker mul(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag);
           if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) {
             // Force a safepoint since we have not had one for at least
@@ -624,15 +615,6 @@
     { MonitorLocker mu(VMOperationRequest_lock, Mutex::_no_safepoint_check_flag);
       mu.notify_all();
     }
-
-    // We want to make sure that we get to a safepoint regularly
-    // even when executing VMops that don't require safepoints.
-    if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) {
-      HandleMark hm(VMThread::vm_thread());
-      SafepointSynchronize::begin();
-      SafepointSynchronize::end();
-      _cur_vm_operation = NULL;
-    }
   }
 }
 
@@ -667,11 +649,7 @@
   if (!t->is_VM_thread()) {
     SkipGCALot sgcalot(t);    // avoid re-entrant attempts to gc-a-lot
     // JavaThread or WatcherThread
-    bool concurrent = op->evaluate_concurrently();
-    // only blocking VM operations need to verify the caller's safepoint state:
-    if (!concurrent) {
-      t->check_for_valid_safepoint_state();
-    }
+    t->check_for_valid_safepoint_state();
 
     // New request from Java thread, evaluate prologue
     if (!op->doit_prologue()) {
@@ -681,16 +659,8 @@
     // Setup VM_operations for execution
     op->set_calling_thread(t);
 
-    // It does not make sense to execute the epilogue, if the VM operation object is getting
-    // deallocated by the VM thread.
-    bool execute_epilog = !op->is_cheap_allocated();
-    assert(!concurrent || op->is_cheap_allocated(), "concurrent => cheap_allocated");
-
-    // Get ticket number for non-concurrent VM operations
-    int ticket = 0;
-    if (!concurrent) {
-      ticket = t->vm_operation_ticket();
-    }
+    // Get ticket number for the VM operation
+    int ticket = t->vm_operation_ticket();
 
     // Add VM operation to list of waiting threads. We are guaranteed not to block while holding the
     // VMOperationQueue_lock, so we can block without a safepoint check. This allows vm operation requests
@@ -702,9 +672,8 @@
       op->set_timestamp(os::javaTimeMillis());
       ml.notify();
     }
-
-    if (!concurrent) {
-      // Wait for completion of request (non-concurrent)
+    {
+      // Wait for completion of request
       // Note: only a JavaThread triggers the safepoint check when locking
       MonitorLocker ml(VMOperationRequest_lock,
                        t->is_Java_thread() ? Mutex::_safepoint_check_flag : Mutex::_no_safepoint_check_flag);
@@ -712,10 +681,7 @@
         ml.wait();
       }
     }
-
-    if (execute_epilog) {
-      op->doit_epilogue();
-    }
+    op->doit_epilogue();
   } else {
     // invoked by VM thread; usually nested VM operation
     assert(t->is_VM_thread(), "must be a VM thread");
@@ -744,9 +710,6 @@
       op->evaluate();
     }
 
-    // Free memory if needed
-    if (op->is_cheap_allocated()) delete op;
-
     _cur_vm_operation = prev_vm_operation;
   }
 }
--- a/src/hotspot/share/runtime/vmThread.hpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/src/hotspot/share/runtime/vmThread.hpp	Fri Nov 29 12:09:25 2019 +0100
@@ -30,6 +30,11 @@
 #include "runtime/task.hpp"
 #include "runtime/vmOperations.hpp"
 
+class VM_QueueHead : public VM_None {
+ public:
+  VM_QueueHead() : VM_None("QueueHead") {}
+};
+
 //
 // Prioritized queue of VM operations.
 //
@@ -52,14 +57,15 @@
   // can scan them from oops_do
   VM_Operation* _drain_list;
 
+  static VM_QueueHead _queue_head[nof_priorities];
+
   // Double-linked non-empty list insert.
   void insert(VM_Operation* q,VM_Operation* n);
   void unlink(VM_Operation* q);
 
   // Basic queue manipulation
   bool queue_empty                (int prio);
-  void queue_add_front            (int prio, VM_Operation *op);
-  void queue_add_back             (int prio, VM_Operation *op);
+  void queue_add                  (int prio, VM_Operation *op);
   VM_Operation* queue_remove_front(int prio);
   void queue_oops_do(int queue, OopClosure* f);
   void drain_list_oops_do(OopClosure* f);
@@ -73,7 +79,6 @@
   // Highlevel operations. Encapsulates policy
   void add(VM_Operation *op);
   VM_Operation* remove_next();                        // Returns next or null
-  VM_Operation* remove_next_at_safepoint_priority()   { return queue_remove_front(SafepointPriority); }
   VM_Operation* drain_at_safepoint_priority() { return queue_drain(SafepointPriority); }
   void set_drain_list(VM_Operation* list) { _drain_list = list; }
   bool peek_at_safepoint_priority() { return queue_peek(SafepointPriority); }
@@ -139,10 +144,10 @@
 
   // Tester
   bool is_VM_thread() const                      { return true; }
-  bool is_GC_thread() const                      { return true; }
 
   // The ever running loop for the VMThread
   void loop();
+  static void check_for_forced_cleanup();
 
   // Called to stop the VM thread
   static void wait_for_vm_thread_exit();
--- a/test/hotspot/gtest/threadHelper.inline.hpp	Fri Nov 29 11:26:25 2019 +0100
+++ b/test/hotspot/gtest/threadHelper.inline.hpp	Fri Nov 29 12:09:25 2019 +0100
@@ -38,8 +38,7 @@
   VM_StopSafepoint(Semaphore* running, Semaphore* wait_for) :
     _running(running), _test_complete(wait_for) {}
   VMOp_Type type() const          { return VMOp_None; }
-  Mode evaluation_mode() const    { return _no_safepoint; }
-  bool is_cheap_allocated() const { return false; }
+  bool evaluate_at_safepoint() const { return false; }
   void doit()                     { _running->signal(); _test_complete->wait(); }
 };