diff --git a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 6aa4cb1fd..68719a627 100644 --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -2364,7 +2364,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, } if (EnableCoroutine) { - __ movptr(r11, Address(r15_thread, JavaThread::coroutine_list_offset())); + __ movptr(r11, Address(r15_thread, JavaThread::thread_coroutine_offset())); __ incrementl(Address(r11, Coroutine::native_call_counter_offset())); } diff --git a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 2cb651f4f..46e309dc2 100644 --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -1210,7 +1210,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) { #endif if (EnableCoroutine) { - __ movptr(t, Address(r15_thread, JavaThread::coroutine_list_offset())); + __ movptr(t, Address(r15_thread, JavaThread::thread_coroutine_offset())); __ incrementl(Address(t, Coroutine::native_call_counter_offset())); } diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 2602f3d6d..a2a8dc834 100644 --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -2672,7 +2672,7 @@ class CMSATBBufferClosure : public SATBBufferClosure { } }; -class G1RemarkThreadsClosure : public ThreadClosure { +class G1RemarkThreadsClosure : public ThreadClosure, public CoroutineClosure { CMSATBBufferClosure _cm_satb_cl; G1CMOopClosure _cm_cl; MarkingCodeBlobClosure _code_cl; @@ -2707,6 +2707,12 @@ class G1RemarkThreadsClosure : public ThreadClosure { } } } + + void do_coroutine(Coroutine* coroutine) { + if(coroutine->claim_oops_do(_is_par, _thread_parity)) { + coroutine->nmethods_do(&_code_cl); + } + } }; class CMRemarkTask: public AbstractGangTask { @@ -2726,6 +2732,7 @@ class CMRemarkTask: public AbstractGangTask { G1RemarkThreadsClosure threads_f(G1CollectedHeap::heap(), task, !_is_serial); Threads::threads_do(&threads_f); + Coroutine::coroutines_do(&threads_f); } do { diff --git a/src/share/vm/jfr/leakprofiler/checkpoint/rootResolver.cpp b/src/share/vm/jfr/leakprofiler/checkpoint/rootResolver.cpp index 083443153..6cdfcd08b 100644 --- a/src/share/vm/jfr/leakprofiler/checkpoint/rootResolver.cpp +++ b/src/share/vm/jfr/leakprofiler/checkpoint/rootResolver.cpp @@ -389,6 +389,13 @@ bool ReferenceToThreadRootClosure::do_java_threads_oops(JavaThread* jt) { ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_global_jni_handle, jt); jt->oops_do(&rcl, NULL, NULL); + if (EnableCoroutine) { + ALL_JAVA_COROUTINES(c) { + if (c->thread() == jt) { + c->oops_do(&rcl, NULL, NULL); + } + } + } return rcl.complete(); } diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp index 8304bf69b..e4bf59660 100644 --- a/src/share/vm/prims/jvm.cpp +++ b/src/share/vm/prims/jvm.cpp @@ -3567,7 +3567,7 @@ JVM_QUICK_ENTRY(jboolean, JVM_IsInSameNative(JNIEnv* env, jobject jthread)) // the thread is in native status and the native call counter isn't changed during two calls // then return true if (thr != NULL && thr->thread_state() == _thread_in_native) { - Coroutine* coro = thr->coroutine_list(); + Coroutine* coro = thr->thread_coroutine(); assert(coro != NULL, "coroutine list"); if (coro->last_native_call_counter() == coro->native_call_counter()) { return JNI_TRUE; diff --git a/src/share/vm/prims/unsafe.cpp b/src/share/vm/prims/unsafe.cpp index 666d56da3..c8fbc8bc2 100644 --- a/src/share/vm/prims/unsafe.cpp +++ b/src/share/vm/prims/unsafe.cpp @@ -1365,7 +1365,7 @@ JVM_ENTRY(jlong, CoroutineSupport_getNativeThreadCoroutine(JNIEnv* env, jclass k DEBUG_CORO_PRINT("CoroutineSupport_getNativeThreadCoroutine\n"); assert(EnableCoroutine, "pre-condition"); - Coroutine* list = thread->coroutine_list(); + Coroutine* list = thread->thread_coroutine(); assert(list != NULL, "thread isn't initialized for coroutines"); return (jlong)list; @@ -1383,11 +1383,10 @@ JVM_ENTRY(void, CoroutineSupport_switchToAndTerminate(JNIEnv* env, jclass klass, oop old_oop = JNIHandles::resolve(old_coroutine); Coroutine* coro = (Coroutine*)java_dyn_CoroutineBase::data(old_oop); assert(coro != NULL, "NULL old coroutine in switchToAndTerminate"); - java_dyn_CoroutineBase::set_data(old_oop, 0); CoroutineStack::free_stack(coro->stack(), thread); - delete coro; + coro->clean_up(); JVM_END JVM_ENTRY(void, CoroutineSupport_switchToAndExit(JNIEnv* env, jclass klass, jobject old_coroutine, jobject target_coroutine)) @@ -1414,7 +1413,7 @@ JVM_ENTRY(jlong, CoroutineSupport_createCoroutine(JNIEnv* env, jclass klass, job if (coro == NULL) { THROW_0(vmSymbols::java_lang_OutOfMemoryError()); } - coro->insert_into_list(thread->coroutine_list()); + coro->insert(); return (jlong)coro; JVM_END @@ -1429,7 +1428,7 @@ JVM_ENTRY(jboolean, CoroutineSupport_testDisposableAndTryReleaseStack(JNIEnv* en jboolean is_disposable = coro->is_disposable(); if (is_disposable) { CoroutineStack::free_stack(coro->stack(), thread); - delete coro; + coro->clean_up(); } return is_disposable; JVM_END @@ -1449,18 +1448,18 @@ JVM_ENTRY(void, CoroutineSupport_setWispBooted(JNIEnv* env, jclass klass)) WispThread::set_wisp_booted(thread); JVM_END -JVM_ENTRY (jobject, CoroutineSupport_getNextCoroutine(JNIEnv* env, jclass klass, jlong coroPtr)) +JVM_ENTRY(void, CoroutineSupport_markAsCarrier(JNIEnv* env, jclass klass)) + DEBUG_CORO_PRINT("CoroutineSupport_markAsCarrier\n"); assert(EnableCoroutine, "pre-condition"); - Coroutine* coro = (Coroutine*)coroPtr; - assert (coro->next()->coroutine() != NULL, "coroutine oop can't be null"); - return JNIHandles::make_local(env, coro->next()->coroutine()); + //Coroutine::mark_as_carrier(thread); JVM_END -JVM_ENTRY (void, CoroutineSupport_moveCoroutine(JNIEnv* env, jclass klass, jlong coroPtr, jlong targetPtr)) + +JVM_ENTRY (jobject, CoroutineSupport_getNextCoroutine(JNIEnv* env, jclass klass, jlong coroPtr)) assert(EnableCoroutine, "pre-condition"); Coroutine* coro = (Coroutine*)coroPtr; - Coroutine* target = (Coroutine*)targetPtr; - Coroutine::move(coro, target); + Coroutine* next = coro->next_coroutine(coro->thread()); + return JNIHandles::make_local(env, next->coroutine()); JVM_END JVM_ENTRY (void, CoroutineSupport_markThreadCoroutine(JNIEnv* env, jclass klass, jlong coroPtr, jobject coroObj)) @@ -1486,8 +1485,6 @@ JVM_ENTRY(jboolean, CoroutineSupport_stealCoroutine(JNIEnv* env, jclass klass, j } assert(coro->thread() != thread, "steal from self"); assert(coro->state() != Coroutine::_current, "running"); - coro->remove_from_list(coro->thread()->coroutine_list()); - coro->insert_into_list(thread->coroutine_list()); // change thread logic if (coro->last_handle_mark() != NULL) { coro->last_handle_mark()->change_thread_for_wisp(thread); @@ -1873,9 +1870,9 @@ JNINativeMethod coroutine_support_methods[] = { CC"(J)Z", FN_PTR(CoroutineSupport_testDisposableAndTryReleaseStack)}, {CC"cleanupCoroutine", CC"()"COBA, FN_PTR(CoroutineSupport_cleanupCoroutine)}, {CC"setWispBooted", CC"()V", FN_PTR(CoroutineSupport_setWispBooted)}, + {CC"markAsCarrier", CC"()V", FN_PTR(CoroutineSupport_markAsCarrier)}, {CC"stealCoroutine", CC"(J)Z", FN_PTR(CoroutineSupport_stealCoroutine)}, {CC"getNextCoroutine", CC"(J)"COR, FN_PTR(CoroutineSupport_getNextCoroutine)}, - {CC"moveCoroutine", CC"(JJ)V", FN_PTR(CoroutineSupport_moveCoroutine)}, {CC"markThreadCoroutine", CC"(J"COBA")V", FN_PTR(CoroutineSupport_markThreadCoroutine)}, {CC"shouldThrowException0", CC"(J)Z", FN_PTR(CoroutineSupport_shouldThrowException0)}, {CC"getCoroutineStack", CC"(J)["STE, FN_PTR(CoroutineSupport_getCoroutineStack)}, diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp index aa3da61a3..bdc42db04 100644 --- a/src/share/vm/runtime/arguments.cpp +++ b/src/share/vm/runtime/arguments.cpp @@ -4146,6 +4146,12 @@ jint Arguments::parse(const JavaVMInitArgs* args) { } #endif + if (EnableCoroutine && UseParallelGC) { + warning("ParallelGC is not supported with Wisp" + "; ignoring EnableCoroutine flag." ); + FLAG_SET_DEFAULT(EnableCoroutine, false); + FLAG_SET_DEFAULT(UseWispMonitor, false); + } // Set object alignment values. set_object_alignment(); diff --git a/src/share/vm/runtime/coroutine.cpp b/src/share/vm/runtime/coroutine.cpp index ce79ba8ed..4c652be35 100644 --- a/src/share/vm/runtime/coroutine.cpp +++ b/src/share/vm/runtime/coroutine.cpp @@ -73,6 +73,10 @@ void coroutine_start(Coroutine* coroutine, jobject coroutineObj) { } #endif +Coroutine* Coroutine::_coroutineHead = NULL; +Mutex* Coroutine::_coroutine_list_lock = NULL; +bool Coroutine::_need_clean_up = false; + void Coroutine::run(jobject coroutine) { // do not call JavaThread::current() here! @@ -127,6 +131,9 @@ Coroutine* Coroutine::create_thread_coroutine(JavaThread* thread, CoroutineStack coro->_clinit_call_counter = 0; coro->_wisp_post_steal_resource_area = NULL; coro->_is_yielding = false; + coro->_has_coroutine = false; + // This initial value ==> never claimed. + coro->_oops_do_parity = 0; thread->set_current_coroutine(coro); return coro; } @@ -181,15 +188,26 @@ Coroutine* Coroutine::create_coroutine(JavaThread* thread, CoroutineStack* stack coro->_clinit_call_counter = 0; coro->_wisp_post_steal_resource_area = new (mtWisp) WispResourceArea(coro, 32); coro->_is_yielding = false; + coro->_has_coroutine = false; + // This initial value ==> never claimed. + coro->_oops_do_parity = 0; + thread->thread_coroutine()->_has_coroutine = true; return coro; } Coroutine::~Coroutine() { - remove_from_list(_thread->coroutine_list()); + assert(_state == Coroutine::_dead, "dead Coroutine"); + assert(_wisp_thread == NULL, "cleanup"); + assert(_wisp_post_steal_resource_area == NULL, "cleanup"); +} + +void Coroutine::clean_up() { if (_wisp_thread != NULL) { delete _wisp_thread; + _wisp_thread = NULL; } delete _wisp_post_steal_resource_area; + _wisp_post_steal_resource_area = NULL; if (!_is_thread_coroutine && _state != Coroutine::_created) { assert(_resource_area != NULL, "_resource_area is NULL"); assert(_handle_area != NULL, "_handle_area is NULL"); @@ -200,6 +218,16 @@ Coroutine::~Coroutine() { JNIHandleBlock::release_block(active_handles(), _thread); //allocated from JavaCalls::call_virtual during coroutine's first running } + _thread = NULL; + _wisp_task = NULL; + _wisp_engine = NULL; + _wisp_task = NULL; + _coroutine = NULL; + _state = Coroutine::_dead; + _metadata_handles = NULL; + _resource_area = NULL; + _handle_area = NULL; + _need_clean_up = true; } void Coroutine::frames_do(FrameClosure* fc) { @@ -285,6 +313,88 @@ bool Coroutine::in_critical(JavaThread* thread) { return true; } +// In Wisp2, the coroutine can be stolen from other carrier. +// For all the carriers, we mark it as true +void Coroutine::mark_as_carrier(JavaThread* thread) { + thread->thread_coroutine()->_has_coroutine = true; +} + +void Coroutine::coroutines_do(CoroutineClosure* cc) { + ALL_JAVA_COROUTINES(c) { + cc->do_coroutine(c); + } +} + +static void frame_verify(frame* f, const RegisterMap *map) { f->verify(map); } + + +void Coroutine::verify() { + if (EnableCoroutine) { + oops_do(&VerifyOopClosure::verify_oop, NULL, NULL); + frames_do(frame_verify); + } +} + +// For global coroutine list, use the thread coroutine of main thread as header +void Coroutine::init_global_coroutine_list(JavaThread* thread) { + thread->thread_coroutine()->insert_into_list(_coroutineHead); + _coroutine_list_lock = new Mutex(Mutex::native, "coroutine list lock", false); +} + +void Coroutine::insert() { + MutexLockerEx ml(_coroutine_list_lock, Mutex::_no_safepoint_check_flag); + insert_into_list(_coroutineHead); +} + +void Coroutine::delete_exited_coroutines() { + assert(SafepointSynchronize::is_at_safepoint(), "should be in safepoint"); + if (_need_clean_up == false) { + return; + } + _coroutine_list_lock->lock_without_safepoint_check(); + Coroutine* node = _coroutineHead ? _coroutineHead->next() : NULL; + Coroutine* next_node = NULL; + for ( ; node != NULL && node != _coroutineHead; ) { + next_node = node->next(); + if (node->_state == _dead && node->_thread == NULL) { + node->remove_from_list(_coroutineHead); + delete node; + } + node = next_node; + } + _coroutine_list_lock->unlock(); + _need_clean_up = false; +} + +Coroutine* Coroutine::next_coroutine(JavaThread* thread) { + Coroutine* node = NULL; + int loop = 0; + if (_is_thread_coroutine) { + if (!_has_coroutine) { + return thread->thread_coroutine(); + } + node = _coroutineHead; + } else { + node = next(); + } + while(node) { + if (node == this) { + return NULL; + } else if (node->_thread == thread) { + return node; + } else if (node == _coroutineHead) { + loop++; + if (loop > 1) { + return NULL; + } + node = node->next(); + } else { + node = node->next(); + } + } + return thread->thread_coroutine(); +} + class oops_do_Closure: public FrameClosure { private: OopClosure* _f; @@ -295,6 +405,25 @@ class oops_do_Closure: public FrameClosure { void frames_do(frame* fr, RegisterMap* map) { fr->oops_do(_f, _cld_f, _cf, map); } }; +// GC support +bool Coroutine::claim_oops_do_par_case(int strong_roots_parity) { + jint coroutine_parity = _oops_do_parity; + if (coroutine_parity != strong_roots_parity) { + jint res = Atomic::cmpxchg(strong_roots_parity, &_oops_do_parity, coroutine_parity); + if (res == coroutine_parity) { + return true; + } else { + guarantee(res == strong_roots_parity, "Or else what?"); + assert(SharedHeap::heap()->workers()->active_workers() > 0, + "Should only fail when parallel."); + return false; + } + } + assert(SharedHeap::heap()->workers()->active_workers() > 0, + "Should only fail when parallel."); + return false; +} + void Coroutine::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) { oops_do_Closure fc(f, cld_f, cf); frames_do(&fc); @@ -1193,7 +1322,7 @@ bool WispPostStealHandleUpdateMark::check(JavaThread *current, bool sp) { assert(current == JavaThread::current(), "must be"); Coroutine *coroutine = current->current_coroutine(); if (!EnableCoroutine || - coroutine == current->coroutine_list() || + coroutine == current->thread_coroutine() || // if we won't steal it, then no need to allocate handles. coroutine->enable_steal_count() != (sp ? current->java_call_counter()+1 : current->java_call_counter())) { _success = false; diff --git a/src/share/vm/runtime/coroutine.hpp b/src/share/vm/runtime/coroutine.hpp index ca4996fa5..f8b4b1940 100644 --- a/src/share/vm/runtime/coroutine.hpp +++ b/src/share/vm/runtime/coroutine.hpp @@ -49,7 +49,7 @@ class Coroutine; class CoroutineStack; class WispThread; - +class CoroutineClosure; template class DoublyLinkedList { @@ -67,7 +67,6 @@ class DoublyLinkedList { void remove_from_list(pointer& list); void insert_into_list(pointer& list); - static void move(pointer& coro, pointer& target); T* last() const { return _last; } T* next() const { return _next; } @@ -87,7 +86,7 @@ class Coroutine: public CHeapObj, public DoublyLinkedList, public DoublyLinkedList, public DoublyLinkedList, public DoublyLinkedList, public DoublyLinkedList void DoublyLinkedList::insert_into_list(pointer& list) { } } -template void DoublyLinkedList::move(pointer &coro, pointer &target) { - assert(coro != NULL, "coroutine can't be null"); - assert(target != NULL, "target can't be null"); - assert(coro != target, "target can't be equal to current"); - - // remove current coro from the ring - coro->_last->_next = coro->_next; - coro->_next->_last = coro->_last; - - // insert at new position - coro->_next = target->_next; - coro->_last = target; - coro->_next->_last = coro; - target->_next = coro; -} - class ObjectWaiter; class WispThread: public JavaThread { @@ -621,6 +637,14 @@ class WispClinitCounterMark : public StackObj { JavaThread* _thread; }; +class CoroutineClosure: public StackObj { + public: + virtual void do_coroutine(Coroutine* coroutine) = 0; +}; + +// All Coroutines +#define ALL_JAVA_COROUTINES(X) for (Coroutine* X = Coroutine::get_coroutine_head() ? Coroutine::get_coroutine_head()->next() : NULL; X && X != Coroutine::get_coroutine_head(); X = X->next()) + bool clear_interrupt_for_wisp(Thread *); #endif // SHARE_VM_RUNTIME_COROUTINE_HPP diff --git a/src/share/vm/runtime/safepoint.cpp b/src/share/vm/runtime/safepoint.cpp index 6b12a8997..91f9cacd1 100644 --- a/src/share/vm/runtime/safepoint.cpp +++ b/src/share/vm/runtime/safepoint.cpp @@ -692,6 +692,10 @@ void SafepointSynchronize::do_cleanup_tasks() { TraceTime t7("purging class loader data graph", TraceSafepointCleanupTime); ClassLoaderDataGraph::purge_if_needed(); } + + if (EnableCoroutine) { + Coroutine::delete_exited_coroutines(); + } } diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp index c79502722..59c6ddca5 100644 --- a/src/share/vm/runtime/thread.cpp +++ b/src/share/vm/runtime/thread.cpp @@ -1533,7 +1533,7 @@ void JavaThread::initialize() { _special_runtime_exit_condition = _no_async_condition; _pending_async_exception = NULL; - _coroutine_list = NULL; + _thread_coroutine = NULL; _current_coroutine = NULL; _wisp_preempted = false; @@ -1672,9 +1672,11 @@ JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : } JavaThread::~JavaThread() { - while (EnableCoroutine && coroutine_list() != NULL) { - CoroutineStack::free_stack(coroutine_list()->stack(), this); - delete coroutine_list(); + if (EnableCoroutine && _thread_coroutine != NULL) { + CoroutineStack::free_stack(_thread_coroutine->stack(), this); + if (_thread_coroutine != Coroutine::get_coroutine_head()) { + delete _thread_coroutine; + } } if (TraceThreadEvents) { @@ -1975,8 +1977,7 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { threadObj, thread_klass, vmSymbols::destroyCoroutineSupport_method_name(), vmSymbols::void_method_signature(), THREAD); - assert(_current_coroutine == _coroutine_list, "not thread coroutine"); - assert(_coroutine_list->next() == _coroutine_list, "ensure all coroutine has benn killed"); + assert(_current_coroutine == _thread_coroutine, "not thread coroutine"); CLEAR_PENDING_EXCEPTION; } @@ -2918,16 +2919,12 @@ void JavaThread::frames_do(void f(frame*, const RegisterMap* map)) { f(fr, fst.register_map()); } if (EnableCoroutine) { - // traverse the coroutine stack frames - Coroutine* current = _coroutine_list; - do { - current->frames_do(f); - current = current->next(); - } while (current != _coroutine_list); + assert(_thread_coroutine != NULL, "sanity"); + Coroutine* c = _thread_coroutine; + c->frames_do(f); } } - #ifndef PRODUCT // Deoptimization // Function for testing deoptimization @@ -3019,6 +3016,9 @@ void JavaThread::gc_epilogue() { frames_do(frame_gc_epilogue); } +void Coroutine::gc_epilogue() { + frames_do(frame_gc_epilogue); +} static void frame_gc_prologue(frame* f, const RegisterMap* map) { f->gc_prologue(); } @@ -3026,6 +3026,10 @@ void JavaThread::gc_prologue() { frames_do(frame_gc_prologue); } +void Coroutine::gc_prologue() { + frames_do(frame_gc_prologue); +} + // If the caller is a NamedThread, then remember, in the current scope, // the given JavaThread in its _processed_thread field. class RememberProcessedThread: public StackObj { @@ -3087,14 +3091,10 @@ void JavaThread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) fst.current()->oops_do(f, cld_f, cf, fst.register_map()); } } - - if (EnableCoroutine) { - Coroutine* current = _coroutine_list; - do { - current->oops_do(f, cld_f, cf); - current = current->next(); - } while (current != _coroutine_list); + assert(_thread_coroutine != NULL, "sanity"); + Coroutine* c = _thread_coroutine; + c->oops_do(f, cld_f, cf); } // callee_target is never live across a gc point so NULL it here should @@ -3140,11 +3140,9 @@ void JavaThread::nmethods_do(CodeBlobClosure* cf) { } if (EnableCoroutine) { - Coroutine* current = _coroutine_list; - do { - current->nmethods_do(cf); - current = current->next(); - } while (current != _coroutine_list); + assert(_thread_coroutine != NULL, "sanity"); + Coroutine* c = _thread_coroutine; + c->nmethods_do(cf); } } @@ -3164,11 +3162,9 @@ void JavaThread::metadata_do(void f(Metadata*)) { } if (EnableCoroutine) { - Coroutine* current = _coroutine_list; - do { - current->metadata_do(f); - current = current->next(); - } while (current != _coroutine_list); + assert(_thread_coroutine != NULL, "sanity"); + Coroutine* c = _thread_coroutine; + c->metadata_do(f); } } @@ -3960,6 +3956,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { Metaspace::post_initialize(); if (EnableCoroutine) { + Coroutine::init_global_coroutine_list((JavaThread*) THREAD); call_startWispDaemons(THREAD); if (HAS_PENDING_EXCEPTION) { vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); @@ -4590,6 +4587,11 @@ void Threads::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) { ALL_JAVA_THREADS(p) { p->oops_do(f, cld_f, cf); } + if (EnableCoroutine) { + ALL_JAVA_COROUTINES(c) { + c->oops_do(f, cld_f, cf); + } + } VMThread::vm_thread()->oops_do(f, cld_f, cf); } @@ -4613,6 +4615,14 @@ void Threads::possibly_parallel_oops_do(OopClosure* f, CLDClosure* cld_f, CodeBl p->oops_do(f, cld_f, cf); } } + if (EnableCoroutine) { + ALL_JAVA_COROUTINES(c) { + if (c->claim_oops_do(is_par, cp)) { + c->oops_do(f, cld_f, cf); + } + } + } + VMThread* vmt = VMThread::vm_thread(); if (vmt->claim_oops_do(is_par, cp)) { vmt->oops_do(f, cld_f, cf); @@ -4641,6 +4651,11 @@ void Threads::nmethods_do(CodeBlobClosure* cf) { ALL_JAVA_THREADS(p) { p->nmethods_do(cf); } + if (EnableCoroutine) { + ALL_JAVA_COROUTINES(c) { + c->nmethods_do(cf); + } + } VMThread::vm_thread()->nmethods_do(cf); } @@ -4648,18 +4663,33 @@ void Threads::metadata_do(void f(Metadata*)) { ALL_JAVA_THREADS(p) { p->metadata_do(f); } + if (EnableCoroutine) { + ALL_JAVA_COROUTINES(c) { + c->metadata_do(f); + } + } } void Threads::gc_epilogue() { ALL_JAVA_THREADS(p) { p->gc_epilogue(); } + if (EnableCoroutine) { + ALL_JAVA_COROUTINES(c) { + c->gc_epilogue(); + } + } } void Threads::gc_prologue() { ALL_JAVA_THREADS(p) { p->gc_prologue(); } + if (EnableCoroutine) { + ALL_JAVA_COROUTINES(c) { + c->gc_prologue(); + } + } } void Threads::deoptimized_wrt_marked_nmethods() { @@ -4704,20 +4734,24 @@ JavaThread *Threads::owning_thread_from_monitor_owner(address owner, bool doLock { MutexLockerEx ml(doLock ? Threads_lock : NULL); - ALL_JAVA_THREADS(p) { - // first, see if owner is the address of a Java thread - if (UseWispMonitor) { - if (p->coroutine_list()) { - Coroutine* c = p->coroutine_list(); - do { - if ((address) c->wisp_thread() == owner) { - return c->wisp_thread(); - } - c = c->next(); - } while (c != p->coroutine_list()); + if (UseWispMonitor) { + ALL_JAVA_THREADS(p) { + Coroutine* c = p->thread_coroutine(); + if ((address) c->wisp_thread() == owner) { + return c->wisp_thread(); + } + } + ALL_JAVA_COROUTINES(c) { + if ((address) c->wisp_thread() == owner) { + return c->wisp_thread(); + } + } + } else { + ALL_JAVA_THREADS(p) { + // first, see if owner is the address of a Java thread + if (owner == (address)p) { + return p; } - } else if (owner == (address)p) { - return p; } } } @@ -4734,21 +4768,28 @@ JavaThread *Threads::owning_thread_from_monitor_owner(address owner, bool doLock JavaThread* the_owner = NULL; { MutexLockerEx ml(doLock ? Threads_lock : NULL); - ALL_JAVA_THREADS(q) { - if (UseWispMonitor) { - if (q->coroutine_list()) { - Coroutine* c = q->coroutine_list(); - do { - if (c->wisp_thread()->is_lock_owned(owner)) { - the_owner = c->wisp_thread(); - break; - } - c = c->next(); - } while (c != q->coroutine_list()); + if (UseWispMonitor) { + ALL_JAVA_THREADS(p) { + Coroutine* c = p->thread_coroutine(); + if (c->wisp_thread()->is_lock_owned(owner)) { + the_owner = c->wisp_thread(); + break; + } + } + if (the_owner == NULL) { + ALL_JAVA_COROUTINES(c) { + if (c->wisp_thread()->is_lock_owned(owner)) { + the_owner = c->wisp_thread(); + break; + } + } + } + } else { + ALL_JAVA_THREADS(q) { + if (q->is_lock_owned(owner)) { + the_owner = q; + break; } - } else if (q->is_lock_owned(owner)) { - the_owner = q; - break; } } } @@ -4785,16 +4826,19 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format } else { p->print_stack_on(st); if (EnableCoroutine) { - assert(p->coroutine_list() != NULL, "coroutine list"); if (!p->is_Compiler_thread() && (PrintThreadCoroutineInfo || !p->current_coroutine()->is_thread_coroutine())) { p->current_coroutine()->print_stack_header_on(st); st->print("\n"); } - Coroutine* c = p->coroutine_list(); - do { - c->print_stack_on(st); - c = c->next(); - } while (c != p->coroutine_list()); + Coroutine* c = p->thread_coroutine(); + c->print_stack_on(st); + if (c->has_coroutine()) { + ALL_JAVA_COROUTINES(c) { + if (c->thread() == p) { + c->print_stack_on(st); + } + } + } } } } @@ -5142,8 +5186,11 @@ void Threads::verify() { } VMThread* thread = VMThread::vm_thread(); if (thread != NULL) thread->verify(); + ALL_JAVA_COROUTINES(c) { + c->verify(); + } } void JavaThread::initialize_coroutine_support() { - Coroutine::create_thread_coroutine(this, CoroutineStack::create_thread_stack(this))->insert_into_list(_coroutine_list); + _thread_coroutine = Coroutine::create_thread_coroutine(this, CoroutineStack::create_thread_stack(this)); } diff --git a/src/share/vm/runtime/thread.hpp b/src/share/vm/runtime/thread.hpp index c2dbd5d02..27a70d163 100644 --- a/src/share/vm/runtime/thread.hpp +++ b/src/share/vm/runtime/thread.hpp @@ -984,14 +984,14 @@ class JavaThread: public Thread { int _frames_to_pop_failed_realloc; // coroutine support - Coroutine* _coroutine_list; + Coroutine* _thread_coroutine; Coroutine* _current_coroutine; bool _wisp_preempted; intptr_t _coroutine_temp; public: - Coroutine*& coroutine_list() { return _coroutine_list; } + Coroutine* thread_coroutine() { return _thread_coroutine; } Coroutine* current_coroutine() { return _current_coroutine; } void set_current_coroutine(Coroutine *coro) { _current_coroutine = coro; } bool wisp_preempted() const { return _wisp_preempted; } @@ -1454,7 +1454,7 @@ class JavaThread: public Thread { static ByteSize stack_guard_state_offset() { return byte_offset_of(JavaThread, _stack_guard_state ); } static ByteSize suspend_flags_offset() { return byte_offset_of(JavaThread, _suspend_flags ); } static ByteSize java_call_counter_offset() { return byte_offset_of(JavaThread, _java_call_counter); } - static ByteSize coroutine_list_offset() { return byte_offset_of(JavaThread, _coroutine_list); } + static ByteSize thread_coroutine_offset() { return byte_offset_of(JavaThread, _thread_coroutine); } static ByteSize do_not_unlock_if_synchronized_offset() { return byte_offset_of(JavaThread, _do_not_unlock_if_synchronized); } static ByteSize should_post_on_exceptions_flag_offset() { diff --git a/test/runtime/coroutine/MemLeakTest.java b/test/runtime/coroutine/MemLeakTest.java index e44be29be..f4ea306f2 100644 --- a/test/runtime/coroutine/MemLeakTest.java +++ b/test/runtime/coroutine/MemLeakTest.java @@ -50,6 +50,7 @@ private static void testThreadCoroutineLeak() throws Exception { t.join(); } + int rss0 = getRssInKb(); System.out.println(rss0); @@ -78,7 +79,6 @@ private static void testUserCreatedCoroutineLeak() throws Exception { Coroutine target = new Coroutine(r); Coroutine.yieldTo(target); // switch to new created coroutine and let it die } - int rss0 = getRssInKb(); System.out.println(rss0);