dotnet / java-interop

Java.Interop provides open-source bindings of Java's Java Native Interface (JNI) for use with .NET managed languages such as C#
Other
198 stars 51 forks source link

Add a JniEnvironment.BeginGetValueScope() method. #4

Open jonpryor opened 9 years ago

jonpryor commented 9 years ago

Building upon Issue #3, we expect JavaVM.GetValue() calls to be "buried" within binding code, not directly invoked by developers (most of the time). Thus, how does a developer tell a binding method that a new value should be created instead of retrieving a possibly shared value?

Introduce JniEnvironment.BeginGetValueScope(GetValueScope):

[Flags]
public enum GetValueBehaviors {
    Default                = 0,
    CreateValues           = 1,
    DoNotMarshalExceptions = 2,
}

partial class JniEnvironment {
    public static IDisposable BeginGetValueBehaviors (GetValueBehaviors scope);
}

Calling JniEnviornment.BeginGetValueBehaviors() would alter the behavior of JavaVM.GetValue(): if GetValueBehaviors.CreateValues is specified, then JavaVM.GetValue() will instead behave like JavaVM.CreateValue(). This allows the end user to maintain some degree of control:

using (var scope = JniEnvironment.BeginGetValueBehaviors (GetValueBehaviors.CreateValues))
using (var typeface = Typeface.Create (...)) {
    // use typeface
}

The above allows disposing of the temporary with impunity, as BeginGetValueScope() will ensure that Typeface.Create() returns unique wrappers instead of possibly shared wrappers.

jonpryor commented 9 years ago

Another option for GetValueScope is to inhibit exception marshaling: Xamarin.Forms has a request to just have the app exit if an exception is thrown, because it Can't Happen, and if it does there's nothing reasonable to do.

Consequently, it would be helpful if exception marshaling could be inhibited in a similar manner.

jonpryor commented 3 years ago

WRT inhibiting exception marshaling, the whole concern was around needing to have two JNI invocations "everywhere", e.g. https://github.com/xamarin/java.interop/blob/main/tests/invocation-overhead/jni.cs#L6095-L6099

(in which JniEnvironment.GetExceptionForLastThrowable() called JNIEnv::ExceptionOccurred() occurred.)

Calling through the delegates is not a "zero-cost" operation, so the idea behind GetValueBehaviors.DoNotMarshalExceptions was as an assertion that "this method will not throw", and thus we could avoid the JNIEnv::ExceptionOccurred() invocation.

However, with the "new" P/Invoke-based system in 926e4bc46ede2cad861d199a5f4290195488a5af (not really "new" anymore), JNIEnv::ExceptionOccurred() is done as part of the C layer, not C#+delegates, and is faster. (Still not zero-cost, but faster.)

I thus don't see much need for GetValueBehaviors.DoNotMarshalExceptions.

GetValueBehaviors.CreateValues still seems like a good idea, but needs to be "paired with" a noun to describe existing behavior, e.g. .IdentityValues?

jonpryor commented 10 months ago

Quasi-related: https://github.com/jonpryor/java.interop/commits/jonp-registration-scope