Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(0.37.0)Relocate state of Continuation from native structure to Object #17111

Merged
merged 1 commit into from
Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public class Continuation {
private Continuation parent;
private boolean started;
private boolean finished;
/* it's a bit-wise struct of CarrierThread ID and continuation flags(includes started and finished flag)
* low 8 bits are reserved for flags and the rest are the carrier thread ID.
* the state should not be directly accessed from Java
*/
private volatile long state;

private static JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();

Expand Down
71 changes: 35 additions & 36 deletions runtime/gc_base/GCExtensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,12 @@ MM_GCExtensions::releaseNativesForContinuationObject(MM_EnvironmentBase* env, j9

if (verify_continuation_list == continuationListOption) {
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, objectPtr);
jboolean finished = J9VMJDKINTERNALVMCONTINUATION_FINISHED(vmThread, objectPtr);

ContinuationState continuationState = *VM_VMHelpers::getContinuationStateAddress(vmThread, objectPtr);
/* there might be potential case that GC would happen between JVM_VirtualThreadUnmountBegin() and JVM_VirtualThreadUnmountEnd() and
* last unmounted continuation Object is marked as "dead", but the related J9VMContinuation has not been freed up.
*/
if (!finished) {
if (!VM_VMHelpers::isFinished(continuationState)) {
Assert_GC_true_with_message2(env, (NULL == continuation), "Continuation expected to be NULL, but it is %p, from Continuation object %p\n", continuation, objectPtr);
}
} else {
Expand All @@ -315,40 +316,38 @@ MM_GCExtensions::needScanStacksForContinuationObject(J9VMThread *vmThread, j9obj
{
bool needScan = false;
#if JAVA_SPEC_VERSION >= 19
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, objectPtr);
if (NULL != continuation) {
/**
* We don't scan mounted continuations:
*
* for concurrent GCs, since stack is actively changing. Instead, we scan them during preMount
* or during root scanning if already mounted at cycle start or during postUnmount (might
* be indirectly via card cleaning) or during final STW (via root re-scan) if still mounted
* at cycle end.
* for sliding compacts to avoid double slot fixups
* If continuation is currently being mounted by this thread, we must be in preMount/postUnmount
* callback and must scan.
*
* For fully STW GCs, there is no harm to scan them, but it's a waste of time since they are
* scanned during root scanning already.
*
* We don't scan currently scanned for the same collector either - one scan is enough for
* the same collector, but there could be concurrent scavenger(local collector) and
* concurrent marking(global collector) overlapping, they are irrelevant and both are
* concurrent, we handle them independently and separately, they are not blocked or ignored
* each other.
*
* we don't scan the continuation object before started and after finished - java stack
* does not exist.
*/
if (isConcurrentGC) {
needScan = VM_VMHelpers::tryWinningConcurrentGCScan(continuation, isGlobalGC, beingMounted);
} else {
/* for STW GCs */
uintptr_t continuationState = continuation->state;
Assert_MM_false(beingMounted);
Assert_MM_false(VM_VMHelpers::isConcurrentlyScanned(continuationState));
needScan = VM_VMHelpers::isActive(continuationState) && !VM_VMHelpers::isContinuationFullyMounted(continuationState);
}
ContinuationState volatile *continuationStatePtr = VM_VMHelpers::getContinuationStateAddress(vmThread, objectPtr);
/**
* We don't scan mounted continuations:
*
* for concurrent GCs, since stack is actively changing. Instead, we scan them during preMount
* or during root scanning if already mounted at cycle start or during postUnmount (might
* be indirectly via card cleaning) or during final STW (via root re-scan) if still mounted
* at cycle end.
* for sliding compacts to avoid double slot fixups
* If continuation is currently being mounted by this thread, we must be in preMount/postUnmount
* callback and must scan.
*
* For fully STW GCs, there is no harm to scan them, but it's a waste of time since they are
* scanned during root scanning already.
*
* We don't scan currently scanned for the same collector either - one scan is enough for
* the same collector, but there could be concurrent scavenger(local collector) and
* concurrent marking(global collector) overlapping, they are irrelevant and both are
* concurrent, we handle them independently and separately, they are not blocked or ignored
* each other.
*
* we don't scan the continuation object before started and after finished - java stack
* does not exist.
*/
if (isConcurrentGC) {
needScan = VM_VMHelpers::tryWinningConcurrentGCScan(continuationStatePtr, isGlobalGC, beingMounted);
} else {
/* for STW GCs */
ContinuationState continuationState = *continuationStatePtr;
Assert_MM_false(beingMounted);
Assert_MM_false(VM_VMHelpers::isConcurrentlyScanned(continuationState));
needScan = VM_VMHelpers::isActive(continuationState) && !VM_VMHelpers::isContinuationFullyMounted(continuationState);
}
#endif /* JAVA_SPEC_VERSION >= 19 */
return needScan;
Expand Down
58 changes: 32 additions & 26 deletions runtime/oti/VMHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2051,16 +2051,22 @@ class VM_VMHelpers
}

#if JAVA_SPEC_VERSION >= 19
static VMINLINE ContinuationState volatile *
getContinuationStateAddress(J9VMThread *vmThread , j9object_t object)
{
return (ContinuationState volatile *) ((uintptr_t) object + J9VMJDKINTERNALVMCONTINUATION_STATE_OFFSET(vmThread));
}

static VMINLINE bool
isStarted(ContinuationState continuationState)
{
return J9_ARE_ALL_BITS_SET(continuationState, J9_GC_CONTINUATION_STATE_STARTED);
}

static VMINLINE void
setContinuationStarted(J9VMContinuation *continuation)
setContinuationStarted(ContinuationState volatile *continuationStatePtr)
{
continuation->state |= J9_GC_CONTINUATION_STATE_STARTED;
*continuationStatePtr |= J9_GC_CONTINUATION_STATE_STARTED;
}

static VMINLINE bool
Expand All @@ -2070,9 +2076,9 @@ class VM_VMHelpers
}

static VMINLINE void
setContinuationFinished(J9VMContinuation *continuation)
setContinuationFinished(ContinuationState volatile *continuationStatePtr)
{
continuation->state |= J9_GC_CONTINUATION_STATE_FINISHED;
*continuationStatePtr |= J9_GC_CONTINUATION_STATE_FINISHED;
}

static VMINLINE bool
Expand Down Expand Up @@ -2112,15 +2118,15 @@ class VM_VMHelpers
}

static VMINLINE void
setConcurrentlyScanned(ContinuationState *continuationState, bool isGlobalGC)
setConcurrentlyScanned(ContinuationState *continuationStatePtr, bool isGlobalGC)
{
*continuationState |= getConcurrentGCMask(isGlobalGC);
*continuationStatePtr |= getConcurrentGCMask(isGlobalGC);
}

static VMINLINE void
resetConcurrentlyScanned(ContinuationState *continuationState, bool isGlobalGC)
resetConcurrentlyScanned(ContinuationState *continuationStatePtr, bool isGlobalGC)
{
*continuationState &= ~getConcurrentGCMask(isGlobalGC);
*continuationStatePtr &= ~getConcurrentGCMask(isGlobalGC);
}

static VMINLINE bool
Expand All @@ -2130,9 +2136,9 @@ class VM_VMHelpers
}

static VMINLINE void
resetPendingState(ContinuationState *continuationState)
resetPendingState(ContinuationState *continuationStatePtr)
{
*continuationState &= ~J9_GC_CONTINUATION_STATE_PENDING_TO_BE_MOUNTED;
*continuationStatePtr &= ~J9_GC_CONTINUATION_STATE_PENDING_TO_BE_MOUNTED;
}

/**
Expand Down Expand Up @@ -2167,16 +2173,16 @@ class VM_VMHelpers
}

static VMINLINE void
settingCarrierAndPendingState(ContinuationState *continuationState, J9VMThread *carrierThread)
settingCarrierAndPendingState(ContinuationState *continuationStatePtr, J9VMThread *carrierThread)
{
/* also set PendingToBeMounted */
*continuationState |= (uintptr_t)carrierThread | J9_GC_CONTINUATION_STATE_PENDING_TO_BE_MOUNTED;
*continuationStatePtr |= (uintptr_t)carrierThread | J9_GC_CONTINUATION_STATE_PENDING_TO_BE_MOUNTED;
}

static VMINLINE void
resetContinuationCarrierID(J9VMContinuation *continuation)
resetContinuationCarrierID(ContinuationState volatile *continuationStatePtr)
{
continuation->state &= ~J9_GC_CONTINUATION_STATE_CARRIERID_MASK;
*continuationStatePtr &= ~J9_GC_CONTINUATION_STATE_CARRIERID_MASK;
}

/*
Expand All @@ -2192,10 +2198,10 @@ class VM_VMHelpers
* another GC thread winning to scan(bit3/bit4,bit3 and bit4 is irrelevant and independent), again don't do anything, and let the winning thread do the work, instead
*/
static VMINLINE bool
tryWinningConcurrentGCScan(J9VMContinuation *continuation, bool isGlobalGC, bool beingMounted)
tryWinningConcurrentGCScan(ContinuationState volatile *continuationStatePtr, bool isGlobalGC, bool beingMounted)
{
do {
uintptr_t oldContinuationState = continuation->state;
ContinuationState oldContinuationState = *continuationStatePtr;
if (VM_VMHelpers::isActive(oldContinuationState)) {

/* If it's being concurrently scanned within the same type of GC by another thread , it's unnecessary to do it again */
Expand All @@ -2206,9 +2212,9 @@ class VM_VMHelpers
*/
if (beingMounted || !isContinuationFullyMounted(oldContinuationState)) {
/* Try to set scan bit for this GC type */
uintptr_t newContinuationState = oldContinuationState;
ContinuationState newContinuationState = oldContinuationState;
setConcurrentlyScanned(&newContinuationState, isGlobalGC);
uintptr_t returnedState = VM_AtomicSupport::lockCompareExchange(&continuation->state, oldContinuationState, newContinuationState);
ContinuationState returnedState = VM_AtomicSupport::lockCompareExchange(continuationStatePtr, oldContinuationState, newContinuationState);
/* If no other thread changed anything (mounted or won scanning for any GC), we succeeded, otherwise retry */
if (oldContinuationState == returnedState) {
return true;
Expand All @@ -2229,16 +2235,16 @@ class VM_VMHelpers
* @param [in] checkConcurrentState can be J9_GC_CONTINUATION_STATE_CONCURRENT_SCAN_LOCAL or J9_GC_CONTINUATION_STATE_CONCURRENT_SCAN_GLOBAL
*/
static VMINLINE void
exitConcurrentGCScan(J9VMContinuation *continuation, bool isGlobalGC)
exitConcurrentGCScan(ContinuationState volatile *continuationStatePtr, bool isGlobalGC)
{
/* clear CONCURRENTSCANNING flag bit3:LocalConcurrentScanning /bit4:GlobalConcurrentScanning */
uintptr_t oldContinuationState = 0;
uintptr_t returnContinuationState = 0;
ContinuationState oldContinuationState = 0;
ContinuationState returnContinuationState = 0;
do {
oldContinuationState = continuation->state;
uintptr_t newContinuationState = oldContinuationState;
oldContinuationState = *continuationStatePtr;
ContinuationState newContinuationState = oldContinuationState;
resetConcurrentlyScanned(&newContinuationState, isGlobalGC);
returnContinuationState = VM_AtomicSupport::lockCompareExchange(&continuation->state, oldContinuationState, newContinuationState);
returnContinuationState = VM_AtomicSupport::lockCompareExchange(continuationStatePtr, oldContinuationState, newContinuationState);
} while (returnContinuationState != oldContinuationState);

if (!isConcurrentlyScanned(returnContinuationState, !isGlobalGC)) {
Expand All @@ -2257,8 +2263,8 @@ class VM_VMHelpers
exitConcurrentGCScan(J9VMThread *vmThread, j9object_t continuationObject, bool isGlobalGC)
{
#if JAVA_SPEC_VERSION >= 19
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(vmThread, continuationObject);
exitConcurrentGCScan(continuation, isGlobalGC);
ContinuationState volatile *continuationStatePtr = getContinuationStateAddress(vmThread, continuationObject);
exitConcurrentGCScan(continuationStatePtr, isGlobalGC);
#endif /* JAVA_SPEC_VERSION >= 19 */
}

Expand Down
9 changes: 4 additions & 5 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -5021,9 +5021,12 @@ typedef struct J9JITGPRSpillArea {
#endif /* J9VM_ARCH_X86 */
} J9JITGPRSpillArea;

#if JAVA_SPEC_VERSION >= 19
/* it's a bit-wise struct of CarrierThread ID and continuation flags
* low 8 bits are reserved for flags and the rest are the carrier thread ID.
*/
typedef uintptr_t ContinuationState;

#if JAVA_SPEC_VERSION >= 19
typedef struct J9VMContinuation {
UDATA* arg0EA;
UDATA* bytecodes;
Expand All @@ -5038,10 +5041,6 @@ typedef struct J9VMContinuation {
struct J9JITGPRSpillArea jitGPRs;
struct J9I2JState i2jState;
struct J9VMEntryLocalStorage* oldEntryLocalStorage;
/* it's a bit-wise struct of CarrierThread ID and continuation flags
* low 8 bits are reserved for flags and the rest are the carrier thread ID.
*/
volatile ContinuationState state;
UDATA dropFlags;
} J9VMContinuation;
#endif /* JAVA_SPEC_VERSION >= 19 */
Expand Down
1 change: 1 addition & 0 deletions runtime/oti/vmconstantpool.xml
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-excepti
<fieldref class="jdk/internal/vm/Continuation" name="vmRef" signature="J" cast="struct J9VMContinuation *" versions="19-"/>
<fieldref class="jdk/internal/vm/Continuation" name="finished" signature="Z" versions="19-"/>
<fieldref class="jdk/internal/vm/Continuation" name="started" signature="Z" versions="19-"/>
<fieldref class="jdk/internal/vm/Continuation" name="state" signature="J" versions="19-"/>
<fieldref class="jdk/internal/vm/Continuation" name="parent" signature="Ljdk/internal/vm/Continuation;" versions="19-"/>
<fieldref class="jdk/internal/vm/Continuation" name="vthread" signature="Ljava/lang/Thread;" versions="19-"/>

Expand Down