Skip to content

Commit

Permalink
Merge pull request #16260 from ChengJin01/fix_ffi_oom_thunk_alloc_wit…
Browse files Browse the repository at this point in the history
…h_heap_list

[Jtreg/FFI]Fix the OOM issue with thunk allocation
  • Loading branch information
gacholio committed Nov 29, 2022
2 parents 9f404be + 5e55aca commit 7a844d3
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 127 deletions.
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)
{
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);
if (NULL != thunkAddr) {
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;
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

0 comments on commit 7a844d3

Please sign in to comment.