From adffc51867266d53e087ceed021912ac7426180b Mon Sep 17 00:00:00 2001 From: Xiaomin Date: Mon, 24 Jul 2023 10:41:22 +0800 Subject: [PATCH] [Misc] Fix bugs in previous commit. Summary: 1. Fix StackOverflow casued by coroutine switch. Coroutine switch should update thread stack information correctly. 2. Make SharedRuntime::monitor_exit_helper can work in JRT_LEAF(no safepoint) for coroutine. 3. _class_to_be_initialized should be bound to WispThread in UseWispMonitor. 4. Thread constructor's thread id is protected by synchronized. It may introduce another unintended context switch which cause assertion failure. Use AtomicInteger instead to avoid it. 5. Fix macros THREAD do not change to WispThread when enable UseWispMonitor. Therefore, methods that use THREAD will do uncorrectly. 6. Update thread object for coroutine WispThread. Refine print_stack_header_on to not return oop. 7. Fix Exceptions::_throw_msg use wrong thread in Wisp. 8. Fix setThreadWrapper in WispTask. Add method to print info in native to avoid synchroize. 9. Fix ReservedStackTest crash in slowdebug. The crash root cause is stack_guard_state is inconsistent. The following contributes to it: - stack_guard_state is not updated correclty in coroutine switch. I think it is not a critical reason. In switch, stack_guard_state should always be stack_guard_enabled. - During reserved stack activation, its stack is too large to exceed to yellow zone to trigger another nested enable_stack_yellow_reserved_zone(). We detect the nested yellow zone and fix the state in this patch. After the patch, the crash is fixed but the test is still fail because of https://bugs.openjdk.org/browse/JDK-8231031. Several improvements as follows: - Make coroutine stack and thread share the same StackOverflow. 10. Fix JRT_LEAF method can not do oops correctly when use Wisp. In java17, InterpreterRuntime::monitorexit and some other monitorexit methods are defined as JRT_LEAF and call them with call_VM_leaf. JRT_LEAF don't allow to call Java methods or break safepoint, so we need to define a new method monitorexit_wisp with JRT_ENTRY_NO_ASYNC and call it with call_VM to make GC do correctly. 11. Fix setThreadWrapper repeatedly when Task is reused by Thread and it's last wrapper is WispThreadWrapper. Test Plan: all wisp cases Reviewed-by: yulei Issue: https://github.com/dragonwell-project/dragonwell17/issues/103 --- make/data/hotspot-symbols/symbols-unix | 1 + .../cpu/aarch64/interp_masm_aarch64.cpp | 12 +- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 5 +- src/hotspot/cpu/arm/interp_masm_arm.cpp | 12 +- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 2 +- .../arm/templateInterpreterGenerator_arm.cpp | 4 +- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 12 +- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 2 +- src/hotspot/cpu/s390/interp_masm_s390.cpp | 12 +- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 2 +- src/hotspot/cpu/x86/interp_masm_x86.cpp | 14 +- src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp | 14 +- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 230 ++++++++++-------- .../x86/templateInterpreterGenerator_x86.cpp | 2 +- src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 7 +- src/hotspot/share/c1/c1_Runtime1.cpp | 7 +- src/hotspot/share/include/jvm.h | 3 + .../share/interpreter/interpreterRuntime.cpp | 28 +++ .../share/interpreter/interpreterRuntime.hpp | 1 + .../interpreter/zero/bytecodeInterpreter.cpp | 30 ++- src/hotspot/share/jvmci/jvmciRuntime.cpp | 9 +- src/hotspot/share/jvmci/jvmciRuntime.hpp | 1 + src/hotspot/share/oops/instanceKlass.cpp | 16 +- src/hotspot/share/opto/macro.cpp | 5 +- src/hotspot/share/opto/runtime.hpp | 2 +- src/hotspot/share/prims/jvm.cpp | 10 + src/hotspot/share/prims/unsafe.cpp | 11 + src/hotspot/share/runtime/coroutine.cpp | 40 ++- src/hotspot/share/runtime/coroutine.hpp | 26 +- src/hotspot/share/runtime/objectMonitor.cpp | 16 +- src/hotspot/share/runtime/sharedRuntime.cpp | 63 +---- src/hotspot/share/runtime/sharedRuntime.hpp | 5 +- src/hotspot/share/runtime/stackOverflow.cpp | 47 +++- src/hotspot/share/runtime/stackOverflow.hpp | 28 ++- src/hotspot/share/runtime/thread.cpp | 25 +- src/hotspot/share/runtime/thread.hpp | 10 +- src/hotspot/share/runtime/thread.inline.hpp | 1 - src/hotspot/share/runtime/vframe.cpp | 6 +- src/hotspot/share/utilities/exceptions.cpp | 6 +- .../com/alibaba/wisp/engine/WispTask.java | 22 +- .../share/classes/java/dyn/Coroutine.java | 20 ++ .../classes/java/dyn/CoroutineSupport.java | 6 + .../share/native/libjava/Coroutine.c | 1 + 43 files changed, 498 insertions(+), 278 deletions(-) diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix index 295cae0c456..90a24009511 100644 --- a/make/data/hotspot-symbols/symbols-unix +++ b/make/data/hotspot-symbols/symbols-unix @@ -194,6 +194,7 @@ JVM_SetNativeThreadName JVM_SetPrimitiveArrayElement JVM_SetThreadPriority JVM_SetWispTask +JVM_UpdateThreadObjectForWispThread JVM_Sleep JVM_StartThread JVM_StopThread diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index bbecb7d3581..fa0db0d3055 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -852,7 +852,11 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) assert(lock_reg == c_rarg1, "The argument is only for looks. It must be rarg1"); if (UseHeavyMonitors) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), lock_reg); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + } } else { Label done; @@ -888,7 +892,11 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) // Call the runtime routine for slow case. str(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); // restore obj - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), lock_reg); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + } bind(done); diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index da1584d7969..5fee0726a95 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1909,7 +1909,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label reguard; Label reguard_done; __ ldrb(rscratch1, Address(rthread, JavaThread::stack_guard_state_offset())); - __ cmpw(rscratch1, StackOverflow::stack_guard_yellow_reserved_disabled); + __ cmpw(rscratch1, static_cast(StackOverflow::stack_guard_yellow_reserved_disabled)); __ br(Assembler::EQ, reguard); __ bind(reguard_done); @@ -2058,6 +2058,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ ldr(r19, Address(rthread, in_bytes(Thread::pending_exception_offset()))); __ str(zr, Address(rthread, in_bytes(Thread::pending_exception_offset()))); + // TODO WispMonitor yield rt_call(masm, CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C)); #ifdef ASSERT @@ -3298,7 +3299,7 @@ void NativeInvokerGenerator::generate() { Label L_reguard; Label L_after_reguard; __ ldrb(rscratch1, Address(rthread, JavaThread::stack_guard_state_offset())); - __ cmpw(rscratch1, StackOverflow::stack_guard_yellow_reserved_disabled); + __ cmpw(rscratch1, static_cast(StackOverflow::stack_guard_yellow_reserved_disabled)); __ br(Assembler::EQ, L_reguard); __ bind(L_after_reguard); diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index 48efb6a8036..513cad1aa31 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -990,7 +990,11 @@ void InterpreterMacroAssembler::unlock_object(Register Rlock) { assert(Rlock == R0, "the first argument"); if (UseHeavyMonitors) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), Rlock); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock); + } } else { Label done, slow_case; @@ -1030,7 +1034,11 @@ void InterpreterMacroAssembler::unlock_object(Register Rlock) { // Call the runtime routine for slow case. str(Robj, Address(Rlock, obj_offset)); // restore obj - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), Rlock); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock); + } bind(done); } diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 30b5ab93ce4..608725536cd 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1235,7 +1235,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ ldr_s32(R2, Address(Rthread, JavaThread::stack_guard_state_offset())); __ str_32(Rtemp, Address(Rthread, JavaThread::thread_state_offset())); - __ cmp(R2, StackOverflow::stack_guard_yellow_reserved_disabled); + __ cmp(R2, static_cast(StackOverflow::stack_guard_yellow_reserved_disabled)); __ b(reguard, eq); __ bind(reguard_done); diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index 2891532d9bb..bc2e0f86993 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -962,9 +962,9 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { { __ ldr_u32(Rtemp, Address(Rthread, JavaThread::stack_guard_state_offset())); __ cmp_32(Rtemp, StackOverflow::stack_guard_yellow_reserved_disabled); - __ call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages), relocInfo::none, eq); + __ call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages), relocInfo::none, eq); #if R9_IS_SCRATCHED - __ restore_method(); + __ restore_method(); #endif } diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 70466fdf3c3..f38c8019130 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -1022,7 +1022,11 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // Throw IllegalMonitorException if object is not locked by current thread. void InterpreterMacroAssembler::unlock_object(Register monitor) { if (UseHeavyMonitors) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), monitor); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); + } } else { // template code: @@ -1094,7 +1098,11 @@ void InterpreterMacroAssembler::unlock_object(Register monitor) { // The lock has been converted into a heavy lock and hence // we need to get into the slow case. bind(slow_case); - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), monitor); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); + } // } Label done; diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 94869ae7ca2..7267373573e 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2362,7 +2362,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, Label no_reguard; __ lwz(r_temp_1, thread_(stack_guard_state)); - __ cmpwi(CCR0, r_temp_1, StackOverflow::stack_guard_yellow_reserved_disabled); + __ cmpwi(CCR0, r_temp_1, static_cast(StackOverflow::stack_guard_yellow_reserved_disabled)); __ bne(CCR0, no_reguard); save_native_result(masm, ret_type, workspace_slot_offset); diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index 51faebad4de..dc96563948f 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1077,7 +1077,11 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) { if (UseHeavyMonitors) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), monitor); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); + } return; } @@ -1151,7 +1155,11 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, Register object) // The lock has been converted into a heavy lock and hence // we need to get into the slow case. z_stg(object, obj_entry); // Restore object entry, has been cleared above. - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), monitor); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); + } // } diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 95facb3a2ef..f145a833a93 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -2056,7 +2056,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, Label no_reguard; __ z_cli(Address(Z_thread, JavaThread::stack_guard_state_offset() + in_ByteSize(sizeof(StackOverflow::StackGuardState) - 1)), - StackOverflow::stack_guard_yellow_reserved_disabled); + static_cast(StackOverflow::stack_guard_yellow_reserved_disabled)); __ z_bre(no_reguard); diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index f08e4741be5..b6a5995c8b8 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1164,7 +1164,7 @@ void InterpreterMacroAssembler::remove_activation( NOT_LP64(get_thread(rthread);) - cmpl(Address(rthread, JavaThread::stack_guard_state_offset()), StackOverflow::stack_guard_enabled); + cmpl(Address(rthread, JavaThread::stack_guard_state_offset()), static_cast(StackOverflow::stack_guard_enabled)); jcc(Assembler::equal, no_reserved_zone_enabling); cmpptr(rbx, Address(rthread, JavaThread::reserved_stack_activation_offset())); @@ -1333,7 +1333,11 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { "The argument is only for looks. It must be c_rarg1"); if (UseHeavyMonitors) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), lock_reg); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + } } else { Label done; @@ -1377,7 +1381,11 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { // Call the runtime routine for slow case. movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), obj_reg); // restore obj - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + if (UseWispMonitor) { + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit_wisp), lock_reg); + } else { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + } bind(done); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 492ec5962d0..9c8e8d0613f 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -2138,13 +2138,17 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // should be a peal // +wordSize because of the push above // args are (oop obj, BasicLock* lock, JavaThread* thread) - __ push(thread); __ lea(rax, Address(rbp, lock_slot_rbp_offset)); - __ push(rax); + if (UseWispMonitor) { + __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::complete_wisp_monitor_unlocking_C), obj_reg, rax); + } else { + __ push(thread); + __ push(rax); + __ push(obj_reg); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C))); + __ addptr(rsp, 3*wordSize); + } - __ push(obj_reg); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C))); - __ addptr(rsp, 3*wordSize); #ifdef ASSERT { Label L; diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index f9a249495dc..84aefbb8095 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2259,7 +2259,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label reguard; Label reguard_done; - __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()), StackOverflow::stack_guard_yellow_reserved_disabled); + __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()), static_cast(StackOverflow::stack_guard_yellow_reserved_disabled)); __ jcc(Assembler::equal, reguard); __ bind(reguard_done); @@ -2440,7 +2440,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ movptr(Address(r15_thread, in_bytes(Thread::pending_exception_offset())), (int32_t)NULL_WORD); // args are (oop obj, BasicLock* lock, JavaThread* thread) - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C))); + if (UseWispMonitor) { + __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::complete_wisp_monitor_unlocking_C), c_rarg0, c_rarg1); + } else { + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C))); + } + __ mov(rsp, r12); // restore sp __ reinit_heapbase(); #ifdef ASSERT @@ -3514,7 +3519,7 @@ void NativeInvokerGenerator::generate() { __ block_comment("reguard stack check"); Label L_reguard; Label L_after_reguard; - __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()), StackOverflow::stack_guard_yellow_reserved_disabled); + __ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()), static_cast(StackOverflow::stack_guard_yellow_reserved_disabled)); __ jcc(Assembler::equal, L_reguard); __ bind(L_after_reguard); @@ -4037,33 +4042,29 @@ void create_switchTo_contents(MacroAssembler *masm, int start, OopMapSet* oop_ma __ push(rbp); Register thread = r15; + + Register old_coroutine = r10; + // copy rsi to r10, rsi is old coroutine oop, shouldn't be changed. + __ movptr(old_coroutine, rsi); + // check that we're dealing with sane objects... + DEBUG_ONLY(stop_if_null(masm, old_coroutine, "null old_coroutine")); + __ movptr(old_coroutine, Address(old_coroutine, java_dyn_CoroutineBase::get_native_coroutine_offset())); + DEBUG_ONLY(stop_if_null(masm, old_coroutine, "old_coroutine without data")); + Register target_coroutine = rdx; // check that we're dealing with sane objects... DEBUG_ONLY(stop_if_null(masm, target_coroutine, "null new_coroutine")); __ movptr(target_coroutine, Address(target_coroutine, java_dyn_CoroutineBase::get_native_coroutine_offset())); DEBUG_ONLY(stop_if_null(masm, target_coroutine, "new_coroutine without data")); -/* -#ifdef ASSERT -#undef __ -#define __ debug_line(masm, __LINE__)-> -#endif -*/ { ////////////////////////////////////////////////////////////////////////// // store information into the old coroutine's object // - // valid registers: rsi = old Coroutine, rdx = target Coroutine + // valid registers: r10 = old Coroutine, rdx = target Coroutine - Register old_coroutine_obj = rsi; - Register old_coroutine = r9; - Register old_stack = r10; Register temp = r8; - - // check that we're dealing with sane objects... - DEBUG_ONLY(stop_if_null(masm, old_coroutine_obj, "null old_coroutine")); - __ movptr(old_coroutine, Address(old_coroutine_obj, java_dyn_CoroutineBase::get_native_coroutine_offset())); - DEBUG_ONLY(stop_if_null(masm, old_coroutine, "old_coroutine without data")); + Register old_stack = r9; #if defined(_WINDOWS) // rescue the SEH pointer @@ -4099,119 +4100,138 @@ void create_switchTo_contents(MacroAssembler *masm, int start, OopMapSet* oop_ma __ movl(temp, Address(thread, JavaThread::java_call_counter_offset())); __ movl(Address(old_coroutine, Coroutine::java_call_counter_offset()), temp); - // store rsp into CorotineStack + // store CorotineStack. + // store rsp into CorotineStack. __ movptr(old_stack, Address(old_coroutine, Coroutine::stack_offset())); __ movptr(Address(old_stack, CoroutineStack::last_sp_offset()), rsp); + __ movl(temp, Address(thread, JavaThread::stack_guard_state_offset())); + __ movl(Address(old_stack, CoroutineStack::stack_guard_state_offset()), temp); + __ movptr(temp, Address(thread, JavaThread::stack_base_offset())); + __ movptr(Address(old_stack, CoroutineStack::stack_base_offset()), temp); + __ movptr(temp, Address(thread, JavaThread::stack_end_offset())); + __ movptr(Address(old_stack, CoroutineStack::stack_end_offset()), temp); + __ movptr(temp, Address(thread, JavaThread::stack_overflow_limit_offset())); + __ movptr(Address(old_stack, CoroutineStack::stack_overflow_limit_offset()), temp); + __ movptr(temp, Address(thread, JavaThread::reserved_stack_activation_offset())); + __ movptr(Address(old_stack, CoroutineStack::reserved_stack_activation_offset()), temp); + __ movl(temp, Address(thread, Thread::stack_size_offset())); + __ movl(Address(old_stack, CoroutineStack::stack_size_offset()), temp); } - Register target_stack = r12; - __ movptr(target_stack, Address(target_coroutine, Coroutine::stack_offset())); { ////////////////////////////////////////////////////////////////////////// // perform the switch to the new stack - // + // restore new coroutine object's information into JavaThread // valid registers: rdx = target Coroutine + Register temp = r8; + Register target_stack = r9; + Register temp2 = r12; __ movl(Address(target_coroutine, Coroutine::state_offset()), Coroutine::_current); - - Register temp = r8; - Register temp2 = r9; - { - Register thread = r15; - __ movptr(Address(thread, JavaThread::current_coroutine_offset()), target_coroutine); - // set new handle and resource areas - __ movptr(temp, Address(target_coroutine, Coroutine::handle_area_offset())); - __ movptr(Address(thread, Thread::handle_area_offset()), temp); - __ movptr(temp, Address(target_coroutine, Coroutine::resource_area_offset())); - __ movptr(Address(thread, Thread::resource_area_offset()), temp); - __ movptr(temp, Address(target_coroutine, Coroutine::last_handle_mark_offset())); - __ movptr(Address(thread, Thread::last_handle_mark_offset()), temp); - __ movptr(temp, Address(target_coroutine, Coroutine::active_handles_offset())); - __ movptr(Address(thread, Thread::active_handles_offset()), temp); - __ movptr(temp, Address(target_coroutine, Coroutine::metadata_handles_offset())); - __ movptr(Address(thread, Thread::metadata_handles_offset()), temp); - __ movptr(temp, Address(target_coroutine, Coroutine::last_Java_pc_offset())); - __ movptr(Address(thread, JavaThread::last_Java_pc_offset()), temp); - __ movptr(temp, Address(target_coroutine, Coroutine::last_Java_sp_offset())); - __ movptr(Address(thread, JavaThread::last_Java_sp_offset()), temp); - __ movl(temp2, Address(target_coroutine, Coroutine::thread_status_offset())); - __ movptr(temp, Address(thread, JavaThread::threadObj_offset())); - // Dereference temp here to get the target JavaThread oop. - __ movptr(temp, Address(temp, 0)); - __ movl(Address(temp, java_lang_Thread::thread_status_offset()), temp2); - __ movl(temp, Address(target_coroutine, Coroutine::java_call_counter_offset())); - __ movl(Address(thread, JavaThread::java_call_counter_offset()), temp); + __ movptr(Address(thread, JavaThread::current_coroutine_offset()), target_coroutine); + + // set new handle and resource areas + __ movptr(temp, Address(target_coroutine, Coroutine::handle_area_offset())); + __ movptr(Address(thread, Thread::handle_area_offset()), temp); + __ movptr(temp, Address(target_coroutine, Coroutine::resource_area_offset())); + __ movptr(Address(thread, Thread::resource_area_offset()), temp); + __ movptr(temp, Address(target_coroutine, Coroutine::last_handle_mark_offset())); + __ movptr(Address(thread, Thread::last_handle_mark_offset()), temp); + __ movptr(temp, Address(target_coroutine, Coroutine::active_handles_offset())); + __ movptr(Address(thread, Thread::active_handles_offset()), temp); + __ movptr(temp, Address(target_coroutine, Coroutine::metadata_handles_offset())); + __ movptr(Address(thread, Thread::metadata_handles_offset()), temp); + __ movptr(temp, Address(target_coroutine, Coroutine::last_Java_pc_offset())); + __ movptr(Address(thread, JavaThread::last_Java_pc_offset()), temp); + __ movptr(temp, Address(target_coroutine, Coroutine::last_Java_sp_offset())); + __ movptr(Address(thread, JavaThread::last_Java_sp_offset()), temp); + __ movptr(temp, Address(thread, JavaThread::threadObj_offset())); + // Dereference temp here to get the target JavaThread oop. + __ movptr(temp2, Address(temp, 0)); + __ movl(temp, Address(target_coroutine, Coroutine::thread_status_offset())); + __ movl(Address(temp2, java_lang_Thread::thread_status_offset()), temp); + __ movl(temp, Address(target_coroutine, Coroutine::java_call_counter_offset())); + __ movl(Address(thread, JavaThread::java_call_counter_offset()), temp); #ifdef ASSERT - __ movptr(Address(target_coroutine, Coroutine::handle_area_offset()), (intptr_t)NULL_WORD); - __ movptr(Address(target_coroutine, Coroutine::resource_area_offset()), (intptr_t)NULL_WORD); - __ movptr(Address(target_coroutine, Coroutine::last_handle_mark_offset()), (intptr_t)NULL_WORD); - __ movl(Address(target_coroutine, Coroutine::java_call_counter_offset()), 0); + __ movptr(Address(target_coroutine, Coroutine::handle_area_offset()), (intptr_t)NULL_WORD); + __ movptr(Address(target_coroutine, Coroutine::resource_area_offset()), (intptr_t)NULL_WORD); + __ movptr(Address(target_coroutine, Coroutine::last_handle_mark_offset()), (intptr_t)NULL_WORD); + __ movl(Address(target_coroutine, Coroutine::java_call_counter_offset()), 0); #endif - // update the thread's stack base and size - __ movptr(temp, Address(target_stack, CoroutineStack::stack_base_offset())); - __ movptr(Address(thread, JavaThread::stack_base_offset()), temp); - __ movl(temp2, Address(target_stack, CoroutineStack::stack_size_offset())); - __ movl(Address(thread, JavaThread::stack_size_offset()), temp2); + // Update the thread's stack base and size + // JavaThread extends from Thread. Both of them have stack information. + // They should be updated correctly together. + __ movptr(target_stack, Address(target_coroutine, Coroutine::stack_offset())); + __ movl(temp, Address(target_stack, CoroutineStack::stack_guard_state_offset())); + __ movl(Address(thread, JavaThread::stack_guard_state_offset()), temp); + __ movptr(temp, Address(target_stack, CoroutineStack::stack_base_offset())); + __ movptr(Address(thread, Thread::stack_base_offset()), temp); + __ movptr(Address(thread, JavaThread::stack_base_offset()), temp); + __ movptr(temp, Address(target_stack, CoroutineStack::stack_end_offset())); + __ movptr(Address(thread, JavaThread::stack_end_offset()), temp); + __ movptr(temp, Address(target_stack, CoroutineStack::stack_overflow_limit_offset())); + __ movptr(Address(thread, JavaThread::stack_overflow_limit_offset()), temp); + __ movptr(temp, Address(target_stack, CoroutineStack::reserved_stack_activation_offset())); + __ movptr(Address(thread, JavaThread::reserved_stack_activation_offset()), temp); +#if !defined(_WINDOWS) + __ movl(temp, Address(target_stack, CoroutineStack::stack_size_offset())); + __ movl(Address(thread, Thread::stack_size_offset()), temp); +#else - // update JavaThread::_reserved_stack_activation for @ReservedStackAccess support - __ movptr(Address(thread, JavaThread::reserved_stack_activation_offset()), temp); - } -#if defined(_WINDOWS) - { - Register tib = rax; - // get the linear address of the TIB (thread info block) - __ prefix(Assembler::GS_segment); - __ movptr(tib, Address(noreg, 0x30)); - - // update the TIB stack base and top - __ movptr(Address(tib, 0x8), temp); - __ subptr(temp, temp2); - __ movptr(Address(tib, 0x10), temp); - - // exchange the TIB structured exception handler pointer - __ movptr(temp, Address(target_coroutine, Coroutine::last_SEH_offset())); - __ movptr(Address(tib, 0), temp); - } + Register tib = rax; + __ movl(temp2, Address(target_stack, CoroutineStack::stack_size_offset())); + __ movl(Address(thread, Thread::stack_size_offset()), temp2); + // get the linear address of the TIB (thread info block) + __ prefix(Assembler::GS_segment); + __ movptr(tib, Address(noreg, 0x30)); + + // update the TIB stack base and top + __ movptr(Address(tib, 0x8), temp); + __ subptr(temp, temp2); + __ movptr(Address(tib, 0x10), temp); + + // exchange the TIB structured exception handler pointer + __ movptr(temp, Address(target_coroutine, Coroutine::last_SEH_offset())); + __ movptr(Address(tib, 0), temp); #endif - // restore the stack pointer - __ movptr(temp, Address(target_stack, CoroutineStack::last_sp_offset())); - __ movptr(rsp, temp); - __ pop(rbp); + // restore the stack pointer + __ movptr(rsp, Address(target_stack, CoroutineStack::last_sp_offset())); + } + __ pop(rbp); - __ int3(); + __ int3(); - if (!terminate) { - ////////////////////////////////////////////////////////////////////////// - // normal case (resume immediately) + if (!terminate) { + ////////////////////////////////////////////////////////////////////////// + // normal case (resume immediately) - // this will reset r12 - __ reinit_heapbase(); + // this will reset r12 + __ reinit_heapbase(); - Label normal; - __ lea(rcx, RuntimeAddress((unsigned char*)coroutine_start)); - __ cmpq(Address(rsp, 0), rcx); - __ jcc(Assembler::notEqual, normal); + Label normal; + __ lea(rcx, RuntimeAddress((unsigned char*)coroutine_start)); + __ cmpq(Address(rsp, 0), rcx); + __ jcc(Assembler::notEqual, normal); - __ movq(c_rarg0, Address(rsp, HeapWordSize * 2)); - __ movq(c_rarg1, Address(rsp, HeapWordSize * 3)); + __ movq(c_rarg0, Address(rsp, HeapWordSize * 2)); + __ movq(c_rarg1, Address(rsp, HeapWordSize * 3)); - __ bind(normal); + __ bind(normal); - __ ret(0); // <-- this will jump to the stored IP of the target coroutine + __ ret(0); // <-- this will jump to the stored IP of the target coroutine - } else { - ////////////////////////////////////////////////////////////////////////// - // slow case (terminate old coroutine) + } else { + ////////////////////////////////////////////////////////////////////////// + // slow case (terminate old coroutine) - // this will reset r12 - __ reinit_heapbase(); + // this will reset r12 + __ reinit_heapbase(); - if (j_rarg0 != rsi) { - __ movptr(j_rarg0, rsi); - } - __ movptr(j_rarg1, 0); + if (j_rarg0 != rsi) { + __ movptr(j_rarg0, rsi); } + __ movptr(j_rarg1, 0); } } \ No newline at end of file diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index 97ff4d58ed1..20c85f81c97 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -1141,7 +1141,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { { Label no_reguard; __ cmpl(Address(thread, JavaThread::stack_guard_state_offset()), - StackOverflow::stack_guard_yellow_reserved_disabled); + static_cast(StackOverflow::stack_guard_yellow_reserved_disabled)); __ jcc(Assembler::notEqual, no_reguard); __ pusha(); // XXX only save smashed registers diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index b73669f6450..16c4cc1dfb1 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -483,7 +483,12 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { markWord old_header = markWord::encode(lock); if (rcvr->cas_set_mark(header, old_header) != old_header) { monitor->set_obj(rcvr); - InterpreterRuntime::monitorexit(monitor); + if (UseWispMonitor) { + HandleMark hm(thread); + CALL_VM_NOCHECK(InterpreterRuntime::monitorexit_wisp(thread, monitor)); + } else { + InterpreterRuntime::monitorexit(monitor); + } } } } diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 77f16cc93e5..6f660a4109a 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -753,12 +753,7 @@ JRT_LEAF(void, Runtime1::monitorexit(JavaThread* current, BasicObjectLock* lock) assert(current->last_Java_sp(), "last_Java_sp must be set"); oop obj = lock->obj(); assert(oopDesc::is_oop(obj), "must be NULL or an object"); - if (UseWispMonitor) { - HandleMarkCleaner __hm(current); - SharedRuntime::monitor_exit_helper(obj, lock->lock(), current); - } else { - SharedRuntime::monitor_exit_helper(obj, lock->lock(), current); - } + SharedRuntime::monitor_exit_helper(obj, lock->lock(), current); JRT_END // Cf. OptoRuntime::deoptimize_caller_frame diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 7390f2c7b7c..28f251ed6ba 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1052,6 +1052,9 @@ JVM_IsSameClassPackage(JNIEnv *env, jclass class1, jclass class2); JNIEXPORT void JNICALL JVM_SetWispTask(JNIEnv* env, jclass clz, jlong coroutinePtr, jint task_id, jobject task, jobject engine); +JNIEXPORT void JNICALL +JVM_UpdateThreadObjectForWispThread(JNIEnv* env, jclass clz, jlong coroutinePtr, jobject threadObject); + JNIEXPORT jint JNICALL JVM_GetProxyUnpark(JNIEnv* env, jclass clz, jintArray res); diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 03aff695190..65b3299f93f 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -773,6 +773,34 @@ JRT_LEAF(void, InterpreterRuntime::monitorexit(BasicObjectLock* elem)) elem->set_obj(NULL); JRT_END +// monitorexit may call Java methods, so it must be a JRT_ENTRY +// (not a JRT_LEAF, JRT_LEAF don't allow to call Java methods or break safepoint) +JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorexit_wisp(JavaThread* current, BasicObjectLock* elem)) +#ifdef ASSERT + current->last_frame().interpreter_frame_verify_monitor(elem); +#endif + Handle h_obj(current, elem->obj()); + assert(Universe::heap()->is_in(h_obj()), "must be an object"); + // The object could become unlocked through a JNI call, + // which we have no other checks for. + // Give a fatal message if CheckJNICalls. Otherwise we ignore it. + if (h_obj()->is_unlocked()) { + if (CheckJNICalls) { + fatal("Object has been unlocked by JNI"); + } + return; + } + // It's safer to use handle to do exit. obj maybe moved by GC. + // Maybe we use obj do something after exit in future code. + ObjectSynchronizer::exit(h_obj, elem->lock(), current); + // Free entry. This must be done here, since a pending exception might be installed on + // exit. If it is not cleared, the exception handling code will try to unlock the monitor again. + elem->set_obj(NULL); +#ifdef ASSERT + current->last_frame().interpreter_frame_verify_monitor(elem); +#endif +JRT_END + JRT_ENTRY(void, InterpreterRuntime::throw_illegal_monitor_state_exception(JavaThread* current)) THROW(vmSymbols::java_lang_IllegalMonitorStateException()); diff --git a/src/hotspot/share/interpreter/interpreterRuntime.hpp b/src/hotspot/share/interpreter/interpreterRuntime.hpp index 5e113b233c8..cb17805cf4d 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.hpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp @@ -112,6 +112,7 @@ class InterpreterRuntime: AllStatic { // Synchronization static void monitorenter(JavaThread* current, BasicObjectLock* elem); static void monitorexit (BasicObjectLock* elem); + static void monitorexit_wisp(JavaThread* current, BasicObjectLock* elem); static void throw_illegal_monitor_state_exception(JavaThread* current); static void new_illegal_monitor_state_exception(JavaThread* current); diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index b93bb30f0c8..383d2bb4479 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -1671,7 +1671,11 @@ void BytecodeInterpreter::run(interpreterState istate) { if (call_vm || lockee->cas_set_mark(header, old_header) != old_header) { // restore object for the slow case most_recent->set_obj(lockee); - InterpreterRuntime::monitorexit(most_recent); + if (UseWispMonitor) { + CALL_VM(InterpreterRuntime::monitorexit_wisp(THREAD, most_recent), handle_exception); + } else { + InterpreterRuntime::monitorexit(most_recent); + } } } UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); @@ -3097,7 +3101,13 @@ void BytecodeInterpreter::run(interpreterState istate) { if (lockee->cas_set_mark(header, old_header) != old_header) { // restore object for the slow case end->set_obj(lockee); - InterpreterRuntime::monitorexit(end); + if (UseWispMonitor) { + // Prevent any HandleMarkCleaner from freeing our live handles + HandleMark __hm(THREAD); + CALL_VM_NOCHECK(InterpreterRuntime::monitorexit_wisp(THREAD, end)); + } else { + InterpreterRuntime::monitorexit(end); + } } } @@ -3147,7 +3157,13 @@ void BytecodeInterpreter::run(interpreterState istate) { THREAD->clear_pending_exception(); } } else if (UseHeavyMonitors) { - InterpreterRuntime::monitorexit(base); + if (UseWispMonitor) { + // Prevent any HandleMarkCleaner from freeing our live handles. + HandleMark __hm(THREAD); + CALL_VM_NOCHECK(InterpreterRuntime::monitorexit_wisp(THREAD, base)); + } else { + InterpreterRuntime::monitorexit(base); + } if (THREAD->has_pending_exception()) { if (!suppress_error) illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); THREAD->clear_pending_exception(); @@ -3165,7 +3181,13 @@ void BytecodeInterpreter::run(interpreterState istate) { if (rcvr->cas_set_mark(header, old_header) != old_header) { // restore object for the slow case base->set_obj(rcvr); - InterpreterRuntime::monitorexit(base); + if (UseWispMonitor) { + // Prevent any HandleMarkCleaner from freeing our live handles + HandleMark __hm(THREAD); + CALL_VM_NOCHECK(InterpreterRuntime::monitorexit_wisp(THREAD, base)); + } else { + InterpreterRuntime::monitorexit(base); + } if (THREAD->has_pending_exception()) { if (!suppress_error) illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); THREAD->clear_pending_exception(); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 4953f324f34..f28c12133f1 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -399,7 +399,14 @@ JRT_END JRT_LEAF(void, JVMCIRuntime::monitorexit(JavaThread* current, oopDesc* obj, BasicLock* lock)) assert(current->last_Java_sp(), "last_Java_sp must be set"); assert(oopDesc::is_oop(obj), "invalid lock object pointer dected"); - SharedRuntime::monitor_exit_helper(obj, lock, current); + SharedRuntime::monitor_exit_helper(obj, lock, current); +JRT_END + +JRT_ENTRY_NO_ASYNC(void, JVMCIRuntime::monitorexit_wisp(JavaThread* current, oopDesc* obj, BasicLock* lock)) + assert(current->last_Java_sp(), "last_Java_sp must be set"); + assert(oopDesc::is_oop(obj), "invalid lock object pointer dected"); + Handle h_obj(current, obj); + SharedRuntime::monitor_exit_helper(h_obj, lock, current); JRT_END // Object.notify() fast path, caller does slow path diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index f5181c49c82..1bc8f043ef3 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -388,6 +388,7 @@ class JVMCIRuntime: public CHeapObj { static address exception_handler_for_pc(JavaThread* current); static void monitorenter(JavaThread* current, oopDesc* obj, BasicLock* lock); static void monitorexit (JavaThread* current, oopDesc* obj, BasicLock* lock); + static void monitorexit_wisp (JavaThread* current, oopDesc* obj, BasicLock* lock); static jboolean object_notify(JavaThread* current, oopDesc* obj); static jboolean object_notifyAll(JavaThread* current, oopDesc* obj); static void vm_error(JavaThread* current, jlong where, jlong format, jlong value); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index f4ecf317c8e..ce5d251482b 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -1091,6 +1091,11 @@ void InstanceKlass::initialize_impl(TRAPS) { // refer to the JVM book page 47 for description of steps // Step 1 { + JavaThread* current = jt; + if (UseWispMonitor) { + current = WispThread::current(current); + } + Handle h_init_lock(THREAD, init_lock()); ObjectLocker ol(h_init_lock, jt); @@ -1098,15 +1103,18 @@ void InstanceKlass::initialize_impl(TRAPS) { // If we were to use wait() instead of waitInterruptibly() then // we might end up throwing IE from link/symbol resolution sites // that aren't expected to throw. This would wreak havoc. See 6320309. - while (is_being_initialized() && !is_reentrant_initialization(jt)) { + while (is_being_initialized() && !is_reentrant_initialization(current)) { wait = true; - jt->set_class_to_be_initialized(this); + assert(current == Thread::current() || + current == WispThread::current(Thread::current()), + "Only the current thread can set this field"); + current->set_class_to_be_initialized(this); ol.wait_uninterruptibly(jt); - jt->set_class_to_be_initialized(NULL); + current->set_class_to_be_initialized(NULL); } // Step 3 - if (is_being_initialized() && is_reentrant_initialization(jt)) { + if (is_being_initialized() && is_reentrant_initialization(current)) { DTRACE_CLASSINIT_PROBE_WAIT(recursive, -1, wait); return; } diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 754e8a189ab..52a0bc15e41 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2432,9 +2432,8 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) { Node *thread = transform_later(new ThreadLocalNode()); CallNode *call; - if (UseWispMonitor && - ((CallNode *)unlock->jvms() != NULL) && ((CallNode *)unlock->jvms()->has_method())) { - call = make_slow_call( (CallNode *) unlock, OptoRuntime::complete_monitor_exit_Type(), OptoRuntime::complete_wisp_monitor_unlocking_Java(), NULL, slow_path, obj, box, thread); + if (UseWispMonitor && ((CallNode *)unlock->jvms() != NULL) && ((CallNode *)unlock->jvms()->has_method())) { + call = make_slow_call( (CallNode *) unlock, OptoRuntime::complete_monitor_exit_Type(), OptoRuntime::complete_wisp_monitor_unlocking_Java(), NULL, slow_path, thread, obj, box); } else { call = make_slow_call( (CallNode *) unlock, OptoRuntime::complete_monitor_exit_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C), "complete_monitor_unlocking_C", slow_path, obj, box, thread); } diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index f1b90708dde..d3ef79009ab 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -174,7 +174,7 @@ class OptoRuntime : public AllStatic { // Slow-path Locking and Unlocking static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); static void complete_monitor_unlocking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); - static void complete_wisp_monitor_unlocking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); + static void complete_wisp_monitor_unlocking_C(JavaThread* thread, oopDesc* obj, BasicLock* lock); static void monitor_notify_C(oopDesc* obj, JavaThread* current); static void monitor_notifyAll_C(oopDesc* obj, JavaThread* current); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index fe5c1f755fb..8a1ac38998d 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3878,6 +3878,16 @@ JVM_ENTRY(void, JVM_SetWispTask(JNIEnv* env, jclass klass, jlong coroutinePtr, j coro->set_wisp_task(JNIHandles::resolve_non_null(task)); JVM_END +JVM_ENTRY(void, JVM_UpdateThreadObjectForWispThread(JNIEnv* env, jclass klass, jlong coroutinePtr, jobject threadObject)) + assert(EnableCoroutine, "Coroutine is disabled"); + if (UseWispMonitor) { + Coroutine* coro = (Coroutine*)coroutinePtr; + WispThread* wt = coro->wisp_thread(); + assert(wt != NULL, "Sanity check"); + wt->set_threadObj(JNIHandles::resolve(threadObject)); + } +JVM_END + JVM_ENTRY(jint, JVM_GetProxyUnpark(JNIEnv* env, jclass klass, jintArray res)) assert(EnableCoroutine, "Coroutine is disabled"); return WispThread::get_proxy_unpark(res); diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 59f158dcdb3..3fa9c8eb724 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -1019,6 +1019,16 @@ JVM_ENTRY (void, CoroutineSupport_checkAndThrowException0(JNIEnv* env, jclass kl } JVM_END +JVM_ENTRY (void, CoroutineSupport_printlnLockFree(JNIEnv* env, jclass klass, jstring info)) + assert(EnableCoroutine, "pre-condition"); + ResourceMark rm(THREAD); + + Handle h_info (THREAD, JNIHandles::resolve_non_null(info)); + char* str = java_lang_String::as_utf8_string(h_info()); + fprintf(stdout, "%s\n", str); + fflush(stdout); +JVM_END + JVM_ENTRY (jobjectArray, CoroutineSupport_getCoroutineStack(JNIEnv* env, jclass klass, jlong coroPtr)) assert(EnableCoroutine, "pre-condition"); @@ -1132,6 +1142,7 @@ JNINativeMethod coroutine_support_methods[] = { {CC"markThreadCoroutine", CC "(J" COBA ")V", FN_PTR(CoroutineSupport_markThreadCoroutine)}, {CC"getCoroutineStack", CC "(J)[" STE, FN_PTR(CoroutineSupport_getCoroutineStack)}, {CC"checkAndThrowException0", CC "(J)V", FN_PTR(CoroutineSupport_checkAndThrowException0)}, + {CC"printlnLockFree", CC "(" LANG "String;)V", FN_PTR(CoroutineSupport_printlnLockFree)}, }; #define COMPILE_CORO_METHODS_BEFORE (3) diff --git a/src/hotspot/share/runtime/coroutine.cpp b/src/hotspot/share/runtime/coroutine.cpp index 5cf5dba629f..f4e1a8a1a88 100644 --- a/src/hotspot/share/runtime/coroutine.cpp +++ b/src/hotspot/share/runtime/coroutine.cpp @@ -407,8 +407,8 @@ CoroutineStack* CoroutineStack::create_thread_stack(JavaThread* thread) { stack->_thread = thread; stack->_is_thread_stack = true; - stack->_stack_base = thread->stack_base(); stack->_stack_size = thread->stack_size(); + StackOverflow::copy(stack->stack_overflow_state(), thread->stack_overflow_state()); stack->_last_sp = NULL; stack->_default_size = false; return stack; @@ -436,26 +436,17 @@ CoroutineStack* CoroutineStack::create_stack(JavaThread* thread, intptr_t size/* stack->_thread = thread; stack->_is_thread_stack = false; - stack->_stack_base = (address)stack->_virtual_space.high(); + address stack_base = (address)stack->_virtual_space.high(); stack->_stack_size = stack->_virtual_space.committed_size(); + address stack_end = stack_base - stack->_stack_size; + stack->_stack_overflow_state.initialize(stack_base, stack_end); stack->_last_sp = NULL; stack->_default_size = default_size; + stack->_stack_overflow_state.create_stack_guard_pages(); - if (os::uses_stack_guard_pages()) { - address low_addr = stack->stack_base() - stack->stack_size(); - size_t len = (StackYellowPages + StackRedPages + StackReservedPages) * os::vm_page_size(); - - bool allocate = os::must_commit_stack_guard_pages(); - - if (!os::guard_memory((char *) low_addr, len)) { - warning("Attempt to protect stack guard pages failed."); - if (os::uncommit_memory((char *) low_addr, len)) { - warning("Attempt to deallocate stack guard pages failed."); - } - } - } - - DEBUG_CORO_ONLY(tty->print("created coroutine stack at %08x with stack size %i (real size: %i)\n", stack->_stack_base, size, stack->_stack_size)); + DEBUG_CORO_ONLY(tty->print( + "created coroutine stack at %08x with stack size %i (real size: %i)\n", + stack->_stack_overflow_state.stack_base(), size, stack->_stack_size)); return stack; } @@ -507,11 +498,15 @@ frame CoroutineStack::last_frame(Coroutine* coro, RegisterMap& map) const { return frame(sp, fp, pc); } -oop Coroutine::print_stack_header_on(outputStream* st) { - oop thread_obj = NULL; +void Coroutine::print_stack_header_on(outputStream* st) { st->print("\n - Coroutine [%p]", this); if (_wisp_task != NULL) { - thread_obj = com_alibaba_wisp_engine_WispTask::get_threadWrapper(_wisp_task); + oop thread_obj = com_alibaba_wisp_engine_WispTask::get_threadWrapper(_wisp_task); +#ifdef ASSERT + if (thread_obj != NULL && UseWispMonitor) { + assert(_wisp_thread->threadObj() == thread_obj, "WispThread thread object is not updated from WispTask"); + } +#endif char buf[128] = ""; if (thread_obj != NULL) { oop name = java_lang_Thread::name(thread_obj); @@ -540,12 +535,11 @@ oop Coroutine::print_stack_header_on(outputStream* st) { } } } // else, we're only using the JKU part - return thread_obj; } void Coroutine::print_stack_on(outputStream* st) { if (_state == Coroutine::_onstack) { - oop thread_obj = print_stack_header_on(st); + print_stack_header_on(st); st->print("\n"); ResourceMark rm; @@ -560,8 +554,6 @@ void Coroutine::print_stack_on(outputStream* st) { java_lang_Throwable::print_stack_element(st, jvf->method(), jvf->bci()); if (UseWispMonitor && JavaMonitorsInStackTrace) { - // t is WispThread - t->set_threadObj(thread_obj); // ensure thread()->current_park_blocker() fetch the correct thread_obj jvf->print_lock_info_on(st, count++); } diff --git a/src/hotspot/share/runtime/coroutine.hpp b/src/hotspot/share/runtime/coroutine.hpp index 4bd7629376e..652ffe0f91e 100644 --- a/src/hotspot/share/runtime/coroutine.hpp +++ b/src/hotspot/share/runtime/coroutine.hpp @@ -211,7 +211,7 @@ class Coroutine: public CHeapObj, public DoublyLinkedList { bool is_disposable(); - oop print_stack_header_on(outputStream* st); + void print_stack_header_on(outputStream* st); void print_stack_on(outputStream* st); bool is_coroutine_frame(vframe* f); @@ -264,10 +264,10 @@ class CoroutineStack: public CHeapObj, public DoublyLinkedList, public DoublyLinkedList, public DoublyLinkedListexception_file(); - pending_line = cur_thread->exception_line(); - CLEAR_PENDING_EXCEPTION; - } -#endif /* MIGHT_HAVE_PENDING */ - - // Use handle to access objects since we will call java code - Handle h_obj(current, obj); - { - EXCEPTION_MARK; - ObjectSynchronizer::exit(h_obj, lock, cur_thread); - } - -#ifdef MIGHT_HAVE_PENDING - if (pending_excep != NULL) { - cur_thread->set_pending_exception(pending_excep, pending_file, pending_line); - } -#endif /* MIGHT_HAVE_PENDING */ -JRT_END - -void SharedRuntime::monitor_exit_helper(oopDesc* obj, BasicLock* lock, JavaThread* current) { +template +void SharedRuntime::monitor_exit_helper(OopRef obj, BasicLock* lock, JavaThread* current) { assert(JavaThread::current() == current, "invariant"); // Exit must be non-blocking, and therefore no exceptions can be thrown. ExceptionMark em(current); - // The object could become unlocked through a JNI call, which we have no other checks for. - // Give a fatal message if CheckJNICalls. Otherwise we ignore it. - if (obj->is_unlocked()) { - if (CheckJNICalls) { - fatal("Object has been unlocked by JNI"); - } - return; - } - if (UseWispMonitor) { - HandleMarkCleaner __hm(current); - Handle h_obj(current, obj); - ObjectSynchronizer::exit(h_obj, lock, current); - } else { - ObjectSynchronizer::exit(obj, lock, current); - } + ObjectSynchronizer::exit(obj, lock, current); } +template void SharedRuntime::monitor_exit_helper(oopDesc* obj, BasicLock* lock, JavaThread* current); +template void SharedRuntime::monitor_exit_helper(Handle obj, BasicLock* lock, JavaThread* current); // Handles the uncommon cases of monitor unlocking in compiled code JRT_LEAF(void, SharedRuntime::complete_monitor_unlocking_C(oopDesc* obj, BasicLock* lock, JavaThread* current)) SharedRuntime::monitor_exit_helper(obj, lock, current); JRT_END +JRT_ENTRY_NO_ASYNC(void, SharedRuntime::complete_wisp_monitor_unlocking_C(JavaThread* current, oopDesc* obj, BasicLock* lock)) + assert(EnableCoroutine, "Coroutine is disabled"); + Handle h_obj(current, obj); + SharedRuntime::monitor_exit_helper(h_obj, lock, current); +JRT_END + #ifndef PRODUCT void SharedRuntime::print_statistics() { diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index a44515df745..c62a0ba9827 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -344,7 +344,8 @@ class SharedRuntime: AllStatic { static void monitor_enter_helper(oopDesc* obj, BasicLock* lock, JavaThread* thread); - static void monitor_exit_helper(oopDesc* obj, BasicLock* lock, JavaThread* current); + template + static void monitor_exit_helper(OopRef obj, BasicLock* lock, JavaThread* current); private: static Handle find_callee_info(Bytecodes::Code& bc, CallInfo& callinfo, TRAPS); @@ -496,7 +497,7 @@ class SharedRuntime: AllStatic { // Slow-path Locking and Unlocking static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* current); static void complete_monitor_unlocking_C(oopDesc* obj, BasicLock* lock, JavaThread* current); - static void complete_wisp_monitor_unlocking_C(oopDesc* obj, BasicLock* lock, JavaThread* current); + static void complete_wisp_monitor_unlocking_C(JavaThread* current, oopDesc* obj, BasicLock* lock); // Resolving of calls static address resolve_static_call_C (JavaThread* current); diff --git a/src/hotspot/share/runtime/stackOverflow.cpp b/src/hotspot/share/runtime/stackOverflow.cpp index 942f3a29e3f..9e57fb58baf 100644 --- a/src/hotspot/share/runtime/stackOverflow.cpp +++ b/src/hotspot/share/runtime/stackOverflow.cpp @@ -99,7 +99,7 @@ void StackOverflow::create_stack_guard_pages() { } if (os::guard_memory((char *) low_addr, len)) { - _stack_guard_state = stack_guard_enabled; + set_stack_guard_state(stack_guard_enabled); } else { log_warning(os, thread)("Attempt to protect stack guard pages failed (" PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); @@ -118,7 +118,7 @@ void StackOverflow::remove_stack_guard_pages() { if (os::must_commit_stack_guard_pages()) { if (os::remove_stack_guard_pages((char *) low_addr, len)) { - _stack_guard_state = stack_guard_unused; + set_stack_guard_state(stack_guard_unused); } else { log_warning(os, thread)("Attempt to deallocate stack guard pages failed (" PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); @@ -127,7 +127,7 @@ void StackOverflow::remove_stack_guard_pages() { } else { if (_stack_guard_state == stack_guard_unused) return; if (os::unguard_memory((char *) low_addr, len)) { - _stack_guard_state = stack_guard_unused; + set_stack_guard_state(stack_guard_unused); } else { log_warning(os, thread)("Attempt to unprotect stack guard pages failed (" PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); @@ -144,6 +144,7 @@ void StackOverflow::enable_stack_reserved_zone(bool check_if_disabled) { if (check_if_disabled && _stack_guard_state == stack_guard_reserved_disabled) { return; } + assert(_stack_guard_state == stack_guard_reserved_disabled, "inconsistent state"); // The base notation is from the stack's point of view, growing downward. @@ -154,7 +155,7 @@ void StackOverflow::enable_stack_reserved_zone(bool check_if_disabled) { guarantee(base < os::current_stack_pointer(),"Error calculating stack reserved zone"); if (os::guard_memory((char *) base, stack_reserved_zone_size())) { - _stack_guard_state = stack_guard_enabled; + set_stack_guard_state(stack_guard_enabled); } else { warning("Attempt to guard stack reserved zone failed."); } @@ -171,7 +172,7 @@ void StackOverflow::disable_stack_reserved_zone() { address base = stack_reserved_zone_base() - stack_reserved_zone_size(); if (os::unguard_memory((char *)base, stack_reserved_zone_size())) { - _stack_guard_state = stack_guard_reserved_disabled; + set_stack_guard_state(stack_guard_reserved_disabled); } else { warning("Attempt to unguard stack reserved zone failed."); } @@ -187,9 +188,20 @@ void StackOverflow::enable_stack_yellow_reserved_zone() { guarantee(base < stack_base(), "Error calculating stack yellow zone"); guarantee(base < os::current_stack_pointer(), "Error calculating stack yellow zone"); + size_t guard_size = 0; + StackGuardState stack_guard_state; + if (reserved_stack_activated()) { + // Here we finish the yellow zone execpetion handle + // within reserved stack activation. + guard_size = stack_yellow_zone_size(); + stack_guard_state = stack_guard_reserved_disabled; + } else { + guard_size = stack_yellow_reserved_zone_size(); + stack_guard_state = stack_guard_enabled; + } - if (os::guard_memory((char *) base, stack_yellow_reserved_zone_size())) { - _stack_guard_state = stack_guard_enabled; + if (os::guard_memory((char *) base, guard_size)) { + set_stack_guard_state(stack_guard_state); } else { warning("Attempt to guard stack yellow zone failed."); } @@ -205,9 +217,17 @@ void StackOverflow::disable_stack_yellow_reserved_zone() { // The base notation is from the stacks point of view, growing downward. // We need to adjust it to work correctly with guard_memory() address base = stack_red_zone_base(); + size_t unguard_size = 0; + StackGuardState stack_guard_state; + if (reserved_stack_activated()) { + assert(_stack_guard_state == stack_guard_reserved_disabled, "sanity check"); + unguard_size = stack_yellow_zone_size(); + } else { + unguard_size = stack_yellow_reserved_zone_size(); + } - if (os::unguard_memory((char *)base, stack_yellow_reserved_zone_size())) { - _stack_guard_state = stack_guard_yellow_reserved_disabled; + if (os::unguard_memory((char *)base, unguard_size)) { + set_stack_guard_state(stack_guard_yellow_reserved_disabled); } else { warning("Attempt to unguard stack yellow zone failed."); } @@ -238,8 +258,9 @@ void StackOverflow::disable_stack_red_zone() { } bool StackOverflow::reguard_stack(address cur_sp) { - if (_stack_guard_state != stack_guard_yellow_reserved_disabled - && _stack_guard_state != stack_guard_reserved_disabled) { + StackGuardState stack_guard_state = _stack_guard_state; + if (stack_guard_state != stack_guard_yellow_reserved_disabled && + stack_guard_state != stack_guard_reserved_disabled) { return true; // Stack already guarded or guard pages not needed. } @@ -250,12 +271,12 @@ bool StackOverflow::reguard_stack(address cur_sp) { // when it should. guarantee(cur_sp > stack_reserved_zone_base(), "not enough space to reguard - increase StackShadowPages"); - if (_stack_guard_state == stack_guard_yellow_reserved_disabled) { + if (stack_guard_state == stack_guard_yellow_reserved_disabled) { enable_stack_yellow_reserved_zone(); if (reserved_stack_activation() != stack_base()) { set_reserved_stack_activation(stack_base()); } - } else if (_stack_guard_state == stack_guard_reserved_disabled) { + } else if (stack_guard_state == stack_guard_reserved_disabled) { set_reserved_stack_activation(stack_base()); enable_stack_reserved_zone(); } diff --git a/src/hotspot/share/runtime/stackOverflow.hpp b/src/hotspot/share/runtime/stackOverflow.hpp index c8e4249ab25..ad33b5ff8df 100644 --- a/src/hotspot/share/runtime/stackOverflow.hpp +++ b/src/hotspot/share/runtime/stackOverflow.hpp @@ -38,9 +38,10 @@ class JavaThread; class StackOverflow { friend class JVMCIVMStructs; friend class JavaThread; + friend class CoroutineStack; public: // State of the stack guard pages for the containing thread. - enum StackGuardState { + enum StackGuardState : int { stack_guard_unused, // not needed stack_guard_reserved_disabled, stack_guard_yellow_reserved_disabled,// disabled (temporarily) after stack overflow @@ -55,8 +56,16 @@ class StackOverflow { // Initialization after thread is started. void initialize(address base, address end) { - _stack_base = base; - _stack_end = end; + // For JavaThread, Thread::record_stack_base_and_size() may be + // invoked twice. One is in JavaThread::run while the other is + // in thread_native_entry. Add a check here to avoid duplicated + // initialization. + if (_stack_base != NULL) { + assert(_stack_base == base, "Sanity check"); + return; + } + _stack_base = base; + _stack_end = end; set_stack_overflow_limit(); set_reserved_stack_activation(base); } @@ -189,6 +198,10 @@ class StackOverflow { return _stack_shadow_zone_size; } + static void copy(StackOverflow* dest, StackOverflow* src) { + memcpy(dest, src, sizeof(StackOverflow)); + } + void create_stack_guard_pages(); void remove_stack_guard_pages(); @@ -219,6 +232,7 @@ class StackOverflow { bool stack_guards_enabled() const; address reserved_stack_activation() const { return _reserved_stack_activation; } + void set_reserved_stack_activation(address addr) { assert(_reserved_stack_activation == stack_base() || _reserved_stack_activation == nullptr @@ -226,6 +240,10 @@ class StackOverflow { _reserved_stack_activation = addr; } + bool reserved_stack_activated() { + return _reserved_stack_activation < stack_base(); + } + // Attempt to reguard the stack after a stack overflow may have occurred. // Returns true if (a) guard pages are not needed on this thread, (b) the // pages are already guarded, or (c) the pages were successfully reguarded. @@ -242,6 +260,10 @@ class StackOverflow { _stack_overflow_limit = stack_end() + MAX2(stack_guard_zone_size(), stack_shadow_zone_size()); } + + void set_stack_guard_state(StackGuardState state) { + _stack_guard_state = state; + } }; #endif // SHARE_RUNTIME_STACKOVERFLOW_HPP diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 9a9aad9b1d5..c7e7f7c7b2d 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -832,7 +832,11 @@ oop JavaThread::threadObj() const { void JavaThread::set_threadObj(oop p) { assert(_thread_oop_storage != NULL, "not yet initialized"); - _threadObj = OopHandle(_thread_oop_storage, p); + if (UseWispMonitor && NULL == p) { + _threadObj = OopHandle(); + } else { + _threadObj = OopHandle(_thread_oop_storage, p); + } } OopStorage* JavaThread::thread_oop_storage() { @@ -1084,6 +1088,7 @@ JavaThread::JavaThread() : _jvmci_reserved_oop0(nullptr), #endif // INCLUDE_JVMCI + _stack_overflow_state(), _exception_oop(oop()), _exception_pc(0), _exception_handler_pc(0), @@ -2784,6 +2789,15 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { create_vm_init_libraries(); } +#ifdef ASSERT + InstanceKlass *k = vmClasses::UnsafeConstants_klass(); + assert(k->is_not_initialized(), "UnsafeConstants should not already be initialized"); +#endif + + // initialize the hardware-specific constants needed by Unsafe + initialize_class(vmSymbols::jdk_internal_misc_UnsafeConstants(), CHECK); + jdk_internal_misc_UnsafeConstants::set_unsafe_constants(); + initialize_class(vmSymbols::java_lang_String(), CHECK); // Inject CompactStrings value after the static initializers for String ran. @@ -2802,15 +2816,6 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { // The VM creates objects of this class. initialize_class(vmSymbols::java_lang_Module(), CHECK); -#ifdef ASSERT - InstanceKlass *k = vmClasses::UnsafeConstants_klass(); - assert(k->is_not_initialized(), "UnsafeConstants should not already be initialized"); -#endif - - // initialize the hardware-specific constants needed by Unsafe - initialize_class(vmSymbols::jdk_internal_misc_UnsafeConstants(), CHECK); - jdk_internal_misc_UnsafeConstants::set_unsafe_constants(); - // The VM preresolves methods to these classes. Make sure that they get initialized initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK); initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 2f9306c4b78..bd8580626d9 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -1338,15 +1338,21 @@ class JavaThread: public Thread { static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); } // StackOverflow offsets - static ByteSize stack_overflow_limit_offset() { + static ByteSize stack_overflow_limit_offset() { return byte_offset_of(JavaThread, _stack_overflow_state._stack_overflow_limit); } - static ByteSize stack_guard_state_offset() { + static ByteSize stack_guard_state_offset() { return byte_offset_of(JavaThread, _stack_overflow_state._stack_guard_state); } static ByteSize reserved_stack_activation_offset() { return byte_offset_of(JavaThread, _stack_overflow_state._reserved_stack_activation); } + static ByteSize stack_base_offset() { + return byte_offset_of(JavaThread, _stack_overflow_state._stack_base); + } + static ByteSize stack_end_offset() { + return byte_offset_of(JavaThread, _stack_overflow_state._stack_end); + } 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); } diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp index ff50e706201..713216711e7 100644 --- a/src/hotspot/share/runtime/thread.inline.hpp +++ b/src/hotspot/share/runtime/thread.inline.hpp @@ -206,7 +206,6 @@ inline void JavaThread::set_terminated(TerminatedTypes t) { inline void JavaThread::set_class_to_be_initialized(InstanceKlass* k) { assert((k == NULL && _class_to_be_initialized != NULL) || (k != NULL && _class_to_be_initialized == NULL), "incorrect usage"); - assert(this == Thread::current(), "Only the current thread can set this field"); _class_to_be_initialized = k; } diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index ab0dcc79453..c8cb3a5c01f 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -218,7 +218,11 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { else if (thread()->osthread()->get_state() == OBJECT_WAIT) { // We are waiting on an Object monitor but Object.wait() isn't the // top-frame, so we should be waiting on a Class initialization monitor. - InstanceKlass* k = thread()->class_to_be_initialized(); + JavaThread* jt = thread(); + if (UseWispMonitor) { + jt = WispThread::current(jt); + } + InstanceKlass* k = jt->class_to_be_initialized(); if (k != NULL) { st->print_cr("\t- waiting on the Class initialization monitor for %s", k->external_name()); } diff --git a/src/hotspot/share/utilities/exceptions.cpp b/src/hotspot/share/utilities/exceptions.cpp index 10272549209..8a366b1fee6 100644 --- a/src/hotspot/share/utilities/exceptions.cpp +++ b/src/hotspot/share/utilities/exceptions.cpp @@ -182,9 +182,6 @@ void Exceptions::_throw(JavaThread* thread, const char* file, int line, Handle h void Exceptions::_throw_msg(JavaThread* thread, const char* file, int line, Symbol* name, const char* message, Handle h_loader, Handle h_protection_domain) { - if (UseWispMonitor && thread->is_Wisp_thread()) { - thread = ((WispThread*) thread)->thread(); - } // Check for special boot-strapping/compiler-thread handling if (special_exception(thread, file, line, name, message)) return; // Create and throw exception @@ -228,6 +225,9 @@ void Exceptions::_throw_msg_cause(JavaThread* thread, const char* file, int line _throw_msg_cause(thread, file, line, name, message, h_cause, Handle(thread, NULL), Handle(thread, NULL)); } void Exceptions::_throw_msg(JavaThread* thread, const char* file, int line, Symbol* name, const char* message) { + if (UseWispMonitor && thread->is_Wisp_thread()) { + thread = ((WispThread*) thread)->thread(); + } _throw_msg(thread, file, line, name, message, Handle(thread, NULL), Handle(thread, NULL)); } void Exceptions::_throw_cause(JavaThread* thread, const char* file, int line, Symbol* name, Handle h_cause) { diff --git a/src/java.base/share/classes/com/alibaba/wisp/engine/WispTask.java b/src/java.base/share/classes/com/alibaba/wisp/engine/WispTask.java index c28c6d1392c..a3cd1267519 100644 --- a/src/java.base/share/classes/com/alibaba/wisp/engine/WispTask.java +++ b/src/java.base/share/classes/com/alibaba/wisp/engine/WispTask.java @@ -180,15 +180,21 @@ void reset(Runnable runnable, WispTask parent, String name, Thread thread, Class // thread status if (thread != null) { // calling from Thread.start() NATIVE_INTERRUPTED_UPDATER.lazySet(this, 1); + if (threadWrapper != null) { + // threadWrapper is not null only when the last wrapper is set by WispThreadWrapper + // so we need to clear it when the task is reused by Thread.start() + assert isThreadAsWisp == false; + setThreadWrapper(null); + } isThreadAsWisp = true; WispEngine.JLA.setWispTask(thread, this); - threadWrapper = thread; + setThreadWrapper(thread); } else { // for WispThreadWrapper, skip native interrupt check NATIVE_INTERRUPTED_UPDATER.lazySet(this, 0); isThreadAsWisp = false; if (threadWrapper == null) { - threadWrapper = new WispThreadWrapper(this); + setThreadWrapper(new WispThreadWrapper(this)); } WispEngine.JLA.setWispAlive(threadWrapper, true); } @@ -201,7 +207,7 @@ void reset(Runnable runnable, WispTask parent, String name, Thread thread, Class void cleanup() { engine = null; - threadWrapper = null; + setThreadWrapper(null); ctxClassLoader = null; } @@ -228,7 +234,7 @@ protected void run() { WispEngine.JLA.setWispAlive(threadWrapper, false); if (isThreadAsWisp) { ThreadAsWisp.exit(threadWrapper); - threadWrapper = null; // else WispThreadWrapper could be reused + setThreadWrapper(null); // else WispThreadWrapper could be reused } if (throwable instanceof CoroutineExitException) { throw (CoroutineExitException) throwable; @@ -501,8 +507,14 @@ public Thread getThreadWrapper() { } void setThreadWrapper(Thread thread) { + assert threadWrapper == null || thread == null; threadWrapper = thread; - WispEngine.JLA.setWispTask(thread, this); + if (threadWrapper != null) { + WispEngine.JLA.setWispTask(threadWrapper, this); + } + if (ctx != null) { + ctx.updateThreadObjectForWispThread(threadWrapper); + } } @Override diff --git a/src/java.base/share/classes/java/dyn/Coroutine.java b/src/java.base/share/classes/java/dyn/Coroutine.java index 559ecc3ddd4..04897e9af6d 100644 --- a/src/java.base/share/classes/java/dyn/Coroutine.java +++ b/src/java.base/share/classes/java/dyn/Coroutine.java @@ -164,6 +164,24 @@ public void setWispTask(int id, Object task, Object engine) { setWispTask(nativeCoroutine, id, task, engine); } + /** + * Update thread object for coroutine WispThread. + * For transparent wisp mode, thread object is created by WispTask. + * It is should be updated to WispThread if UseMonitorWisp is open. + * Otherwise, Coroutine::print_stack_on could not print lock info. + * For each coroutine, it holds three thead objects: one is for underly + * JavaThread, one is for WispTask, one is for WispThread. The underly + * JavaThread threadObject should not be exposed to end user. Its status + * is not critical for user semantic. The WispTask and WispThread + * thread object should be same and reflect coroutine running/park status. + * Their thread object is created by WispTask and updated to WispThread. + * + * @param threadObject thread object oop or null. + */ + public void updateThreadObjectForWispThread(Object threadObject) { + updateThreadObjectForWispThread(nativeCoroutine, threadObject); + } + /** * get StackTrace element for coroutine * @return StackTraceElement @@ -186,4 +204,6 @@ protected void run() { private static native void registerNatives(); private static native void setWispTask(long coroutine, int id, Object task, Object engine); + + private static native void updateThreadObjectForWispThread(long coroutine, Object threadObject); } diff --git a/src/java.base/share/classes/java/dyn/CoroutineSupport.java b/src/java.base/share/classes/java/dyn/CoroutineSupport.java index 7de1e94bbf5..09d794a67fb 100644 --- a/src/java.base/share/classes/java/dyn/CoroutineSupport.java +++ b/src/java.base/share/classes/java/dyn/CoroutineSupport.java @@ -400,6 +400,12 @@ public CoroutineBase getCurrent() { */ private static native void markThreadCoroutine(long coroPtr, CoroutineBase threadCoroutine); + /** + * print info by native method, without synchronize + * @param info info to be printed in Java + */ + public static native void printlnLockFree(String info); + @IntrinsicCandidate private static native void switchTo(CoroutineBase current, CoroutineBase target); diff --git a/src/java.base/share/native/libjava/Coroutine.c b/src/java.base/share/native/libjava/Coroutine.c index c38cb783452..990a5322421 100644 --- a/src/java.base/share/native/libjava/Coroutine.c +++ b/src/java.base/share/native/libjava/Coroutine.c @@ -9,6 +9,7 @@ static JNINativeMethod methods[] = { {"setWispTask","(JI"OBJ OBJ")V", (void *)&JVM_SetWispTask}, + {"updateThreadObjectForWispThread","(J"OBJ")V", (void *)&JVM_UpdateThreadObjectForWispThread}, }; JNIEXPORT void JNICALL