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.45) ScopedMemoryAccess closeScope0 Updates #19433

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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