You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Context: 16e1ecd
Context: 312fbf4
It occurs to me that it would be easier for "external" developers to
use `Java.Interop.dll` if it didn't require building and distributing
any native libraries. Furthermore, as of commit 312fbf4
(C#9 function pointer backend), it's *plausible* to make that work.
Let's do so.
Add a new `$(Standalone)` "configuration" property to
`src\Java.Interop\Java.Interop.csproj`; when True, the
`FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS` compiler define is set
instead of the `FEATURE_JNIENVIRONMENT_JI_PINVOKES` define.
This enables `JniEnvironment` to use C#9 function pointers instead of
P/Invokes to invoke the `JNIEnv` function pointers.
% dotnet build src/Java.Interop/Java.Interop.csproj -p:Standalone=True
% ikdasm src/Java.Interop/obj/Debug/net7.0/Java.Interop.dll | grep pinvoke
# no matches
# If `-p:Standalone=True` isn't set, then there are 188 matches.
Update `Java.Interop.dll` to compile when
`FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS` is set.
!!ABI BREAK!! `[Obsolete]` the method
`JniRuntime.GetAvailableInvocationPointers()`. In retrospect this
never should have been exposed at this level of the stack, and its
existence was responsible for "really really bizarre" .NET Android
[app crashes][0] (due to static constructor orderings) when
*sometimes* `JniRuntime.Current` wasn't set "early enough":
D Mono : AOT: FOUND method Java.Interop.JniRuntime:GetAvailableInvocationPointers () [0x78e4da7960 - 0x78e4da7a7c 0x78e4de6840]
D Mono : AOT: FOUND method Java.Interop.JniRuntime:GetCreatedJavaVMs (intptr[],int,int&) [0x78e4ddd2b0 - 0x78e4ddd300 0x78e4de6bcd]
D Mono : AOT: NOT FOUND: Java.Interop.NativeMethods:java_interop_jvm_list (intptr[],int,int&).
F monodroid-assembly: Internal p/invoke symbol 'java-interop @ java_interop_jvm_list' (hash: 0x58c48fc8b89cb484) not found in compile-time map.
*Nobody* should be using this method, largely given that only
Xamarin.Android and .NET Android apps currently use
`Java.Interop.dll`, and neither use
`JniRuntime.GetAvailableInvocationPointers()`. Furthermore,
it *can't* work on Android, as Android doesn't provide a public
[`JNI_GetCreatedJavaVMs()`][1] symbol.
Update `build-tools/jnienv-gen` so that a `JniNativeMethods` class
is created which contains "human usable" ways to invoke `JNIEnv`
function pointers. (Nobody wants to copy the expression
`(*((JNIEnv**)env))->ExceptionClear(env)` more than once, ever.
`JniNativeMethods.ExceptionClear(env)` is much nicer to write.)
Update `samples/Hello-Core` so that it sets `Standalone=True`.
Verification: After building `samples/Hello-Core`, the contained
`Java.Interop.dll` doesn't contain any `pinvokeimpl` methods:
% dotnet build samples/Hello-Core
% ikdasm samples/Hello-Core/bin/Debug/Java.Interop.dll | grep pinvoke
# no matches
TODO: I also attempted to reduce the number of P/Invokes in
`Java.Runtime.Environment.dll`, with the hope that when *not* using
MonoVM it could be used without a native `java-interop` library.
This used [`System.Runtime.InteropServices.NativeLibrary`][2] to load
`JniRuntime.CreationOptions.JvmLibraryPath` and invoke the
`JNI_CreateJavaVM()` and `JNI_GetCreatedJavaVMs()` exports.
Unfortunately, this new backend crashes inexplicably when using
`dotnet test`. The backend can now be selected by setting the
`JI_LOADER_TYPE` environment variable to one of:
* `native-library`: the `NativeLibrary` backened, or
* `java-interop`: the previous `java-interop` native lib backend.
This allows testing to work and CI to succeed:
% dotnet test bin/TestDebug-net7.0/Java.Interop-Tests.dll
# all good
while allowing us to separately explore why it crashes:
% JI_LOADER_TYPE=native-library dotnet test bin/TestDebug-net7.0/Java.Interop-Tests.dll
…
# jonp: LoadJvmLibrary(…/libjli.dylib)=9056174496
# jonp: JNI_CreateJavaVM=4561133901; JNI_GetCreatedJavaVMs=4561133970
# jonp: executing JNI_CreateJavaVM=10fdd614d
Error occurred during initialization of VM
Could not reserve enough space in CodeHeap 'non-nmethods' (2496K)
The active test run was aborted. Reason: Test host process crashed
Test Run Aborted with error System.Exception: One or more errors occurred.
---> System.Exception: Unable to read beyond the end of the stream.
at System.IO.BinaryReader.Read7BitEncodedInt()
at System.IO.BinaryReader.ReadString()
at Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.LengthPrefixCommunicationChannel.NotifyDataAvailable()
at Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TcpClientExtensions.MessageLoopAsync(TcpClient client, ICommunicationChannel channel, Action`1 errorHandler, CancellationToken cancellationToken)
--- End of inner exception stack trace ---.
[0]: https://discord.com/channels/732297728826277939/732297837953679412/979054761603125319
[1]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#JNI_GetCreatedJavaVMs
[2]: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativelibrary?view=net-7.0
0 commit comments