-
Notifications
You must be signed in to change notification settings - Fork 54
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
[Java.Runtime.Environment] Partial support for .NET Core #804
Conversation
@radekdoulik , @jpobst : thoughts on the new API additions? Are current Or should we treat it "as if" they were disposed or finalized? |
Related discussion & elaboration: #426 (comment) |
98e0288
to
3bd2bb1
Compare
@jpobst: if you know how to filter a YAML (…which shouldn't be that hard. We'll just want to write a |
Design thoughts… Instead of a
Additionally, A scenario behind #426 was e.g. to do a "C# plugin for a machine learning pipeline": have Tensorflow+Java installed on a server, write a plugin for it within C#, and then process lots of images in a pipeline with the C# plugin. In such an environment, the normal GC bridge isn't necessarily required: between each image you can "release everything" and do some GC's so that you don't leak. My suspicion, though, is that you wouldn't want to release everything. You'd just want to release "everything created since some well-defined point". This would allow one to initialize things once, get a good "starting state", and then process the pipeline, without needn't to re-initialize between each item.
I think we need a better abstraction than what is proposed here. Probably something "stack-like". |
Context: #804 Two changes within commit 89a5a22 allow `dotnet test` to be used to run the net472 mono-required NUnit tests: 1. The `java-interop` native library is reliably copied to the `$(OutputPath)` of referencing projects. This ensures that e.g. `bin/TestDebug/libjava-interop.dylib` exists without extra `make` commands or an `msbuild /t:RunTests` invocation. 2. More importantly, `tests/TestJVM` was updated to use `Xamarin.Android.Tools.AndroidSdk.dll` along with `JdkInfo.GetKnownSystemJdkInfos()`. (2) means that the `JI_JVM_PATH` environment variable doesn't *need* to be set before running unit tests, and is largely responsible for allowing `dotnet test` to work: % make prepare all % dotnet test bin/TestDebug/Java.Interop-Tests.dll … Passed! - Failed: 0, Passed: 631, Skipped: 1, Total: 632, Duration: 686 ms Note that these tests are *not* executed under .NET Core/CoreCLR! It's simply using `dotnet test` as an equivalent to/replacement for `mono nunit3-console.exe`. Java.Interop-Tests to be run under .NET Core are built into e.g. `bin/TestDebug-netcoreapp3.1/Java.Interop-Tests.dll`, and trying to run *that* test suite crashes and burns: % dotnet test bin/TestDebug-netcoreapp3.1/Java.Interop-Tests.dll … Failed! - Failed: 16, Passed: 325, Skipped: 1, Total: 342, Duration: 311 ms See e.g. PR #804 for an attempt to make .NET Core support work.
3bd2bb1
to
f77edab
Compare
f77edab
to
4d281fb
Compare
In the interest of expediency, I've removed API additions which attempt to fix Issue #426. What remains is "potentially weird" -- the There is thus no API breakage, and no new semantics to review here. Issue #426 will contain the primary discussion of how to "properly" support a non-bridging GC environment. |
4d281fb
to
3d6166b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks fine to me, though not really my area of expertise. Hopefully Radek can review better than me!
@@ -47,6 +48,8 @@ public static unsafe JniObjectReference FindClass (string classname) | |||
return r; | |||
} | |||
|
|||
// NativeMethods.java_interop_jnienv_exception_describe (info.EnvironmentPointer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dead code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but not entirely; from the commit message:
The attempt to retain useful Java-side exceptions in 89a5a22
proved to be incomplete. Add a comment to invoke
JNIEnv::ExceptionDescribe(). We don't always want this
to be present, but when we do want it…
@@ -370,7 +370,12 @@ static Expression GetRuntime () | |||
return Expression.Property (null, typeof (JniEnvironment), "Runtime"); | |||
} | |||
|
|||
static MethodInfo FormatterServices_GetUninitializedObject = Type.GetType ("System.Runtime.Serialization.FormatterServices", throwOnError: true) | |||
static MethodInfo FormatterServices_GetUninitializedObject = | |||
#if NETFRAMEWORK || NET_2_0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#if NETCOREAPP
might be simpler here (plus switch the branches). Nothing important though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we start targeting .NET 5/6, won't we also need NET
? Meaning we'd likewise want #if NETCOREAPP || NET
? Which doesn't actually seem simpler…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
net5, net6, ... also define NETCOREAPP
3d6166b
to
203b18a
Compare
builder.ValueManager = builder.ValueManager ?? new ManagedValueManager (); | ||
builder.ObjectReferenceManager = builder.ObjectReferenceManager ?? new ManagedObjectReferenceManager (builder.JniGlobalReferenceLogWriter, builder.JniLocalReferenceLogWriter); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. We don't have to create the managers before creating the VM. I like that change.
var peers = new List<IJavaPeerable> (); | ||
|
||
lock (RegisteredInstances) { | ||
foreach (var ps in RegisteredInstances.Values) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here it might be more efficient to do:
List<IDisposable> values;
lock (RegisteredInstances) {
values = new List<IDisposable> (RegisteredInstances.Values);
RegisteredInstances.Clear ();
}
and do the rest of cleaning after that? It will also lower time spent in lock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RegisteredInstances.Values
is of type ICollection<List<IJavaPeerable>>
, not ICollection<IJavaPeerable>
. Thus, new List<IDisposable> (RegisteredInstances.Values)
won't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was updating the code from elswhere, so it would need to be new List<List<IJavaPeerable>> (RegisteredInstances.Values)
, the idea is the same though. To leave the lock
block quickly.
203b18a
to
33da2df
Compare
Enable C#8 [Nullable Reference Types][0] for `Java.Runtime.Environment.dll`. Add partial support for a "non-bridged backend", so that a `JniRuntime.JniValueManager` exists for .NET Core. This new "managed" backed is used if the Mono runtime is *not* used. To work, `ManagedValueManager` holds *strong* references to `IJavaPeerable` instances. As such, tests which required the use of GC integration are now "optional", conditional on the `!NO_GC_BRIDGE_SUPPORT` define. The `ManagedValueManager.CollectPeers()` method calls `IJavaPeerable.Dispose()` on all currently referenced peers, then stops referencing the managed peers. This causes all GREFs to be dropped, allowing Java peers to be collected, and then allows the .NET GC to collect the `IJavaPeerable` values. Any and all exceptions thrown by `IJavaPeerable.Dispose()` are caught and re-thrown by an `AggregateException`. Update `Java.Interop-Tests.csproj` to define `NO_GC_BRIDGE_SUPPORT` and `NO_MARSHAL_MEMBER_BUILDER_SUPPORT` when building for .NET Core. This excludes all currently "troublesome"/non-passing tests. These changes allow all remaining `Java.Interop-Tests` unit tests to execute under .NET Core: % dotnet test -v diag '--logger:trx;verbosity=detailed' bin/TestDebug-netcoreapp3.1/Java.Interop-Tests.dll Passed! - Failed: 0, Passed: 617, Skipped: 1, Total: 618, Duration: 1 s Other changes: * The attempt to retain useful Java-side exceptions in 89a5a22 proved to be incomplete. Add a comment to invoke [`JNIEnv::ExceptionDescribe()`][1]. We don't always want this to be present, but when we do want it… * While `NO_MARSHAL_MEMBER_BUILDER_SUPPORT` is set -- which means that `Java.Interop.Export`-related tests aren't run -- there are some fixes for `Java.Interop.Export` & related unit tests for .NET Core, to avoid the use of generic delegate types and to avoid a `Type.GetType()` which is no longer needed. [0]: https://docs.microsoft.com/dotnet/csharp/nullable-references [1]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#ExceptionDescribe
33da2df
to
763963a
Compare
Enable C#8 Nullable Reference Types for
Java.Runtime.Environment.dll
.Add partial support for a "non-bridged backend", so that a
JniRuntime.JniValueManager
exists for .NET Core. This new"managed" backed is used if the Mono runtime is not used.
To work,
ManagedValueManager
holds strong references toIJavaPeerable
instances. As such, tests which required the use ofGC integration are now "optional", conditional on the
!NO_GC_BRIDGE_SUPPORT
define.The
ManagedValueManager.CollectPeers()
method callsIJavaPeerable.Dispose()
on all currently referenced peers, thenstops referencing the managed peers.
This causes all GREFs to be dropped, allowing Java peers to be
collected, and then allows the .NET GC to collect the
IJavaPeerable
values.
Any and all exceptions thrown by
IJavaPeerable.Dispose()
arecaught and re-thrown by an
AggregateException
.Update
Java.Interop-Tests.csproj
to defineNO_GC_BRIDGE_SUPPORT
and
NO_MARSHAL_MEMBER_BUILDER_SUPPORT
when building for .NET Core.This excludes all currently "troublesome"/non-passing tests.
These changes allow all remaining
Java.Interop-Tests
unit tests toexecute under .NET Core:
Other changes:
The attempt to retain useful Java-side exceptions in 89a5a22
proved to be incomplete. Add a comment to invoke
JNIEnv::ExceptionDescribe()
. We don't always want thisto be present, but when we do want it…
While
NO_MARSHAL_MEMBER_BUILDER_SUPPORT
is set -- which meansthat
Java.Interop.Export
-related tests aren't run -- there aresome fixes for
Java.Interop.Export
& related unit tests for.NET Core, to avoid the use of generic delegate types and to
avoid a
Type.GetType()
which is no longer needed.