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

[Jtreg/FFI]Fix the OOM issue with thunk allocation #16260

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
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,6 @@ public final class InternalUpcallHandler {
private final long thunkAddr;
private UpcallMHMetaData metaData;

/* The generated thunk address are cached & shared in multiple upcalls/threads within the same session/scope */
private static final HashMap<Integer, Long> cachedUpcallThunkAddr = new HashMap<>();

private static final class PrivateUpcallClassLock {
PrivateUpcallClassLock() {}
}
private static final Object privateUpcallClassLock = new PrivateUpcallClassLock();

/*[IF JAVA_SPEC_VERSION >= 19]*/
/**
* The constructor creates an upcall handler specific to the requested java method
Expand Down Expand Up @@ -131,7 +123,7 @@ private long getUpcallThunkAddr(MethodHandle target, ResourceScope sessionOrScop
/*[ENDIF] JAVA_SPEC_VERSION >= 19 */
{
int argLayoutCount = argLayoutArray.length;
/* The last element of the native signature array is for the return type */
/* The last element of the native signature array is for the return type. */
String[] nativeSignatureStrs = new String[argLayoutCount + 1];
for (int argIndex = 0; argIndex < argLayoutCount; argIndex++) {
MemoryLayout argLayout = argLayoutArray[argIndex];
Expand All @@ -148,31 +140,12 @@ private long getUpcallThunkAddr(MethodHandle target, ResourceScope sessionOrScop
nativeSignatureStrs[argLayoutCount] = LayoutStrPreprocessor.getSimplifiedLayoutString(realReturnLayout, false);
}

long addr = 0;
synchronized(privateUpcallClassLock) {
/* The generated thunks are shared across upcalls or threads only when
* the target method handles are identical within the same session/scope
* given a thunk plus the associated metadata is released automatically
* in native via freeUpcallStub() in OpenJDK when the corresponding
* session/scope is terminated.
*/
String targetHashScopeStr = target.hashCode() + "#" + sessionOrScope.toString(); //$NON-NLS-1$
Integer upcallThunkAddrKey = Integer.valueOf(targetHashScopeStr.hashCode());
Long upcallThunkAddr = cachedUpcallThunkAddr.get(upcallThunkAddrKey);
if (upcallThunkAddr != null) {
addr = upcallThunkAddr.longValue();
} else {
/* The thunk must be created for each upcall handler given the UpcallMHMetaData object uniquely bound to the thunk
* is only alive for a MemorySession(JDK19)/ResourceScope(JDK17/18) specified in java, which means the upcall handler
* and its UpcallMHMetaData object will be cleaned up automatically once their session/scope is closed.
*/
metaData = new UpcallMHMetaData(target, sessionOrScope);
addr = allocateUpcallStub(metaData, nativeSignatureStrs);
cachedUpcallThunkAddr.put(upcallThunkAddrKey, Long.valueOf(addr));
}
}

return addr;
/* The thunk must be created for each upcall handler given the UpcallMHMetaData object uniquely bound to the thunk
* is only alive for a MemorySession(JDK19)/ResourceScope(JDK17/18) specified in java, which means the upcall handler
* and its UpcallMHMetaData object will be cleaned up automatically once their session/scope is closed.
*/
metaData = new UpcallMHMetaData(target, sessionOrScope);
return allocateUpcallStub(metaData, nativeSignatureStrs);
}

/* This native requests the JIT to generate an upcall thunk of the specified java method
Expand Down
33 changes: 16 additions & 17 deletions runtime/jcl/common/jdk_internal_foreign_abi_UpcallStubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,36 +48,35 @@ extern "C" {
* to be allocated on the heap for thunk (especially on AIX only with 4KB virtual memory).
*/
jboolean JNICALL
Java_jdk_internal_foreign_abi_UpcallStubs_freeUpcallStub0(JNIEnv *env, jobject receiver, jlong address)
Java_jdk_internal_foreign_abi_UpcallStubs_freeUpcallStub0(JNIEnv *env, jclass clazz, jlong address)
ChengJin01 marked this conversation as resolved.
Show resolved Hide resolved
{
J9VMThread *currentThread = (J9VMThread *)env;
J9JavaVM *vm = currentThread->javaVM;
const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
#if defined(AIXPPC) || (defined(S390) && defined(zOS))
#if defined(AIXPPC) || defined(J9ZOS390)
/* The first element of the function pointer holds the thunk memory address,
* as specified in vm/ap64/UpcallThunkGen.cpp
* as specified in vm/ap64/UpcallThunkGen.cpp and vm/mz64/UpcallThunkGen.cpp.
*/
UDATA *functionPtr = (UDATA *)address;
void *thunkAddr = (void *)functionPtr[0];
#else /* defined(AIXPPC) || (defined(S390) && defined(zOS)) */
void *thunkAddr = (void *)(UDATA)address;
#endif /* defined(AIXPPC) || (defined(S390) && defined(zOS)) */
void **functionPtr = (void **)(intptr_t)address;
void *thunkAddr = *functionPtr;
#else /* defined(AIXPPC) || defined(J9ZOS390) */
void *thunkAddr = (void *)(intptr_t)address;
#endif /* defined(AIXPPC) || defined(J9ZOS390) */

PORT_ACCESS_FROM_JAVAVM(vm);

omrthread_monitor_enter(vm->thunkHeapWrapperMutex);
omrthread_monitor_enter(vm->thunkHeapListMutex);
ChengJin01 marked this conversation as resolved.
Show resolved Hide resolved
if (NULL != thunkAddr) {
ChengJin01 marked this conversation as resolved.
Show resolved Hide resolved
J9UpcallThunkHeapWrapper *thunkHeapWrapper = vm->thunkHeapWrapper;
J9HashTable *metaDataHashTable = thunkHeapWrapper->metaDataHashTable;
J9Heap *thunkHeap = thunkHeapWrapper->heap;
J9HashTable *metaDataHashTable = vm->thunkHeapHead->metaDataHashTable;

if (NULL != metaDataHashTable) {
J9UpcallMetaDataEntry metaDataEntry = {0};
metaDataEntry.thunkAddrValue = (UDATA)(uintptr_t)thunkAddr;
metaDataEntry.thunkAddrValue = (UDATA)thunkAddr;
metaDataEntry.upcallMetaData = NULL;
J9UpcallMetaDataEntry * result = (J9UpcallMetaDataEntry *)hashTableFind(metaDataHashTable, &metaDataEntry);
if (NULL != result) {
J9UpcallMetaData *metaData = result->upcallMetaData;
J9Heap *thunkHeap = metaData->thunkHeapWrapper->heap;
keithc-ca marked this conversation as resolved.
Show resolved Hide resolved
J9UpcallNativeSignature *nativeFuncSig = metaData->nativeFuncSignature;
if (NULL != nativeFuncSig) {
j9mem_free_memory(nativeFuncSig->sigArray);
Expand All @@ -93,18 +92,18 @@ Java_jdk_internal_foreign_abi_UpcallStubs_freeUpcallStub0(JNIEnv *env, jobject r
if (NULL != thunkHeap) {
#if defined(OSX) && defined(AARCH64)
pthread_jit_write_protect_np(0);
#endif
#endif /* defined(OSX) && defined(AARCH64) */
j9heap_free(thunkHeap, thunkAddr);
#if defined(OSX) && defined(AARCH64)
pthread_jit_write_protect_np(1);
#endif
#endif /* defined(OSX) && defined(AARCH64) */
}
}
}
}
omrthread_monitor_exit(vm->thunkHeapWrapperMutex);
omrthread_monitor_exit(vm->thunkHeapListMutex);

return true;
return JNI_TRUE;
}

/**
Expand Down
24 changes: 15 additions & 9 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -5783,8 +5783,8 @@ typedef struct J9JavaVM {
omrthread_monitor_t cifNativeCalloutDataCacheMutex;
struct J9Pool *cifArgumentTypesCache;
omrthread_monitor_t cifArgumentTypesCacheMutex;
struct J9UpcallThunkHeapWrapper *thunkHeapWrapper;
omrthread_monitor_t thunkHeapWrapperMutex;
struct J9UpcallThunkHeapList *thunkHeapHead;
omrthread_monitor_t thunkHeapListMutex;
#endif /* JAVA_SPEC_VERSION >= 16 */
struct J9HashTable* ensureHashedClasses;
#if JAVA_SPEC_VERSION >= 19
Expand Down Expand Up @@ -5933,6 +5933,18 @@ typedef struct J9UpcallNativeSignature {
J9UpcallSigType *sigArray;
} J9UpcallNativeSignature;

typedef struct J9UpcallThunkHeapWrapper {
J9Heap *heap;
uintptr_t heapSize;
J9PortVmemIdentifier vmemID;
} J9UpcallThunkHeapWrapper;

typedef struct J9UpcallThunkHeapList {
J9UpcallThunkHeapWrapper *thunkHeapWrapper;
J9HashTable *metaDataHashTable;
struct J9UpcallThunkHeapList *next;
} J9UpcallThunkHeapList;

typedef struct J9UpcallMetaData {
J9JavaVM *vm;
J9VMThread *downCallThread; /* The thread is mainly used to set exceptions in dispatcher if a native thread is created locally */
Expand All @@ -5942,20 +5954,14 @@ typedef struct J9UpcallMetaData {
UDATA thunkSize; /* The size of the generated thunk */
J9UpcallNativeSignature *nativeFuncSignature; /* The native function signature extracted from FunctionDescriptor */
UDATA functionPtr[3]; /* The address of the generated thunk on AIX or z/OS */
J9UpcallThunkHeapWrapper *thunkHeapWrapper; /* The thunk heap associated with the metaData */
} J9UpcallMetaData;

typedef struct J9UpcallMetaDataEntry {
UDATA thunkAddrValue;
J9UpcallMetaData *upcallMetaData;
} J9UpcallMetaDataEntry;

typedef struct J9UpcallThunkHeapWrapper {
J9Heap *heap;
uintptr_t heapSize;
J9PortVmemIdentifier vmemID;
J9HashTable *metaDataHashTable;
} J9UpcallThunkHeapWrapper;

#endif /* JAVA_SPEC_VERSION >= 16 */

/* Data block for JIT instance field watch reporting */
Expand Down
2 changes: 1 addition & 1 deletion runtime/oti/jclprots.h
Original file line number Diff line number Diff line change
Expand Up @@ -1267,7 +1267,7 @@ void JNICALL
Java_jdk_internal_foreign_abi_UpcallStubs_registerNatives(JNIEnv *env, jclass clazz);

jboolean JNICALL
Java_jdk_internal_foreign_abi_UpcallStubs_freeUpcallStub0(JNIEnv *env, jobject receiver, jlong address);
Java_jdk_internal_foreign_abi_UpcallStubs_freeUpcallStub0(JNIEnv *env, jclass clazz, jlong address);

void JNICALL
Java_jdk_internal_misc_ScopedMemoryAccess_registerNatives(JNIEnv *env, jclass clazz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ OutOfLineINL_openj9_internal_foreign_abi_InternalUpcallHandler_allocateUpcallStu
}

done:
VM_OutOfLineINL_Helpers::returnDouble(currentThread, (I_64)(uintptr_t)thunkAddr, 3);
VM_OutOfLineINL_Helpers::returnDouble(currentThread, (I_64)(intptr_t)thunkAddr, 3);
return rc;

freeAllMemoryThenExit:
Expand Down
Loading