ikvmnet / ikvm

A Java Virtual Machine and Bytecode-to-IL Converter for .NET
Other
1.22k stars 111 forks source link

Implement JVMTI #335

Open TheLastRar opened 1 year ago

TheLastRar commented 1 year ago

IKVM version : IKVM-8.5.0-image-netcoreapp3.1-win7-x64

Only the client was tested.

Version of LWJGL used by default is dependent on the JVMTI interface pointer. LWJGL is open source library for using gl in java, It however uses native code to retrieve the JVMTI interface pointer.

[16:31:54] [Client thread/INFO]: LWJGL Version: 3.1.6 build 14
[LWJGL] Failed to retrieve the JVMTI interface pointer.
[16:31:55] [Client thread/INFO]: [STDERR]: java.lang.InternalError: cli.System.NullReferenceException
[16:31:55] [Client thread/INFO]: [STDERR]:  at IKVM.Java.Externs.sun.misc.Unsafe.GetField(Unsafe.cs:151)
[16:31:55] [Client thread/INFO]: [STDERR]:  at IKVM.Java.Externs.sun.misc.Unsafe.getLong(Unsafe.cs:464)
[16:31:55] [Client thread/INFO]: [STDERR]:  at sun.misc.Unsafe.getLong(Native Method)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.lwjgl.system.MemoryAccess$MemoryAccessorUnsafe.getAddressOffset(MemoryAccess.java:149)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.lwjgl.system.MemoryAccess$MemoryAccessorUnsafe.<clinit>(MemoryAccess.java:132)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.lwjgl.system.MemoryAccess$MemoryAccessorUnsafe.<init>(MemoryAccess.java:171)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.lwjgl.system.MemoryAccess.getInstance(MemoryAccess.java:32)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.lwjgl.system.MemoryUtil.<clinit>(MemoryUtil.java:63)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.lwjgl.system.MemoryUtil.memAddress(MemoryUtil.java:634)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.lwjgl.system.MemoryStack.<init>(MemoryStack.java:61)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.lwjgl.system.MemoryStack.create(MemoryStack.java:82)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.lwjgl.system.MemoryStack.create(MemoryStack.java:71)
[16:31:55] [Client thread/INFO]: [STDERR]:  at java.lang.ThreadLocal$SuppliedThreadLocal.initialValue(ThreadLocal.java:284)
[16:31:55] [Client thread/INFO]: [STDERR]:  at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:180)
[16:31:55] [Client thread/INFO]: [STDERR]:  at java.lang.ThreadLocal.get(ThreadLocal.java:170)
[16:31:55] [Client thread/INFO]: [STDERR]:  at cgd.a(SourceFile:127)
[16:31:55] [Client thread/INFO]: [STDERR]:  at cft.an(SourceFile:561)
[16:31:55] [Client thread/INFO]: [STDERR]:  at cft.am(SourceFile:438)
[16:31:55] [Client thread/INFO]: [STDERR]:  at cft.a(SourceFile:380)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.prismlauncher.launcher.impl.StandardLauncher.launch(StandardLauncher.java:89)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.prismlauncher.EntryPoint.listen(EntryPoint.java:128)
[16:31:55] [Client thread/INFO]: [STDERR]:  at org.prismlauncher.EntryPoint.main(EntryPoint.java:71)
[16:31:55] [Client thread/INFO]: [STDERR]:  at java.lang.reflect.Method.invoke(Method.java:486)
[16:31:55] [Client thread/INFO]: [STDERR]:  at IKVM.Java.Externs.ikvm.runtime.Launcher.run(Launcher.cs:43)
[16:31:55] [Client thread/INFO]: [STDERR]: Caused by: cli.System.NullReferenceException
[16:31:55] [Client thread/INFO]: [STDERR]: [LWJGL] [MemoryAccessor] Unsupported JVM detected, this will likely result in low performance. Please inform LWJGL developers.
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at org.lwjgl.system.ThreadLocalUtil.jvmtiGetJNIFunctionTable()
   at org.lwjgl.system.ThreadLocalUtil.setEnv(Int64, Int32)
   at org.lwjgl.opengl.GL.setCapabilities(org.lwjgl.opengl.GLCapabilities)
   at org.lwjgl.opengl.GL.createCapabilities(Boolean)
   at org.lwjgl.opengl.GL.createCapabilities()
   at cgd..ctor(cft, cgc, cnq$a, System.String)
   at cgc.a(cnq$a, System.String)
   at cft.am()
   at cft.a()
   at org.prismlauncher.launcher.impl.StandardLauncher.launch()
   at org.prismlauncher.EntryPoint.listen()
   at org.prismlauncher.EntryPoint.main(System.String[])
   at DynamicClass.__<FastMethodAccessor>__org_prismlauncher_EntryPoint__main(System.Object, System.Object[], ikvm.internal.CallerID)
   at IKVM.Java.Externs.sun.reflect.ReflectionFactory+FastMethodAccessorImpl.invoke(System.Object, System.Object[], ikvm.internal.CallerID)
   at java.lang.reflect.Method.invoke(System.Object, System.Object[], ikvm.internal.CallerID)
   at java.lang.reflect.Method.invoke(System.Object, System.Object[])
   at IKVM.Runtime.Launcher.Run(System.String, Boolean, System.String[], System.String, System.Collections.Generic.IDictionary`2<System.String,System.String>)
   at IKVM.Java.Externs.ikvm.runtime.Launcher.run(System.Type, System.String[], System.String, java.util.Properties)
   at ikvm.runtime.Launcher.run(System.Type, System.String[], System.String, java.util.Properties)
   at IKVM.Tools.Java.Program.Main(System.String[])
wasabii commented 1 year ago

I do think I fixed this though.

TheLastRar commented 1 year ago

Still broken unfortunately

This version of LWJGL uses JNI to the JVMTI pointer https://github.com/LWJGL/lwjgl3/blob/3.1.6/modules/lwjgl/core/src/main/c/common_tools.c#L187-L199

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    UNUSED_PARAM(reserved)

    jvm = vm;

    if ((*jvm)->GetEnv(jvm, (void **)&jvmti, JVMTI_VERSION_1_2) != JNI_OK) {
        fprintf(stderr, "[LWJGL] Failed to retrieve the JVMTI interface pointer.");
        fflush(stderr);
    }

    envTLSInit();
    return JNI_VERSION_1_8;
}

Which on IKVM logs the error message about the JVMTI interface pointer.

The first stack trace is similar to https://github.com/ikvmnet/ikvm/issues/336, except unlike 3.2.2, 3.1.6 has a fallback and can continue.

The second stack trace is LWJGL trying to dereference the jvmti pointer it failed to get in JNI_OnLoad, and crashing with a System.AccessViolationException as a result.

wasabii commented 1 year ago

Man, when I first read this bug, I assumed it was just the JNI interface pointer. Now that I'm looking closer... JVMTI. I had focused on the stack trace that followed about the null field.

This is an area I believe is completely unimplemented. We don't have JVMTI stuff implemented. I'll take a quick look and see what the total level of difficulty is. But I suspect it's not going to be something I take up soon.

If maybe you could figure out what LWJGL needs from JVMTI, we could focus on those aspects?

Also because it's related #158

wasabii commented 1 year ago

Yeah. This is going to go far beyond what I can do currently. This is deeper stuff that is probably going to require a bridge to the Core profiler API and debugger APIs.

TheLastRar commented 1 year ago

The functions used by 3.1.6 are GetJNIFunctionTable() and Deallocate(), 3.2.x and newer don't need any JVMTI apis

wasabii commented 10 months ago

@TheLastRar Does that mean >= 3.2.x works?

wasabii commented 10 months ago

Since we don't support JVMTI, I'm going to leave this one open, but retitle it about JVMTI specifically. Might never get completed. But it is technically a missing feature.

TheLastRar commented 10 months ago

@TheLastRar Does that mean >= 3.2.x works?

3.2.2 is busted due to https://github.com/ikvmnet/ikvm/issues/336 3.3.x seems to work fine last I checked

wasabii commented 10 months ago

Neat.