Skip to content

Commit b3a2162

Browse files
committed
[Java.Interop] JniRuntime.JniValueManager API Review
As threatened in commit 9d6e160: > 1. Most (all?) of the logic within JniRuntime.JniValueManager is > going to need to be moved into subclasses, in order to remove > Mono-isms/requirements from the API contract (e.g. a > non-GC-oriented implementation for execution on desktop .NET). Also threatened in commit f5ce0ad: > * Review the JniRuntime.JniValueManager API for sanity. > Ideally it should be possible to implement "sanely" on .NET, > though possibly *without* GC integration. Perhaps "manual" GCs > are supportable, e.g. a JniRuntime.ValueManager.Collect() method > which the developer must invoke occasionally. > (Terrible, certainly, but possibly useful for prototypes?) IT IS TIME. Review the JniRuntime.JniValueManager API, moving as much "sensible" logic which deals with object lifetime management out of JniRuntime.JniValueManager and into MonoRuntimeValueManager (in Java.Runtime.Environment.dll). Doing this *ensures* that IJavaPeerable be fully ipmlementable without the usef of internal calls, and helps ensure that JniValueManager is a (reasonably?) complete abstraction. This does *not* currently impact the value *creation* logic such as JniRuntime.JniValueManager.CreateValue<T>() (commit c659341), as these methods don't deal directly with object lifetime management. Of note is the current JniRuntime.JniValueManager abstraction: partial abstract class JniValueManager { // Snapshot of all managed objects. public abstract List<WeakReference<IJavaPeerable>> GetSurfacedObjects () // Obtain mapping from JNI handle to IJavaPeerable public abstract IJavaPeerable PeekObject (JniObjectReference reference); // Add a value to the manager; value added should be obtainable // via PeekObject(). public abstract void Add (IJavaPeerable value); // Remove a value from the manager. Value should no longer be // obtainable from PeekObject() public abstract void Remove (IJavaPeerable value); // Called from IJavaPeerable implementation finalizer; // Does whatever needs to be done from a finalizer. ;-) public abstract void Finalize (IJavaPeerable value); // Perform a "garbage collection" of all values under management. public abstract void Collect (); public abstract void WaitForGCBridgeProcessing (); } TODO: Provde a non-Mono JniRuntime.JniValueManager implementation for use on .NET/CoreCLR to ensure that the abstraction is sufficiently complete for use. TODO: Review MonoRuntimeValueManager.Finalize(). It's doing *significantly more work* than Xamarin.Android's Java.Lang.Object finalizer does, and trying to reduce the work done breaks tests.
1 parent ca5ebff commit b3a2162

14 files changed

+364
-341
lines changed

src/Java.Interop/Java.Interop/JavaException.cs

Lines changed: 31 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,8 @@ unsafe public class JavaException : Exception, IJavaPeerable
2929
public unsafe JavaException ()
3030
{
3131
var peer = JniPeerMembers.InstanceMethods.StartCreateInstance ("()V", GetType (), null);
32-
using (SetPeerReference (
33-
ref peer,
34-
JniObjectReferenceOptions.CopyAndDispose)) {
35-
JniPeerMembers.InstanceMethods.FinishCreateInstance ("()V", this, null);
36-
}
32+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
33+
JniPeerMembers.InstanceMethods.FinishCreateInstance ("()V", this, null);
3734
javaStackTrace = _GetJavaStack (PeerReference);
3835
}
3936

@@ -46,11 +43,8 @@ public unsafe JavaException (string message)
4643
var args = stackalloc JniArgumentValue [1];
4744
args [0] = new JniArgumentValue (native_message);
4845
var peer = JniPeerMembers.InstanceMethods.StartCreateInstance (signature, GetType (), args);
49-
using (SetPeerReference (
50-
ref peer,
51-
JniObjectReferenceOptions.CopyAndDispose)) {
52-
JniPeerMembers.InstanceMethods.FinishCreateInstance (signature, this, args);
53-
}
46+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
47+
JniPeerMembers.InstanceMethods.FinishCreateInstance (signature, this, args);
5448
} finally {
5549
JniObjectReference.Dispose (ref native_message, JniObjectReferenceOptions.CopyAndDispose);
5650
}
@@ -66,11 +60,8 @@ public unsafe JavaException (string message, Exception innerException)
6660
var args = stackalloc JniArgumentValue [1];
6761
args [0] = new JniArgumentValue (native_message);
6862
var peer = JniPeerMembers.InstanceMethods.StartCreateInstance (signature, GetType (), args);
69-
using (SetPeerReference (
70-
ref peer,
71-
JniObjectReferenceOptions.CopyAndDispose)) {
72-
JniPeerMembers.InstanceMethods.FinishCreateInstance (signature, this, args);
73-
}
63+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
64+
JniPeerMembers.InstanceMethods.FinishCreateInstance (signature, this, args);
7465
} finally {
7566
JniObjectReference.Dispose (ref native_message, JniObjectReferenceOptions.CopyAndDispose);
7667
}
@@ -85,14 +76,19 @@ public JavaException (ref JniObjectReference reference, JniObjectReferenceOption
8576

8677
if (!reference.IsValid)
8778
return;
88-
using (SetPeerReference (ref reference, transfer)) {
89-
}
79+
80+
Construct (ref reference, transfer);
9081
javaStackTrace = _GetJavaStack (PeerReference);
9182
}
9283

84+
protected void Construct (ref JniObjectReference reference, JniObjectReferenceOptions options)
85+
{
86+
JniEnvironment.Runtime.ValueManager.Construct (this, ref reference, options);
87+
}
88+
9389
~JavaException ()
9490
{
95-
JniEnvironment.Runtime.ValueManager.TryCollectObject (this);
91+
JniEnvironment.Runtime.ValueManager.Finalize (this);
9692
}
9793

9894
public JniObjectReference PeerReference {
@@ -129,20 +125,29 @@ public override string StackTrace {
129125
}
130126
}
131127

132-
protected SetSafeHandleCompletion SetPeerReference (ref JniObjectReference handle, JniObjectReferenceOptions transfer)
128+
protected void SetPeerReference (ref JniObjectReference reference, JniObjectReferenceOptions options)
133129
{
134-
return JniEnvironment.Runtime.ValueManager.SetObjectPeerReference (
135-
this,
136-
ref handle,
137-
transfer,
138-
a => new SetSafeHandleCompletion (a));
130+
if (options == JniObjectReferenceOptions.None) {
131+
((IJavaPeerable) this).SetPeerReference (new JniObjectReference ());
132+
return;
133+
}
134+
135+
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
136+
this.reference = reference;
137+
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
138+
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
139+
this.handle = reference.Handle;
140+
this.handle_type = reference.Type;
141+
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
142+
143+
JniObjectReference.Dispose (ref reference, options);
139144
}
140145

141146
public void UnregisterFromRuntime ()
142147
{
143148
if (!PeerReference.IsValid)
144149
throw new ObjectDisposedException (GetType ().FullName);
145-
JniEnvironment.Runtime.ValueManager.UnRegisterObject (this);
150+
JniEnvironment.Runtime.ValueManager.Remove (this);
146151
}
147152

148153
public void Dispose ()
@@ -244,29 +249,7 @@ void IJavaPeerable.SetJniIdentityHashCode (int value)
244249

245250
void IJavaPeerable.SetPeerReference (JniObjectReference reference)
246251
{
247-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
248-
this.reference = reference;
249-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
250-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
251-
this.handle = reference.Handle;
252-
this.handle_type = reference.Type;
253-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
254-
}
255-
256-
protected struct SetSafeHandleCompletion : IDisposable {
257-
258-
readonly Action action;
259-
260-
public SetSafeHandleCompletion (Action action)
261-
{
262-
this.action = action;
263-
}
264-
265-
public void Dispose ()
266-
{
267-
if (action != null)
268-
action ();
269-
}
252+
SetPeerReference (ref reference, JniObjectReferenceOptions.Copy);
270253
}
271254
}
272255
}

src/Java.Interop/Java.Interop/JavaObject.cs

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ unsafe public class JavaObject : IJavaPeerable
2626

2727
~JavaObject ()
2828
{
29-
JniEnvironment.Runtime.ValueManager.TryCollectObject (this);
29+
JniEnvironment.Runtime.ValueManager.Finalize (this);
3030
}
3131

3232
public JniObjectReference PeerReference {
@@ -51,39 +51,49 @@ public virtual JniPeerMembers JniPeerMembers {
5151
get {return _members;}
5252
}
5353

54-
public JavaObject (ref JniObjectReference reference, JniObjectReferenceOptions transfer)
54+
public JavaObject (ref JniObjectReference reference, JniObjectReferenceOptions options)
5555
{
56-
if (transfer == JniObjectReferenceOptions.None)
56+
if (options == JniObjectReferenceOptions.None)
5757
return;
5858

59-
using (SetPeerReference (ref reference, transfer)) {
60-
}
59+
Construct (ref reference, options);
6160
}
6261

6362
public unsafe JavaObject ()
6463
{
6564
var peer = JniPeerMembers.InstanceMethods.StartCreateInstance ("()V", GetType (), null);
66-
using (SetPeerReference (
67-
ref peer,
68-
JniObjectReferenceOptions.CopyAndDispose)) {
69-
JniPeerMembers.InstanceMethods.FinishCreateInstance ("()V", this, null);
70-
}
65+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
66+
JniPeerMembers.InstanceMethods.FinishCreateInstance ("()V", this, null);
7167
}
7268

73-
protected SetPeerReferenceCompletion SetPeerReference (ref JniObjectReference handle, JniObjectReferenceOptions transfer)
69+
protected void Construct (ref JniObjectReference reference, JniObjectReferenceOptions options)
7470
{
75-
return JniEnvironment.Runtime.ValueManager.SetObjectPeerReference (
76-
this,
77-
ref handle,
78-
transfer,
79-
a => new SetPeerReferenceCompletion (a));
71+
JniEnvironment.Runtime.ValueManager.Construct (this, ref reference, options);
72+
}
73+
74+
protected void SetPeerReference (ref JniObjectReference reference, JniObjectReferenceOptions options)
75+
{
76+
if (options == JniObjectReferenceOptions.None) {
77+
((IJavaPeerable) this).SetPeerReference (new JniObjectReference ());
78+
return;
79+
}
80+
81+
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
82+
this.reference = reference;
83+
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
84+
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
85+
this.handle = reference.Handle;
86+
this.handle_type = reference.Type;
87+
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
88+
89+
JniObjectReference.Dispose (ref reference, options);
8090
}
8191

8292
public void UnregisterFromRuntime ()
8393
{
8494
if (!PeerReference.IsValid)
8595
throw new ObjectDisposedException (GetType ().FullName);
86-
JniEnvironment.Runtime.ValueManager.UnRegisterObject (this);
96+
JniEnvironment.Runtime.ValueManager.Remove (this);
8797
}
8898

8999
public void Dispose ()
@@ -141,32 +151,9 @@ void IJavaPeerable.SetJniIdentityHashCode (int value)
141151
keyHandle = value;
142152
}
143153

144-
145154
void IJavaPeerable.SetPeerReference (JniObjectReference reference)
146155
{
147-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
148-
this.reference = reference;
149-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
150-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
151-
this.handle = reference.Handle;
152-
this.handle_type = reference.Type;
153-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
154-
}
155-
156-
protected struct SetPeerReferenceCompletion : IDisposable {
157-
158-
readonly Action action;
159-
160-
public SetPeerReferenceCompletion (Action action)
161-
{
162-
this.action = action;
163-
}
164-
165-
public void Dispose ()
166-
{
167-
if (action != null)
168-
action ();
169-
}
156+
SetPeerReference (ref reference, JniObjectReferenceOptions.Copy);
170157
}
171158
}
172159
}

src/Java.Interop/Java.Interop/JavaObjectArray.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ public unsafe JavaObjectArray (int length)
2828
: this (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
2929
{
3030
var peer = _NewArray (CheckLength (length));
31-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
32-
}
31+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
3332
}
3433

3534
public JavaObjectArray (IList<T> value)

src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,8 @@ public JavaBooleanArray (ref JniObjectReference handle, JniObjectReferenceOption
9595
public unsafe JavaBooleanArray (int length)
9696
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
9797
{
98-
var peer = JniEnvironment.Arrays.NewBooleanArray (CheckLength (length));
99-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
100-
}
98+
var peer = JniEnvironment.Arrays.NewBooleanArray (CheckLength (length));
99+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
101100
}
102101

103102
public JavaBooleanArray (System.Collections.Generic.IList<Boolean> value)
@@ -243,9 +242,8 @@ public JavaSByteArray (ref JniObjectReference handle, JniObjectReferenceOptions
243242
public unsafe JavaSByteArray (int length)
244243
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
245244
{
246-
var peer = JniEnvironment.Arrays.NewByteArray (CheckLength (length));
247-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
248-
}
245+
var peer = JniEnvironment.Arrays.NewByteArray (CheckLength (length));
246+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
249247
}
250248

251249
public JavaSByteArray (System.Collections.Generic.IList<SByte> value)
@@ -391,9 +389,8 @@ public JavaCharArray (ref JniObjectReference handle, JniObjectReferenceOptions o
391389
public unsafe JavaCharArray (int length)
392390
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
393391
{
394-
var peer = JniEnvironment.Arrays.NewCharArray (CheckLength (length));
395-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
396-
}
392+
var peer = JniEnvironment.Arrays.NewCharArray (CheckLength (length));
393+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
397394
}
398395

399396
public JavaCharArray (System.Collections.Generic.IList<Char> value)
@@ -539,9 +536,8 @@ public JavaInt16Array (ref JniObjectReference handle, JniObjectReferenceOptions
539536
public unsafe JavaInt16Array (int length)
540537
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
541538
{
542-
var peer = JniEnvironment.Arrays.NewShortArray (CheckLength (length));
543-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
544-
}
539+
var peer = JniEnvironment.Arrays.NewShortArray (CheckLength (length));
540+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
545541
}
546542

547543
public JavaInt16Array (System.Collections.Generic.IList<Int16> value)
@@ -687,9 +683,8 @@ public JavaInt32Array (ref JniObjectReference handle, JniObjectReferenceOptions
687683
public unsafe JavaInt32Array (int length)
688684
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
689685
{
690-
var peer = JniEnvironment.Arrays.NewIntArray (CheckLength (length));
691-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
692-
}
686+
var peer = JniEnvironment.Arrays.NewIntArray (CheckLength (length));
687+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
693688
}
694689

695690
public JavaInt32Array (System.Collections.Generic.IList<Int32> value)
@@ -835,9 +830,8 @@ public JavaInt64Array (ref JniObjectReference handle, JniObjectReferenceOptions
835830
public unsafe JavaInt64Array (int length)
836831
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
837832
{
838-
var peer = JniEnvironment.Arrays.NewLongArray (CheckLength (length));
839-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
840-
}
833+
var peer = JniEnvironment.Arrays.NewLongArray (CheckLength (length));
834+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
841835
}
842836

843837
public JavaInt64Array (System.Collections.Generic.IList<Int64> value)
@@ -983,9 +977,8 @@ public JavaSingleArray (ref JniObjectReference handle, JniObjectReferenceOptions
983977
public unsafe JavaSingleArray (int length)
984978
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
985979
{
986-
var peer = JniEnvironment.Arrays.NewFloatArray (CheckLength (length));
987-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
988-
}
980+
var peer = JniEnvironment.Arrays.NewFloatArray (CheckLength (length));
981+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
989982
}
990983

991984
public JavaSingleArray (System.Collections.Generic.IList<Single> value)
@@ -1131,9 +1124,8 @@ public JavaDoubleArray (ref JniObjectReference handle, JniObjectReferenceOptions
11311124
public unsafe JavaDoubleArray (int length)
11321125
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
11331126
{
1134-
var peer = JniEnvironment.Arrays.NewDoubleArray (CheckLength (length));
1135-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
1136-
}
1127+
var peer = JniEnvironment.Arrays.NewDoubleArray (CheckLength (length));
1128+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
11371129
}
11381130

11391131
public JavaDoubleArray (System.Collections.Generic.IList<Double> value)

src/Java.Interop/Java.Interop/JavaPrimitiveArrays.tt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,8 @@ namespace Java.Interop {
8585
public unsafe Java<#= info.TypeModifier #>Array (int length)
8686
: base (ref *InvalidJniObjectReference, JniObjectReferenceOptions.None)
8787
{
88-
var peer = JniEnvironment.Arrays.New<#= info.JniMarshalType #>Array (CheckLength (length));
89-
using (SetPeerReference (ref peer, JniObjectReferenceOptions.CopyAndDispose)) {
90-
}
88+
var peer = JniEnvironment.Arrays.New<#= info.JniMarshalType #>Array (CheckLength (length));
89+
Construct (ref peer, JniObjectReferenceOptions.CopyAndDispose);
9190
}
9291

9392
public Java<#= info.TypeModifier #>Array (System.Collections.Generic.IList<<#= info.ManagedType #>> value)

0 commit comments

Comments
 (0)