--- old/src/hotspot/share/runtime/biasedLocking.cpp Tue Nov 21 15:20:27 2017 +++ new/src/hotspot/share/runtime/biasedLocking.cpp Tue Nov 21 15:20:26 2017 @@ -215,12 +215,8 @@ if (requesting_thread == biased_thread) { thread_is_alive = true; } else { - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur_thread = jtiwh.next(); ) { - if (cur_thread == biased_thread) { - thread_is_alive = true; - break; - } - } + ThreadsListHandle tlh; + thread_is_alive = tlh.includes(biased_thread); } if (!thread_is_alive) { if (allow_rebias) { --- old/src/hotspot/share/runtime/globals.hpp Tue Nov 21 15:20:29 2017 +++ new/src/hotspot/share/runtime/globals.hpp Tue Nov 21 15:20:28 2017 @@ -2481,10 +2481,10 @@ NOT_LP64(range(-1, max_intx)) \ \ diagnostic(bool, EnableThreadSMRExtraValidityChecks, true, \ - "Enable Thread SMR extra validity checks") \ + "Enable Thread SMR extra validity checks") \ \ diagnostic(bool, EnableThreadSMRStatistics, true, \ - "Enable Thread SMR Statistics") \ + "Enable Thread SMR Statistics") \ \ product(bool, Inline, true, \ "Enable inlining") \ --- old/src/hotspot/share/runtime/handshake.cpp Tue Nov 21 15:20:32 2017 +++ new/src/hotspot/share/runtime/handshake.cpp Tue Nov 21 15:20:31 2017 @@ -137,22 +137,23 @@ } // We need to re-think this with SMR ThreadsList. - // There is assumption in code that Threads_lock should be lock - // during certain phases. + // There is an assumption in the code that the Threads_lock should be + // locked during certain phases. MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag); ThreadsListHandle tlh; - if (tlh.includes(_target)) { - // Warning threads address might be re-used. - // handshake_process_by_vmthread will check the semaphore for us again - // Since we can't have more then one handshake in flight a reuse of thread address - // should be okey since the new thread will not have an operation. + if (tlh.includes(_target)) { + // Warning _target's address might be re-used. + // handshake_process_by_vmthread will check the semaphore for us again. + // Since we can't have more then one handshake in flight a reuse of + // _target's address should be okay since the new thread will not have + // an operation. _target->handshake_process_by_vmthread(); } else { - // We can't warn here is since the thread do cancel_handshake after it have been removed - // from ThreadsList. So we should just keep looping here until while below return negative - // If we have a bug, then we deadlock here, which is good for debugging. + // We can't warn here since the thread does cancel_handshake after + // it has been removed from the ThreadsList. So we should just keep + // looping here until while below returns false. If we have a bug, + // then we hang here, which is good for debugging. } - } while (!poll_for_completed_thread()); } @@ -197,12 +198,12 @@ // by semaphores and we optimistically begin by working on the blocked threads { // We need to re-think this with SMR ThreadsList. - // There is assumption in code that Threads_lock should be lock - // during certain phases. + // There is an assumption in the code that the Threads_lock should + // be locked during certain phases. MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag); for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thr = jtiwh.next(); ) { - // A new thread on the ThreadsList will not have an operation. - // Hence is skipped in handshake_process_by_vmthread. + // A new thread on the ThreadsList will not have an operation, + // hence it is skipped in handshake_process_by_vmthread. thr->handshake_process_by_vmthread(); } } --- old/src/hotspot/share/runtime/memprofiler.cpp Tue Nov 21 15:20:34 2017 +++ new/src/hotspot/share/runtime/memprofiler.cpp Tue Nov 21 15:20:34 2017 @@ -52,8 +52,6 @@ void MemProfilerTask::task() { - // Get thread lock to provide mutual exclusion, and so we can iterate safely over the thread list. - MutexLocker mu(Threads_lock); MemProfiler::do_trace(); } --- old/src/hotspot/share/runtime/thread.cpp Tue Nov 21 15:20:37 2017 +++ new/src/hotspot/share/runtime/thread.cpp Tue Nov 21 15:20:36 2017 @@ -3429,10 +3429,15 @@ // ======= Threads ======== // The Threads class links together all active threads, and provides -// operations over all threads. It is protected by its own Mutex -// lock, which is also used in other contexts to protect thread -// operations from having the thread being operated on from exiting -// and going away unexpectedly (e.g., safepoint synchronization) +// operations over all threads. It is protected by the Threads_lock, +// which is also used in other global contexts like safepointing. +// ThreadsListHandles are used to safely perform operations on one +// or more threads without the risk of the thread exiting during the +// operation. +// +// Note: The Threads_lock is currently more widely used than we +// would like. We are actively migrating Threads_lock uses to other +// mechanisms in order to reduce Threads_lock contention. JavaThread* Threads::_thread_list = NULL; int Threads::_number_of_threads = 0; @@ -3440,6 +3445,7 @@ int Threads::_return_code = 0; int Threads::_thread_claim_parity = 0; size_t JavaThread::_stack_size_at_create = 0; +// Safe Memory Reclamation (SMR) support: Monitor* Threads::_smr_delete_lock = new Monitor(Monitor::special, "smr_delete_lock", false /* allow_vm_block */, @@ -3446,22 +3452,86 @@ Monitor::_safepoint_check_never); // The '_cnt', '_max' and '_times" fields are enabled via // -XX:+EnableThreadSMRStatistics: + +// # of parallel threads in _smr_delete_lock->wait(). +// Impl note: Hard to imagine > 64K waiting threads so this could be 16-bit, +// but there is no nice 16-bit _FORMAT support. uint Threads::_smr_delete_lock_wait_cnt = 0; + +// Max # of parallel threads in _smr_delete_lock->wait(). +// Impl note: See _smr_delete_lock_wait_cnt note. uint Threads::_smr_delete_lock_wait_max = 0; -volatile jint Threads::_smr_delete_notify = 0; -volatile jint Threads::_smr_deleted_thread_cnt = 0; -volatile jint Threads::_smr_deleted_thread_time_max = 0; -volatile jint Threads::_smr_deleted_thread_times = 0; + +// Flag to indicate when an _smr_delete_lock->notify() is needed. +// Impl note: See _smr_delete_lock_wait_cnt note. +volatile uint Threads::_smr_delete_notify = 0; + +// # of threads deleted over VM lifetime. +// Impl note: Atomically incremented over VM lifetime so use unsigned for more +// range. Unsigned 64-bit would be more future proof, but 64-bit atomic inc +// isn't available everywhere (or is it?). +volatile uint Threads::_smr_deleted_thread_cnt = 0; + +// Max time in millis to delete a thread. +// Impl note: 16-bit might be too small on an overloaded machine. Use +// unsigned since this is a time value. Set via Atomic::cmpxchg() in a +// loop for correctness. +volatile uint Threads::_smr_deleted_thread_time_max = 0; + +// Cumulative time in millis to delete threads. +// Impl note: Atomically added to over VM lifetime so use unsigned for more +// range. Unsigned 64-bit would be more future proof, but 64-bit atomic inc +// isn't available everywhere (or is it?). +volatile uint Threads::_smr_deleted_thread_times = 0; + ThreadsList* volatile Threads::_smr_java_thread_list = new ThreadsList(0); -long Threads::_smr_java_thread_list_alloc_cnt = 1; -long Threads::_smr_java_thread_list_free_cnt = 0; + +// # of ThreadsLists allocated over VM lifetime. +// Impl note: We allocate a new ThreadsList for every thread create and +// every thread delete so we need a bigger type than the +// _smr_deleted_thread_cnt field. +uint64_t Threads::_smr_java_thread_list_alloc_cnt = 1; + +// # of ThreadsLists freed over VM lifetime. +// Impl note: See _smr_java_thread_list_alloc_cnt note. +uint64_t Threads::_smr_java_thread_list_free_cnt = 0; + +// Max size ThreadsList allocated. +// Impl note: Max # of threads alive at one time should fit in unsigned 32-bit. uint Threads::_smr_java_thread_list_max = 0; + +// Max # of nested ThreadsLists for a thread. +// Impl note: Hard to imagine > 64K nested ThreadsLists so this could be +// 16-bit, but there is no nice 16-bit _FORMAT support. uint Threads::_smr_nested_thread_list_max = 0; -volatile jint Threads::_smr_tlh_cnt = 0; -volatile jint Threads::_smr_tlh_time_max = 0; -volatile jint Threads::_smr_tlh_times = 0; + +// # of ThreadsListHandles deleted over VM lifetime. +// Impl note: Atomically incremented over VM lifetime so use unsigned for +// more range. There will be fewer ThreadsListHandles than threads so +// unsigned 32-bit should be fine. +volatile uint Threads::_smr_tlh_cnt = 0; + +// Max time in millis to delete a ThreadsListHandle. +// Impl note: 16-bit might be too small on an overloaded machine. Use +// unsigned since this is a time value. Set via Atomic::cmpxchg() in a +// loop for correctness. +volatile uint Threads::_smr_tlh_time_max = 0; + +// Cumulative time in millis to delete ThreadsListHandles. +// Impl note: Atomically added to over VM lifetime so use unsigned for more +// range. Unsigned 64-bit would be more future proof, but 64-bit atomic inc +// isn't available everywhere (or is it?). +volatile uint Threads::_smr_tlh_times = 0; + ThreadsList* Threads::_smr_to_delete_list = NULL; + +// # of parallel ThreadsLists on the to-delete list. +// Impl note: Hard to imagine > 64K ThreadsLists needing to be deleted so +// this could be 16-bit, but there is no nice 16-bit _FORMAT support. uint Threads::_smr_to_delete_list_cnt = 0; + +// Max # of parallel ThreadsLists on the to-delete list. +// Impl note: See _smr_to_delete_list_cnt note. uint Threads::_smr_to_delete_list_max = 0; #ifdef ASSERT @@ -4826,8 +4896,8 @@ // Retry the whole scenario. } - // If someone set a handshake on us just as we entered exit path, we simple cancel it. if (ThreadLocalHandshakes) { + // The thread is about to be deleted so cancel any handshake. thread->cancel_handshake(); } @@ -4834,7 +4904,7 @@ delete thread; if (EnableThreadSMRStatistics) { timer.stop(); - jint millis = (jint)timer.milliseconds(); + uint millis = (uint)timer.milliseconds(); Threads::inc_smr_deleted_thread_cnt(); Threads::add_smr_deleted_thread_times(millis); Threads::update_smr_deleted_thread_time_max(millis); @@ -5419,8 +5489,8 @@ if (!EnableThreadSMRStatistics) { return; } - st->print_cr("_smr_java_thread_list_alloc_cnt=%ld, " - "_smr_java_thread_list_free_cnt=%ld, " + st->print_cr("_smr_java_thread_list_alloc_cnt=" UINT64_FORMAT "," + "_smr_java_thread_list_free_cnt=" UINT64_FORMAT "," "_smr_java_thread_list_max=%u, " "_smr_nested_thread_list_max=%u", _smr_java_thread_list_alloc_cnt, @@ -5428,19 +5498,19 @@ _smr_java_thread_list_max, _smr_nested_thread_list_max); if (_smr_tlh_cnt > 0) { - st->print_cr("_smr_tlh_cnt=" INT32_FORMAT - ", _smr_tlh_times=" INT32_FORMAT + st->print_cr("_smr_tlh_cnt=%u" + ", _smr_tlh_times=%u" ", avg_smr_tlh_time=%0.2f" - ", _smr_tlh_time_max=" INT32_FORMAT, + ", _smr_tlh_time_max=%u", _smr_tlh_cnt, _smr_tlh_times, ((double) _smr_tlh_times / _smr_tlh_cnt), _smr_tlh_time_max); } if (_smr_deleted_thread_cnt > 0) { - st->print_cr("_smr_deleted_thread_cnt=" INT32_FORMAT - ", _smr_deleted_thread_times=" INT32_FORMAT + st->print_cr("_smr_deleted_thread_cnt=%u" + ", _smr_deleted_thread_times=%u" ", avg_smr_deleted_thread_time=%0.2f" - ", _smr_deleted_thread_time_max=" INT32_FORMAT, + ", _smr_deleted_thread_time_max=%u", _smr_deleted_thread_cnt, _smr_deleted_thread_times, ((double) _smr_deleted_thread_times / _smr_deleted_thread_cnt), _smr_deleted_thread_time_max); --- old/src/hotspot/share/runtime/thread.hpp Tue Nov 21 15:20:41 2017 +++ new/src/hotspot/share/runtime/thread.hpp Tue Nov 21 15:20:40 2017 @@ -1176,7 +1176,7 @@ // JavaThread termination and lifecycle support: void smr_delete(); - bool on_thread_list() { return _on_thread_list; } + bool on_thread_list() const { return _on_thread_list; } void set_on_thread_list() { _on_thread_list = true; } // thread has called JavaThread::exit() or is terminated @@ -1187,7 +1187,7 @@ bool check_is_terminated(TerminatedTypes l_terminated) const { return l_terminated != _not_terminated && l_terminated != _thread_exiting; } - bool is_terminated(); + bool is_terminated() const; void set_terminated(TerminatedTypes t); // special for Threads::remove() which is static: void set_terminated_value(); @@ -2130,24 +2130,39 @@ static Monitor* _smr_delete_lock; // The '_cnt', '_max' and '_times" fields are enabled via // -XX:+EnableThreadSMRStatistics: + // # of parallel threads in _smr_delete_lock->wait(). static uint _smr_delete_lock_wait_cnt; + // Max # of parallel threads in _smr_delete_lock->wait(). static uint _smr_delete_lock_wait_max; - static volatile jint _smr_delete_notify; - static volatile jint _smr_deleted_thread_cnt; - static volatile jint _smr_deleted_thread_time_max; - static volatile jint _smr_deleted_thread_times; + // Flag to indicate when an _smr_delete_lock->notify() is needed. + static volatile uint _smr_delete_notify; + // # of threads deleted over VM lifetime. + static volatile uint _smr_deleted_thread_cnt; + // Max time in millis to delete a thread. + static volatile uint _smr_deleted_thread_time_max; + // Cumulative time in millis to delete threads. + static volatile uint _smr_deleted_thread_times; static ThreadsList* volatile _smr_java_thread_list; static ThreadsList* get_smr_java_thread_list(); static ThreadsList* xchg_smr_java_thread_list(ThreadsList* new_list); - static long _smr_java_thread_list_alloc_cnt; - static long _smr_java_thread_list_free_cnt; + // # of ThreadsLists allocated over VM lifetime. + static uint64_t _smr_java_thread_list_alloc_cnt; + // # of ThreadsLists freed over VM lifetime. + static uint64_t _smr_java_thread_list_free_cnt; + // Max size ThreadsList allocated. static uint _smr_java_thread_list_max; + // Max # of nested ThreadsLists for a thread. static uint _smr_nested_thread_list_max; - static volatile jint _smr_tlh_cnt; - static volatile jint _smr_tlh_time_max; - static volatile jint _smr_tlh_times; + // # of ThreadsListHandles deleted over VM lifetime. + static volatile uint _smr_tlh_cnt; + // Max time in millis to delete a ThreadsListHandle. + static volatile uint _smr_tlh_time_max; + // Cumulative time in millis to delete ThreadsListHandles. + static volatile uint _smr_tlh_times; static ThreadsList* _smr_to_delete_list; + // # of parallel ThreadsLists on the to-delete list. static uint _smr_to_delete_list_cnt; + // Max # of parallel ThreadsLists on the to-delete list. static uint _smr_to_delete_list_max; static JavaThread* _thread_list; @@ -2199,11 +2214,11 @@ static void set_smr_delete_notify(); static void clear_smr_delete_notify(); static void inc_smr_deleted_thread_cnt(); - static void update_smr_deleted_thread_time_max(jint new_value); - static void add_smr_deleted_thread_times(jint add_value); + static void update_smr_deleted_thread_time_max(uint new_value); + static void add_smr_deleted_thread_times(uint add_value); static void inc_smr_tlh_cnt(); - static void update_smr_tlh_time_max(jint new_value); - static void add_smr_tlh_times(jint add_value); + static void update_smr_tlh_time_max(uint new_value); + static void add_smr_tlh_times(uint add_value); // Initializes the vm and creates the vm thread static jint create_vm(JavaVMInitArgs* args, bool* canTryAgain); --- old/src/hotspot/share/runtime/thread.inline.hpp Tue Nov 21 15:20:44 2017 +++ new/src/hotspot/share/runtime/thread.inline.hpp Tue Nov 21 15:20:43 2017 @@ -192,12 +192,12 @@ return l_terminated == _thread_exiting || check_is_terminated(l_terminated); } -inline bool JavaThread::is_terminated() { +inline bool JavaThread::is_terminated() const { // Use load-acquire so that setting of _terminated by // JavaThread::exit() is seen more quickly. TerminatedTypes l_terminated = (TerminatedTypes) OrderAccess::load_acquire((volatile jint *) &_terminated); - return check_is_terminated(_terminated); + return check_is_terminated(l_terminated); } inline void JavaThread::set_terminated(TerminatedTypes t) { @@ -229,9 +229,9 @@ Atomic::inc(&_smr_deleted_thread_cnt); } -inline void Threads::update_smr_deleted_thread_time_max(jint new_value) { +inline void Threads::update_smr_deleted_thread_time_max(uint new_value) { while (true) { - jint cur_value = _smr_deleted_thread_time_max; + uint cur_value = _smr_deleted_thread_time_max; if (new_value <= cur_value) { // No need to update max value so we're done. break; @@ -243,7 +243,7 @@ } } -inline void Threads::add_smr_deleted_thread_times(jint add_value) { +inline void Threads::add_smr_deleted_thread_times(uint add_value) { Atomic::add(add_value, &_smr_deleted_thread_times); } @@ -251,9 +251,9 @@ Atomic::inc(&_smr_tlh_cnt); } -inline void Threads::update_smr_tlh_time_max(jint new_value) { +inline void Threads::update_smr_tlh_time_max(uint new_value) { while (true) { - jint cur_value = _smr_tlh_time_max; + uint cur_value = _smr_tlh_time_max; if (new_value <= cur_value) { // No need to update max value so we're done. break; @@ -265,7 +265,7 @@ } } -inline void Threads::add_smr_tlh_times(jint add_value) { +inline void Threads::add_smr_tlh_times(uint add_value) { Atomic::add(add_value, &_smr_tlh_times); } --- old/src/hotspot/share/runtime/threadSMR.cpp Tue Nov 21 15:20:46 2017 +++ new/src/hotspot/share/runtime/threadSMR.cpp Tue Nov 21 15:20:45 2017 @@ -29,7 +29,7 @@ #include "services/threadService.hpp" // 'entries + 1' so we always have at least one entry. -ThreadsList::ThreadsList(int entries) : _length(entries), _threads(NEW_C_HEAP_ARRAY(JavaThread*, entries + 1, mtGC)), _next_list(NULL) { +ThreadsList::ThreadsList(int entries) : _length(entries), _threads(NEW_C_HEAP_ARRAY(JavaThread*, entries + 1, mtThread)), _next_list(NULL) { *(JavaThread**)(_threads + entries) = NULL; // Make sure the extra entry is NULL. } @@ -61,7 +61,7 @@ Threads::release_stable_list(_self); if (EnableThreadSMRStatistics) { _timer.stop(); - jint millis = (jint)_timer.milliseconds(); + uint millis = (uint)_timer.milliseconds(); Threads::inc_smr_tlh_cnt(); Threads::add_smr_tlh_times(millis); Threads::update_smr_tlh_time_max(millis); --- old/src/hotspot/share/runtime/threadSMR.hpp Tue Nov 21 15:20:48 2017 +++ new/src/hotspot/share/runtime/threadSMR.hpp Tue Nov 21 15:20:48 2017 @@ -28,6 +28,55 @@ #include "memory/allocation.hpp" #include "runtime/timer.hpp" +// Thread Safe Memory Reclaimation (Thread-SMR) support. +// +// ThreadsListHandles are used to safely perform operations on one or more +// threads without the risk of the thread or threads exiting during the +// operation. It is no longer necessary to hold the Threads_lock to safely +// perform an operation on a target thread. +// +// There are several different ways to refer to java.lang.Thread objects +// so we have a few ways to get a protected JavaThread *: +// +// JNI jobject example: +// jobject jthread = ...; +// : +// ThreadsListHandle tlh; +// JavaThread* jt = NULL; +// bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &jt, NULL); +// if (is_alive) { +// : // do stuff with 'jt'... +// } +// +// JVM/TI jthread example: +// jthread thread = ...; +// : +// JavaThread* jt = NULL; +// ThreadsListHandle tlh; +// jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &jt, NULL); +// if (err != JVMTI_ERROR_NONE) { +// return err; +// } +// : // do stuff with 'jt'... +// +// JVM/TI oop example (this one should be very rare): +// oop thread_obj = ...; +// : +// JavaThread *jt = NULL; +// ThreadsListHandle tlh; +// jvmtiError err = JvmtiExport::cv_oop_to_JavaThread(tlh.list(), thread_obj, &jt); +// if (err != JVMTI_ERROR_NONE) { +// return err; +// } +// : // do stuff with 'jt'... +// +// A JavaThread * that is included in the ThreadsList that is held by +// a ThreadsListHandle is protected as long as the ThreadsListHandle +// remains in scope. The target JavaThread * may have logically exited, +// but that target JavaThread * will not be deleted until it is no +// longer protected by a ThreadsListHandle. + + // A fast list of JavaThreads. // class ThreadsList : public CHeapObj { @@ -183,7 +232,7 @@ uint _index; public: - JavaThreadIteratorWithHandle() : _tlh(), _index(0) {} + JavaThreadIteratorWithHandle() : _index(0) {} uint length() const { return _tlh.length(); --- old/src/hotspot/share/runtime/vm_operations.hpp Tue Nov 21 15:20:51 2017 +++ new/src/hotspot/share/runtime/vm_operations.hpp Tue Nov 21 15:20:50 2017 @@ -403,8 +403,8 @@ VM_FindDeadlocks(outputStream* st) : _concurrent_locks(true), _out(st), _deadlocks(NULL) {}; ~VM_FindDeadlocks(); - DeadlockCycle* result() { return _deadlocks; }; - VMOp_Type type() const { return VMOp_FindDeadlocks; } + DeadlockCycle* result() { return _deadlocks; }; + VMOp_Type type() const { return VMOp_FindDeadlocks; } void doit(); bool doit_prologue(); }; --- old/test/hotspot/jtreg/runtime/ErrorHandling/ErrorHandler.java Tue Nov 21 15:20:54 2017 +++ new/test/hotspot/jtreg/runtime/ErrorHandling/ErrorHandler.java Tue Nov 21 15:20:53 2017 @@ -23,6 +23,7 @@ /* * @test + * @requires (vm.debug == true) * @bug 6888954 * @bug 8015884 * @summary Exercise HotSpot error handling code by invoking java with @@ -39,6 +40,7 @@ public class ErrorHandler { public static OutputAnalyzer runTest(int testcase) throws Exception { + // The -XX:ErrorHandlerTest=N option requires debug bits. return new OutputAnalyzer( ProcessTools.createJavaProcessBuilder( "-XX:-TransmitErrorReport", "-XX:-CreateCoredumpOnCrash", "-XX:ErrorHandlerTest=" + testcase) @@ -46,10 +48,6 @@ } public static void main(String[] args) throws Exception { - // Test is only applicable for debug builds - if (!Platform.isDebugBuild()) { - return; - } // Keep this in sync with hotspot/src/share/vm/utilities/debug.cpp int i = 1; String[] strings = { --- old/test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java Tue Nov 21 15:20:56 2017 +++ new/test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java Tue Nov 21 15:20:55 2017 @@ -33,6 +33,7 @@ /* * @test + * @requires (vm.debug == true) * @bug 8167108 * @summary Nested ThreadsListHandle info should be in error handling output. * @modules java.base/jdk.internal.misc @@ -47,11 +48,7 @@ public class NestedThreadsListHandleInErrorHandlingTest { public static void main(String[] args) throws Exception { - if (!Platform.isDebugBuild()) { - // -XX:ErrorHandlerTest=N option requires debug bits. - return; - } - + // The -XX:ErrorHandlerTest=N option requires debug bits. ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-Xmx100M", --- old/test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java Tue Nov 21 15:20:59 2017 +++ new/test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java Tue Nov 21 15:20:58 2017 @@ -33,6 +33,7 @@ /* * @test + * @requires (vm.debug == true) * @bug 8167108 * @summary ThreadsListHandle info should be in error handling output. * @modules java.base/jdk.internal.misc @@ -47,11 +48,7 @@ public class ThreadsListHandleInErrorHandlingTest { public static void main(String[] args) throws Exception { - if (!Platform.isDebugBuild()) { - // -XX:ErrorHandlerTest=N option requires debug bits. - return; - } - + // The -XX:ErrorHandlerTest=N option requires debug bits. ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-Xmx100M",