# HG changeset patch # User rehn # Date 1575025765 -3600 # Node ID 3636bab5e81e2d84804912037a4b6d843dc1e28f # Parent 5e8f9713e34303fe0a966000cf8044c83de54e01 8234086: VM operation can be simplified Reviewed-by: kbarrett, dholmes, dcubed diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/jfr/leakprofiler/utilities/vmOperation.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; } diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp --- 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() : diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/biasedLocking.cpp --- 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; diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/handshake.cpp --- 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; diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/safepoint.cpp --- 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; diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/safepoint.hpp --- 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; } diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/synchronizer.cpp --- 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)); diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/synchronizer.hpp --- 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); diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/thread.cpp --- 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); } diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/vmOperations.cpp --- 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())); diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/vmOperations.hpp --- 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 { +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: - // 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(); }; diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/vmThread.cpp --- 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; } } diff -r 5e8f9713e343 -r 3636bab5e81e src/hotspot/share/runtime/vmThread.hpp --- 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(); diff -r 5e8f9713e343 -r 3636bab5e81e test/hotspot/gtest/threadHelper.inline.hpp --- 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(); } };