diff --git a/modules/lwjgl/core/src/main/java/org/lwjgl/system/ThreadLocalUtil.java b/modules/lwjgl/core/src/main/java/org/lwjgl/system/ThreadLocalUtil.java index 65d7666d50..fa7dc74429 100644 --- a/modules/lwjgl/core/src/main/java/org/lwjgl/system/ThreadLocalUtil.java +++ b/modules/lwjgl/core/src/main/java/org/lwjgl/system/ThreadLocalUtil.java @@ -90,6 +90,18 @@ be easy to workaround (attaching the agent at startup, making sure no contexts a /** The global JNIEnv. */ private static final long JNI_NATIVE_INTERFACE = memGetAddress(getThreadJNIEnv()); + /** The offset in JNIEnv at which to store the pointer to the capabilities array. */ + private static final int CAPABILITIES_OFFSET = 3 * POINTER_SIZE; + + /** + * Initial value of reserved3 + * + * - OpenJDK: NULL + * - EspressoVM: NULL + * - GraalVM Native Image: pointer to UnimplementedWithJNIEnvArgument function (see #875) + */ + private static final long RESERVED3_NULL = memGetAddress(JNI_NATIVE_INTERFACE + CAPABILITIES_OFFSET); + /** The number of pointers in the JNIEnv struct. */ private static final int JNI_NATIVE_INTERFACE_FUNCTION_COUNT; @@ -103,9 +115,6 @@ be easy to workaround (attaching the agent at startup, making sure no contexts a */ private static long FUNCTION_MISSING_ABORT_TABLE = NULL; - /** The offset in JNIEnv at which to store the pointer to the capabilities array. */ - private static final int CAPABILITIES_OFFSET = 3 * POINTER_SIZE; - static { int JNI_VERSION = GetVersion(); @@ -184,21 +193,27 @@ public static void setCapabilities(long capabilities) { // Ensures FUNCTION_MISSING_ABORT will be called even if no context is current, public static void setFunctionMissingAddresses(int functionCount) { - // OpenJDK: NULL - // GraalVM Native Image: pointer to UnimplementedWithJNIEnvArgument function (see #875) - long RESERVED0_NULL = memGetAddress(JNI_NATIVE_INTERFACE); - long ptr = JNI_NATIVE_INTERFACE + CAPABILITIES_OFFSET; + // aka. reserved3 long currentTable = memGetAddress(ptr); + if (functionCount == 0) { - if (currentTable != RESERVED0_NULL) { + if (currentTable == FUNCTION_MISSING_ABORT) { FUNCTION_MISSING_ABORT_TABLE = NULL; getAllocator().free(currentTable); - memPutAddress(ptr, NULL); + memPutAddress(ptr, RESERVED3_NULL); } } else { - if (currentTable != RESERVED0_NULL) { + // OpenJDK: NULL + // EspressoVM: pointer to VM internal + // GraalVM Native Image: pointer to UnimplementedWithJNIEnvArgument function (see #875) + long RESERVED0_NULL = memGetAddress(JNI_NATIVE_INTERFACE); + + boolean slotAvailable = currentTable == NULL; // on HotSpot or Espresso + slotAvailable |= currentTable == RESERVED0_NULL; // on Native Image + + if (!slotAvailable) { throw new IllegalStateException("setFunctionMissingAddresses has been called already"); } if (currentTable != NULL) { @@ -233,4 +248,4 @@ public static boolean areCapabilitiesDifferent(PointerBuffer ref, PointerBuffer return false; } -} \ No newline at end of file +}