Skip to content

Commit

Permalink
Merge pull request #19433 from babsingh/main1_v0.45.0-release
Browse files Browse the repository at this point in the history
(0.45) ScopedMemoryAccess closeScope0 Updates
  • Loading branch information
pshipton authored May 2, 2024
2 parents 62b8685 + 0de9810 commit 8c94893
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 47 deletions.
6 changes: 6 additions & 0 deletions runtime/gc_structs/VMThreadSlotIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ GC_VMThreadSlotIterator::nextSlot()
case 11:
return &(_vmThread->scopedValueCache);
#endif /* JAVA_SPEC_VERSION >= 19 */
#if JAVA_SPEC_VERSION >= 22
case 12:
return &(_vmThread->scopedError);
case 13:
return &(_vmThread->closeScopeObj);
#endif /* JAVA_SPEC_VERSION >= 22 */
default:
break;
}
Expand Down
92 changes: 49 additions & 43 deletions runtime/jcl/common/jdk_internal_misc_ScopedMemoryAccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,49 +37,28 @@ Java_jdk_internal_misc_ScopedMemoryAccess_registerNatives(JNIEnv *env, jclass cl
{
}

static UDATA
closeScope0FrameWalkFunction(J9VMThread *vmThread, J9StackWalkState *walkState)
{
if (JNI_FALSE == *(jboolean *)walkState->userData2) {
/* scope has been found */
return J9_STACKWALK_STOP_ITERATING;
}
return J9_STACKWALK_KEEP_ITERATING;
}

static void
closeScope0OSlotWalkFunction(J9VMThread *vmThread, J9StackWalkState *walkState, j9object_t *slot, const void *stackLocation)
{
J9Method *method = walkState->method;
if (NULL != method) {
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
if (NULL != romMethod && J9ROMMETHOD_HAS_EXTENDED_MODIFIERS(romMethod)) {
U_32 extraModifiers = getExtendedModifiersDataFromROMMethod(romMethod);
if (J9ROMMETHOD_HAS_SCOPED_ANNOTATION(extraModifiers)) {
if (*slot == J9_JNI_UNWRAP_REFERENCE(walkState->userData1)) {
*(jboolean *)walkState->userData2 = JNI_FALSE;
}
}
}
}
}

/**
* For each thread, walk Java stack and look for the scope instance. Methods that can take and access a scope
* instance are marked with the "@Scoped" extended modifier. If the scope instance is found in a method, that
* method is accessing the memory segment associated with the scope and thus closing the scope will fail.
*/
#if JAVA_SPEC_VERSION >= 22
void JNICALL
Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject instance, jobject scope, jobject error)
#elif (JAVA_SPEC_VERSION >= 19) && (JAVA_SPEC_VERSION <= 21) /* JAVA_SPEC_VERSION >= 22 */
jboolean JNICALL
#if JAVA_SPEC_VERSION >= 19
Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject instance, jobject scope)
#else /* JAVA_SPEC_VERSION >= 19 */
#else /* JAVA_SPEC_VERSION >= 22 */
jboolean JNICALL
Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject instance, jobject scope, jobject exception)
#endif /* JAVA_SPEC_VERSION >= 19 */
#endif /* JAVA_SPEC_VERSION >= 22 */
{
J9VMThread *currentThread = (J9VMThread *)env;
J9JavaVM *vm = currentThread->javaVM;
const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
jboolean scopeNotFound = JNI_TRUE;
#if JAVA_SPEC_VERSION <= 21
jboolean scopeFound = JNI_FALSE;
#endif /* JAVA_SPEC_VERSION <= 21 */

vmFuncs->internalEnterVMFromJNI(currentThread);

Expand All @@ -88,21 +67,31 @@ Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject insta
} else {
vmFuncs->acquireExclusiveVMAccess(currentThread);
J9VMThread *walkThread = J9_LINKED_LIST_START_DO(vm->mainThread);
j9object_t closeScopeObj = J9_JNI_UNWRAP_REFERENCE(scope);
#if JAVA_SPEC_VERSION >= 22
j9object_t errorObj = J9_JNI_UNWRAP_REFERENCE(error);
#endif /* JAVA_SPEC_VERSION >= 22 */
while (NULL != walkThread) {
if (VM_VMHelpers::threadCanRunJavaCode(walkThread)) {
J9StackWalkState walkState;
walkState.walkThread = walkThread;
walkState.flags = J9_STACKWALK_ITERATE_FRAMES | J9_STACKWALK_ITERATE_O_SLOTS;
walkState.skipCount = 0;
walkState.userData1 = (void *)scope;
walkState.userData2 = (void *)&scopeNotFound;
walkState.frameWalkFunction = closeScope0FrameWalkFunction;
walkState.objectSlotWalkFunction = closeScope0OSlotWalkFunction;
#if JAVA_SPEC_VERSION >= 22
/* Skip since an exception is already pending to be thrown.*/
if (NULL != walkThread->scopedError) {
continue;
}
#endif /* JAVA_SPEC_VERSION >= 22 */

vm->walkStackFrames(walkThread, &walkState);
if (JNI_FALSE == *(jboolean *)walkState.userData2) {
/* scope found */
if (vmFuncs->hasMemoryScope(walkThread, closeScopeObj)) {
/* Scope found. */
#if JAVA_SPEC_VERSION >= 22
setHaltFlag(walkThread, J9_PUBLIC_FLAGS_CLOSE_SCOPE);
walkThread->scopedError = errorObj;
walkThread->closeScopeObj = closeScopeObj;
/* Atomic add is not needed since exclusive VM access has been acquired. */
vm->closeScopeNotifyCount += 1;
#else /* JAVA_SPEC_VERSION >= 22 */
scopeFound = JNI_TRUE;
break;
#endif /* JAVA_SPEC_VERSION >= 22 */
}
}

Expand All @@ -112,7 +101,24 @@ Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject insta
}

vmFuncs->internalExitVMToJNI(currentThread);
return scopeNotFound;

#if JAVA_SPEC_VERSION >= 22
/* There are gaps where async exceptions are not processed in time
* (e.g. JIT compiled code in a loop). Wait until J9VMThread->scopedError
* (async exception) is transferred to J9VMThread->currentException. The
* wait prevents a MemorySession to be closed until no more operations are
* being performed on it.
*/
omrthread_monitor_enter(vm->closeScopeMutex);
while (0 != vm->closeScopeNotifyCount) {
omrthread_monitor_wait(vm->closeScopeMutex);
}
omrthread_monitor_exit(vm->closeScopeMutex);
#endif /* JAVA_SPEC_VERSION >= 22 */

#if JAVA_SPEC_VERSION <= 21
return !scopeFound;
#endif /* JAVA_SPEC_VERSION <= 21 */
}
#endif /* JAVA_SPEC_VERSION >= 16 */

Expand Down
2 changes: 1 addition & 1 deletion runtime/oti/j9consts.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ extern "C" {
#define J9_PUBLIC_FLAGS_THREAD_PARKED 0x20000
#define J9_PUBLIC_FLAGS_EXCLUSIVE_SET_NOT_SAFE 0x40000
#define J9_PUBLIC_FLAGS_THREAD_TIMED 0x80000
#define J9_PUBLIC_FLAGS_UNUSED_0x100000 0x100000
#define J9_PUBLIC_FLAGS_CLOSE_SCOPE 0x100000
#define J9_PUBLIC_FLAGS_HALT_THREAD_FOR_CHECKPOINT 0x200000
#define J9_PUBLIC_FLAGS_JNI_CRITICAL_REGION 0x400000
#define J9_PUBLIC_FLAGS_POP_FRAMES_INTERRUPT 0x800000
Expand Down
9 changes: 9 additions & 0 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -5090,6 +5090,7 @@ typedef struct J9InternalVMFunctions {
float (JNICALL *native2InterpJavaUpcallF)(struct J9UpcallMetaData *data, void *argsListPointer);
double (JNICALL *native2InterpJavaUpcallD)(struct J9UpcallMetaData *data, void *argsListPointer);
U_8 * (JNICALL *native2InterpJavaUpcallStruct)(struct J9UpcallMetaData *data, void *argsListPointer);
BOOLEAN (*hasMemoryScope)(struct J9VMThread *walkThread, j9object_t scope);
#endif /* JAVA_SPEC_VERSION >= 16 */
#if JAVA_SPEC_VERSION >= 19
void (*copyFieldsFromContinuation)(struct J9VMThread *currentThread, struct J9VMThread *vmThread, struct J9VMEntryLocalStorage *els, struct J9VMContinuation *continuation);
Expand Down Expand Up @@ -5456,6 +5457,10 @@ typedef struct J9VMThread {
#if JAVA_SPEC_VERSION >= 21
BOOLEAN isInCriticalDownCall;
#endif /* JAVA_SPEC_VERSION >= 21 */
#if JAVA_SPEC_VERSION >= 22
j9object_t scopedError;
j9object_t closeScopeObj;
#endif /* JAVA_SPEC_VERSION >= 22 */
} J9VMThread;

#define J9VMTHREAD_ALIGNMENT 0x100
Expand Down Expand Up @@ -6044,6 +6049,10 @@ typedef struct J9JavaVM {
/* Pool for allocating J9MemberNameListNode. */
struct J9Pool *memberNameListNodePool;
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
#if JAVA_SPEC_VERSION >= 22
omrthread_monitor_t closeScopeMutex;
UDATA closeScopeNotifyCount;
#endif /* JAVA_SPEC_VERSION >= 22 */
} J9JavaVM;

#define J9VM_PHASE_STARTUP 1
Expand Down
10 changes: 7 additions & 3 deletions runtime/oti/jclprots.h
Original file line number Diff line number Diff line change
Expand Up @@ -1285,12 +1285,16 @@ Java_jdk_internal_foreign_abi_UpcallStubs_freeUpcallStub0(JNIEnv *env, jclass cl
void JNICALL
Java_jdk_internal_misc_ScopedMemoryAccess_registerNatives(JNIEnv *env, jclass clazz);

#if JAVA_SPEC_VERSION >= 22
void JNICALL
Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject instance, jobject scope, jobject error);
#elif (JAVA_SPEC_VERSION >= 19) && (JAVA_SPEC_VERSION < 22) /* JAVA_SPEC_VERSION >= 22 */
jboolean JNICALL
#if JAVA_SPEC_VERSION >= 19
Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject instance, jobject scope);
#else /* JAVA_SPEC_VERSION >= 19 */
#else /* JAVA_SPEC_VERSION >= 22 */
jboolean JNICALL
Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject instance, jobject scope, jobject exception);
#endif /* JAVA_SPEC_VERSION >= 19 */
#endif /* JAVA_SPEC_VERSION >= 22 */
#endif /* JAVA_SPEC_VERSION >= 16 */

#if defined(J9VM_OPT_CRIU_SUPPORT)
Expand Down
10 changes: 10 additions & 0 deletions runtime/oti/vm_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -5267,6 +5267,16 @@ native2InterpJavaUpcallD(J9UpcallMetaData *data, void *argsListPointer);
U_8 * JNICALL
native2InterpJavaUpcallStruct(J9UpcallMetaData *data, void *argsListPointer);

/**
* @brief Check if the memory's scope exists on the stack of the thread.
*
* @param[in] walkThread the J9VMThread to be walked
* @param[in] scope the object searched during the walk
*
* @return true if scope is found, false if not
*/
BOOLEAN
hasMemoryScope(J9VMThread *walkThread, j9object_t scope);
#endif /* JAVA_SPEC_VERSION >= 16 */

#ifdef __cplusplus
Expand Down
106 changes: 106 additions & 0 deletions runtime/vm/AsyncMessageHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,74 @@

extern "C" {

#if JAVA_SPEC_VERSION >= 16
/**
* Frame walk function, which is used with hasMemoryScope.
*
* @param[in] vmThread the J9VMThread
* @param[in] walkState the stack walk state
*
* @return J9_STACKWALK_STOP_ITERATING to stop iterating, and
* J9_STACKWALK_KEEP_ITERATING to continue iterating
*/
static UDATA
closeScope0FrameWalkFunction(J9VMThread *vmThread, J9StackWalkState *walkState)
{
if (*(bool *)walkState->userData2) {
/* Scope has been found. */
return J9_STACKWALK_STOP_ITERATING;
}
return J9_STACKWALK_KEEP_ITERATING;
}

/**
* O-slot walk function, which is used with hasMemoryScope.
*
* @param[in] vmThread the J9VMThread
* @param[in] walkState the stack walk state
* @param[in] slot the O-slot pointer
* @param[in] stackLocation the stack location
*/
static void
closeScope0OSlotWalkFunction(J9VMThread *vmThread, J9StackWalkState *walkState, j9object_t *slot, const void *stackLocation)
{
J9Method *method = walkState->method;
if (NULL != method) {
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
if (NULL != romMethod && J9ROMMETHOD_HAS_EXTENDED_MODIFIERS(romMethod)) {
U_32 extraModifiers = getExtendedModifiersDataFromROMMethod(romMethod);
if (J9ROMMETHOD_HAS_SCOPED_ANNOTATION(extraModifiers)) {
if (*slot == walkState->userData1) {
*(bool *)walkState->userData2 = true;
}
}
}
}
}

BOOLEAN
hasMemoryScope(J9VMThread *walkThread, j9object_t scope)
{
bool scopeFound = false;

if (NULL != scope) {
J9StackWalkState walkState;

walkState.walkThread = walkThread;
walkState.flags = J9_STACKWALK_ITERATE_FRAMES | J9_STACKWALK_ITERATE_O_SLOTS;
walkState.skipCount = 0;
walkState.userData1 = (void *)scope;
walkState.userData2 = (void *)&scopeFound;
walkState.frameWalkFunction = closeScope0FrameWalkFunction;
walkState.objectSlotWalkFunction = closeScope0OSlotWalkFunction;

walkThread->javaVM->walkStackFrames(walkThread, &walkState);
}

return scopeFound;
}
#endif /* JAVA_SPEC_VERSION >= 16 */

void
clearAsyncEventFlags(J9VMThread *vmThread, UDATA flags)
{
Expand Down Expand Up @@ -72,6 +140,44 @@ javaCheckAsyncMessages(J9VMThread *currentThread, UDATA throwExceptions)
result = J9_CHECK_ASYNC_POP_FRAMES;
break;
}
#if JAVA_SPEC_VERSION >= 22
/* Check for a close scope request. */
if (J9_ARE_ANY_BITS_SET(publicFlags, J9_PUBLIC_FLAGS_CLOSE_SCOPE)) {
bool notifyThreads = false;
if (hasMemoryScope(currentThread, currentThread->closeScopeObj)) {
if (throwExceptions) {
currentThread->currentException = currentThread->scopedError;
currentThread->scopedError = NULL;
currentThread->closeScopeObj = NULL;
clearEventFlag(currentThread, J9_PUBLIC_FLAGS_CLOSE_SCOPE);
result = J9_CHECK_ASYNC_THROW_EXCEPTION;
notifyThreads = true;
} else {
VM_VMHelpers::indicateAsyncMessagePending(currentThread);
}
} else {
currentThread->scopedError = NULL;
currentThread->closeScopeObj = NULL;
clearEventFlag(currentThread, J9_PUBLIC_FLAGS_CLOSE_SCOPE);
notifyThreads = true;
}
if (notifyThreads) {
J9JavaVM *vm = currentThread->javaVM;
/* Notify all threads that are waiting in ScopedMemoryAccess closeScope0
* to continue since the MemorySession(s) will no longer be used and it
* is safe to close them.
*/
omrthread_monitor_enter(vm->closeScopeMutex);
Assert_VM_true(vm->closeScopeNotifyCount > 0);
vm->closeScopeNotifyCount -= 1;
if (0 == vm->closeScopeNotifyCount) {
omrthread_monitor_notify_all(vm->closeScopeMutex);
}
omrthread_monitor_exit(vm->closeScopeMutex);
}
break;
}
#endif /* JAVA_SPEC_VERSION >= 22 */
/* Check for a thread halt request */
if (J9_ARE_ANY_BITS_SET(publicFlags, J9_PUBLIC_FLAGS_RELEASE_ACCESS_REQUIRED_MASK)) {
Assert_VM_false(J9_ARE_ANY_BITS_SET(publicFlags, J9_PUBLIC_FLAGS_NOT_AT_SAFE_POINT));
Expand Down
1 change: 1 addition & 0 deletions runtime/vm/intfunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ J9InternalVMFunctions J9InternalFunctions = {
native2InterpJavaUpcallF,
native2InterpJavaUpcallD,
native2InterpJavaUpcallStruct,
hasMemoryScope,
#endif /* JAVA_SPEC_VERSION >= 16 */
#if JAVA_SPEC_VERSION >= 19
copyFieldsFromContinuation,
Expand Down
7 changes: 7 additions & 0 deletions runtime/vm/jvminit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,13 @@ freeJavaVM(J9JavaVM * vm)
}
#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */

#if JAVA_SPEC_VERSION >= 22
if (NULL != vm->closeScopeMutex) {
omrthread_monitor_destroy(vm->closeScopeMutex);
vm->closeScopeMutex = NULL;
}
#endif /* JAVA_SPEC_VERSION >= 22 */

j9mem_free_memory(vm);

if (NULL != tmpLib->self_handle) {
Expand Down
4 changes: 4 additions & 0 deletions runtime/vm/vmthinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ UDATA initializeVMThreading(J9JavaVM *vm)
omrthread_monitor_init_with_name(&vm->delayedLockingOperationsMutex, 0, "Delayed locking operations mutex") ||
#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */

#if JAVA_SPEC_VERSION >= 22
omrthread_monitor_init_with_name(&vm->closeScopeMutex, 0, "ScopedMemoryAccess closeScope0 mutex") ||
#endif /* JAVA_SPEC_VERSION >= 22 */

initializeMonitorTable(vm)
)
{
Expand Down

0 comments on commit 8c94893

Please sign in to comment.