internal static void AssertSelf(IJavaPeerable self) { if (self == null) { throw new ArgumentNullException(nameof(self)); } var peer = self.PeerReference; if (!peer.IsValid) { throw new ObjectDisposedException(self.GetType().FullName); } #if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES var lref = peer.SafeHandle as JniLocalReference; if (lref != null && !JniEnvironment.IsHandleValid(lref)) { var t = self.GetType().FullName; throw new NotSupportedException( "You've created a " + t + " in one thread and are using it " + "from another thread without calling IJavaPeerable.Register(). " + "Passing JNI local references between threads is not supported; " + "call IJavaObject.RegisterWithVM() if sharing between threads is required."); } #endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES }
public override void FinalizePeer(IJavaPeerable value) { var h = value.PeerReference; var o = Runtime.ObjectReferenceManager; // MUST NOT use SafeHandle.ReferenceType: local refs are tied to a JniEnvironment // and the JniEnvironment's corresponding thread; it's a thread-local value. // Accessing SafeHandle.ReferenceType won't kill anything (so far...), but // instead it always returns JniReferenceType.Invalid. if (!h.IsValid || h.Type == JniObjectReferenceType.Local) { if (o.LogGlobalReferenceMessages) { o.WriteGlobalReferenceLine("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}", h.ToString(), value.JniIdentityHashCode.ToString("x"), RuntimeHelpers.GetHashCode(value).ToString("x"), value.GetType().ToString()); } RemovePeer(value); value.SetPeerReference(new JniObjectReference()); value.Finalized(); return; } try { bool collected = TryGC(value, ref h); if (collected) { RemovePeer(value); value.SetPeerReference(new JniObjectReference()); if (o.LogGlobalReferenceMessages) { o.WriteGlobalReferenceLine("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}", h.ToString(), value.JniIdentityHashCode.ToString("x"), RuntimeHelpers.GetHashCode(value).ToString("x"), value.GetType().ToString()); } value.Finalized(); } else { value.SetPeerReference(h); GC.ReRegisterForFinalize(value); } } catch (Exception e) { Runtime.FailFast("Unable to perform a GC! " + e); } }
void Dispose(JniObjectReference h, IJavaPeerable value) { value.Disposed(); Remove(value); var o = Runtime.ObjectReferenceManager; if (o.LogGlobalReferenceMessages) { o.WriteGlobalReferenceLine("Disposing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3} Java.Type={4}", h.ToString(), value.JniIdentityHashCode.ToString("x"), RuntimeHelpers.GetHashCode(value).ToString("x"), value.GetType().ToString(), JniEnvironment.Types.GetJniTypeNameFromInstance(h)); } #if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES var lref = value.PeerReference.SafeHandle as JniLocalReference; if (lref != null && !JniEnvironment.IsHandleValid(lref)) { // `lref` was created on another thread, and CANNOT be disposed on this thread. // Just invalidate the reference and move on. lref.SetHandleAsInvalid(); } #endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES JniObjectReference.Dispose(ref h); value.SetPeerReference(new JniObjectReference()); GC.SuppressFinalize(value); }
public override void AddPeer(IJavaPeerable value) { if (RegisteredInstances == null) { throw new ObjectDisposedException(nameof(MonoRuntimeValueManager)); } var r = value.PeerReference; if (!r.IsValid) { throw new ObjectDisposedException(value.GetType().FullName); } var o = PeekPeer(value.PeerReference); if (o != null) { return; } if (r.Type != JniObjectReferenceType.Global) { value.SetPeerReference(r.NewGlobalRef()); JniObjectReference.Dispose(ref r, JniObjectReferenceOptions.CopyAndDispose); } int key = value.JniIdentityHashCode; lock (RegisteredInstances) { List <IJavaPeerable> peers; if (!RegisteredInstances.TryGetValue(key, out peers)) { peers = new List <IJavaPeerable> () { value, }; RegisteredInstances.Add(key, peers); return; } for (int i = peers.Count - 1; i >= 0; i--) { var p = peers [i]; if (!JniEnvironment.Types.IsSameObject(p.PeerReference, value.PeerReference)) { continue; } if (Replaceable(p)) { peers [i] = value; } else { WarnNotReplacing(key, value, p); } return; } peers.Add(value); } }
public void Construct(IJavaPeerable peer, ref JniObjectReference reference, JniObjectReferenceOptions options) { if (peer == null) { throw new ArgumentNullException(nameof(peer)); } var newRef = peer.PeerReference; if (newRef.IsValid) { // Activation! See ManagedPeer.RunConstructor peer.SetJniManagedPeerState(peer.JniManagedPeerState | JniManagedPeerStates.Activatable); JniObjectReference.Dispose(ref reference, options); newRef = newRef.NewGlobalRef(); } else if (options == JniObjectReferenceOptions.None) { // `reference` is likely *InvalidJniObjectReference, and can't be touched return; } else if (!reference.IsValid) { throw new ArgumentException("JNI Object Reference is invalid.", nameof(reference)); } else { newRef = reference; if ((options & JniObjectReferenceOptions.Copy) == JniObjectReferenceOptions.Copy) { newRef = reference.NewGlobalRef(); } JniObjectReference.Dispose(ref reference, options); } peer.SetPeerReference(newRef); peer.SetJniIdentityHashCode(JniSystem.IdentityHashCode(newRef)); var o = Runtime.ObjectReferenceManager; if (o.LogGlobalReferenceMessages) { o.WriteGlobalReferenceLine("Created PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}, Java.Type={4}", newRef.ToString(), peer.JniIdentityHashCode.ToString("x"), RuntimeHelpers.GetHashCode(peer).ToString("x"), peer.GetType().FullName, JniEnvironment.Types.GetJniTypeNameFromInstance(newRef)); } if ((options & DoNotRegisterTarget) != DoNotRegisterTarget) { Add(peer); } }
protected override bool UsesVirtualDispatch(IJavaPeerable value, Type declaringType) { var peerType = GetThresholdType (value); if (peerType != null) { return peerType == value.GetType (); } return base.UsesVirtualDispatch (value, declaringType); }
protected override bool UsesVirtualDispatch(IJavaPeerable value, Type declaringType) { var peerType = GetThresholdType(value); if (peerType != null) { return(peerType == value.GetType()); } return(base.UsesVirtualDispatch(value, declaringType)); }
internal void AddPeer(IJavaPeerable value, IntPtr handle, JniHandleOwnership transfer, out IntPtr handleField) { if (handle == IntPtr.Zero) { handleField = handle; return; } var transferType = transfer & (JniHandleOwnership.DoNotTransfer | JniHandleOwnership.TransferLocalRef | JniHandleOwnership.TransferGlobalRef); switch (transferType) { case JniHandleOwnership.DoNotTransfer: handleField = JNIEnv.NewGlobalRef(handle); break; case JniHandleOwnership.TransferLocalRef: handleField = JNIEnv.NewGlobalRef(handle); JNIEnv.DeleteLocalRef(handle); break; case JniHandleOwnership.TransferGlobalRef: handleField = handle; break; default: throw new ArgumentOutOfRangeException("transfer", transfer, "Invalid `transfer` value: " + transfer + " on type " + value.GetType()); } if (handleField == IntPtr.Zero) { throw new InvalidOperationException("Unable to allocate Global Reference for object '" + value.ToString() + "'!"); } IntPtr hash = JNIEnv.IdentityHash !(handleField); value.SetJniIdentityHashCode((int)hash); if ((transfer & JniHandleOwnership.DoNotRegister) == 0) { AddPeer(value, new JniObjectReference(handleField, JniObjectReferenceType.Global), hash); } if (Logger.LogGlobalRef) { JNIEnv._monodroid_gref_log("handle 0x" + handleField.ToString("x") + "; key_handle 0x" + hash.ToString("x") + ": Java Type: `" + JNIEnv.GetClassNameFromInstance(handleField) + "`; " + "MCW type: `" + value.GetType().FullName + "`\n"); } }
void WarnNotReplacing(int key, IJavaPeerable ignoreValue, IJavaPeerable keepValue) { Runtime.ObjectReferenceManager.WriteGlobalReferenceLine( "Warning: Not registering PeerReference={0} IdentityHashCode=0x{1} Instance={2} Instance.Type={3} Java.Type={4}; " + "keeping previously registered PeerReference={5} Instance={6} Instance.Type={7} Java.Type={8}.", ignoreValue.PeerReference.ToString(), key.ToString("x"), RuntimeHelpers.GetHashCode(ignoreValue).ToString("x"), ignoreValue.GetType().FullName, JniEnvironment.Types.GetJniTypeNameFromInstance(ignoreValue.PeerReference), keepValue.PeerReference.ToString(), RuntimeHelpers.GetHashCode(keepValue).ToString("x"), keepValue.GetType().FullName, JniEnvironment.Types.GetJniTypeNameFromInstance(keepValue.PeerReference)); }
public unsafe void FinishCreateInstance(string constructorSignature, IJavaPeerable self, JniArgumentValue *parameters) { if (constructorSignature == null) { throw new ArgumentNullException(nameof(constructorSignature)); } if (self == null) { throw new ArgumentNullException(nameof(self)); } if (JniEnvironment.Runtime.NewObjectRequired) { return; } var methods = GetConstructorsForType(self.GetType()); var ctor = methods.GetConstructor(constructorSignature); JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod(self.PeerReference, methods.JniPeerType.PeerReference, ctor, parameters); }
protected virtual bool UsesVirtualDispatch(IJavaPeerable value, Type?declaringType) { return(value.GetType() == declaringType || declaringType == null || value.GetType() == value.JniPeerMembers.ManagedPeerType); }
public override void AddPeer(IJavaPeerable value) { var r = value.PeerReference; if (!r.IsValid) { throw new ObjectDisposedException(value.GetType().FullName); } var o = PeekPeer(value.PeerReference); if (o != null) { return; } if (r.Type != JniObjectReferenceType.Global) { value.SetPeerReference(r.NewGlobalRef()); JniObjectReference.Dispose(ref r, JniObjectReferenceOptions.CopyAndDispose); } int key = value.JniIdentityHashCode; lock (RegisteredInstances) { List <WeakReference <IJavaPeerable> > peers; if (!RegisteredInstances.TryGetValue(key, out peers)) { peers = new List <WeakReference <IJavaPeerable> > () { new WeakReference <IJavaPeerable>(value, trackResurrection: true), }; RegisteredInstances.Add(key, peers); return; } for (int i = peers.Count - 1; i >= 0; i--) { var wp = peers [i]; IJavaPeerable p; if (!wp.TryGetTarget(out p)) { // Peer was collected peers.RemoveAt(i); continue; } if (!JniEnvironment.Types.IsSameObject(p.PeerReference, value.PeerReference)) { continue; } if (Replaceable(p)) { peers [i] = new WeakReference <IJavaPeerable>(value, trackResurrection: true); } else { WarnNotReplacing(key, value, p); } return; } peers.Add(new WeakReference <IJavaPeerable> (value, trackResurrection: true)); } }