public override void DestroyGenericArgumentState(Single value, ref JniValueMarshalerState state, ParameterAttributes synchronize)
        {
            var r = state.ReferenceValue;

            JniObjectReference.Dispose(ref r);
            state = new JniValueMarshalerState();
        }
            ConstructorInfo GetPeerConstructor(JniObjectReference instance, Type fallbackType)
            {
                var klass       = JniEnvironment.Types.GetObjectClass(instance);
                var jniTypeName = JniEnvironment.Types.GetJniTypeNameFromClass(klass);

                Type type = null;

                while (jniTypeName != null)
                {
                    type = Runtime.TypeManager.GetType(JniTypeSignature.Parse(jniTypeName));

                    if (type != null)
                    {
                        var ctor = GetActivationConstructor(type);

                        if (ctor != null)
                        {
                            JniObjectReference.Dispose(ref klass);
                            return(ctor);
                        }
                    }

                    var super = JniEnvironment.Types.GetSuperclass(klass);
                    jniTypeName = super.IsValid
                                                ? JniEnvironment.Types.GetJniTypeNameFromClass(super)
                                                : null;

                    JniObjectReference.Dispose(ref klass, JniObjectReferenceOptions.CopyAndDispose);
                    klass = super;
                }
                JniObjectReference.Dispose(ref klass, JniObjectReferenceOptions.CopyAndDispose);

                return(GetActivationConstructor(fallbackType));
            }
Exemple #3
0
            public object CreateValue(ref JniObjectReference reference, JniObjectReferenceOptions options, Type targetType = null)
            {
                if (!reference.IsValid)
                {
                    return(null);
                }

                if (targetType != null && typeof(IJavaPeerable).GetTypeInfo().IsAssignableFrom(targetType.GetTypeInfo()))
                {
                    return(JavaPeerableValueMarshaler.Instance.CreateGenericValue(ref reference, options, targetType));
                }

                var boxed = PeekBoxedObject(reference);

                if (boxed != null)
                {
                    JniObjectReference.Dispose(ref reference, options);
                    if (targetType != null)
                    {
                        return(Convert.ChangeType(boxed, targetType));
                    }
                    return(boxed);
                }

                targetType = targetType ?? GetRuntimeType(reference);
                if (targetType == null)
                {
                    // Let's hope this is an IJavaPeerable!
                    return(JavaPeerableValueMarshaler.Instance.CreateGenericValue(ref reference, options, targetType));
                }
                var marshaler = GetValueMarshaler(targetType);

                return(marshaler.CreateValue(ref reference, options, targetType));
            }
Exemple #4
0
            public object GetValue(ref JniObjectReference reference, JniObjectReferenceOptions options, Type targetType = null)
            {
                if (!reference.IsValid)
                {
                    return(null);
                }

                var existing = PeekValue(reference);

                if (existing != null && (targetType == null || targetType.GetTypeInfo().IsAssignableFrom(existing.GetType().GetTypeInfo())))
                {
                    JniObjectReference.Dispose(ref reference, options);
                    return(existing);
                }

                if (targetType != null && typeof(IJavaPeerable).GetTypeInfo().IsAssignableFrom(targetType.GetTypeInfo()))
                {
                    return(JavaPeerableValueMarshaler.Instance.CreateGenericValue(ref reference, options, targetType));
                }

                targetType = targetType ?? GetRuntimeType(reference);
                if (targetType == null)
                {
                    // Let's hope this is an IJavaPeerable!
                    return(JavaPeerableValueMarshaler.Instance.CreateGenericValue(ref reference, options, targetType));
                }
                var marshaler = GetValueMarshaler(targetType);

                return(marshaler.CreateValue(ref reference, options, targetType));
            }
Exemple #5
0
            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);
            }
Exemple #6
0
        public override object CreateGenericValue(ref JniObjectReference reference, JniObjectReferenceOptions options, Type targetType)
        {
            var jvm = JniEnvironment.Runtime;

            if (targetType == null || targetType == typeof(object))
            {
                targetType = jvm.ValueManager.GetRuntimeType(reference);
            }
            if (targetType != null)
            {
                var vm = jvm.ValueManager.GetValueMarshaler(targetType);
                if (vm != Instance)
                {
                    return(vm.CreateValue(ref reference, options, targetType));
                }
            }

            var target = jvm.ValueManager.PeekValue(reference);

            if (target != null)
            {
                JniObjectReference.Dispose(ref reference, options);
                return(target);
            }
            // Punt! Hope it's a java.lang.Object
            return(jvm.ValueManager.CreatePeer(ref reference, options, targetType));
        }
Exemple #7
0
 unsafe string _GetJavaStack(JniObjectReference handle)
 {
     using (var StringWriter_class = new JniType("java/io/StringWriter"))
         using (var PrintWriter_class = new JniType("java/io/PrintWriter")) {
             var StringWriter_init = StringWriter_class.GetConstructor("()V");
             var PrintWriter_init  = PrintWriter_class.GetConstructor("(Ljava/io/Writer;)V");
             var swriter           = StringWriter_class.NewObject(StringWriter_init, null);
             try {
                 var pwriter_args = stackalloc JniArgumentValue [1];
                 pwriter_args [0] = new JniArgumentValue(swriter);
                 var pwriter = PrintWriter_class.NewObject(PrintWriter_init, pwriter_args);
                 try {
                     var pst      = _members.InstanceMethods.GetMethodInfo("printStackTrace.(Ljava/io/PrintWriter;)V");
                     var pst_args = stackalloc JniArgumentValue [1];
                     pst_args [0] = new JniArgumentValue(pwriter);
                     JniEnvironment.InstanceMethods.CallVoidMethod(handle, pst, pst_args);
                     var s = JniEnvironment.Object.ToString(swriter);
                     return(JniEnvironment.Strings.ToString(ref s, JniObjectReferenceOptions.CopyAndDispose));
                 } finally {
                     JniObjectReference.Dispose(ref pwriter, JniObjectReferenceOptions.CopyAndDispose);
                 }
             } finally {
                 JniObjectReference.Dispose(ref swriter, JniObjectReferenceOptions.CopyAndDispose);
             }
         }
 }
        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);
            }
        }
Exemple #9
0
            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);
                }
            }
 internal static Int64 GetValueFromJni(ref JniObjectReference self, JniObjectReferenceOptions transfer, Type targetType)
 {
     Debug.Assert(targetType == null || targetType == typeof(Int64), "Expected targetType==typeof(Int64); was: " + targetType);
     TypeRef.GetCachedInstanceMethod(ref longValue, "longValue", "()J");
     try {
         return(JniEnvironment.InstanceMethods.CallLongMethod(self, longValue));
     } finally {
         JniObjectReference.Dispose(ref self, transfer);
     }
 }
Exemple #11
0
 internal static Char GetValueFromJni(ref JniObjectReference self, JniObjectReferenceOptions transfer, Type?targetType)
 {
     Debug.Assert(targetType == null || targetType == typeof(Char), "Expected targetType==typeof(Char); was: " + targetType);
     TypeRef.GetCachedInstanceMethod(ref charValue, "charValue", "()C");
     try {
         return(JniEnvironment.InstanceMethods.CallCharMethod(self, charValue));
     } finally {
         JniObjectReference.Dispose(ref self, transfer);
     }
 }
 internal static Boolean GetValueFromJni(ref JniObjectReference self, JniObjectReferenceOptions transfer, Type targetType)
 {
     Debug.Assert(targetType == null || targetType == typeof(Boolean), "Expected targetType==typeof(Boolean); was: " + targetType);
     TypeRef.GetCachedInstanceMethod(ref booleanValue, "booleanValue", "()Z");
     try {
         return(JniEnvironment.InstanceMethods.CallBooleanMethod(self, booleanValue));
     } finally {
         JniObjectReference.Dispose(ref self, transfer);
     }
 }
 internal static Single GetValueFromJni(ref JniObjectReference self, JniObjectReferenceOptions transfer, Type targetType)
 {
     Debug.Assert(targetType == null || targetType == typeof(Single), "Expected targetType==typeof(Single); was: " + targetType);
     TypeRef.GetCachedInstanceMethod(ref floatValue, "floatValue", "()F");
     try {
         return(JniEnvironment.InstanceMethods.CallFloatMethod(self, floatValue));
     } finally {
         JniObjectReference.Dispose(ref self, transfer);
     }
 }
        internal static void Collect()
        {
            var runtime = JavaLangRuntime.GetRuntime();

            try {
                JavaLangRuntime.GC(runtime);
            } finally {
                JniObjectReference.Dispose(ref runtime);
            }
        }
Exemple #15
0
            public static string GetJniTypeNameFromInstance(JniObjectReference instance)
            {
                var lref = GetObjectClass(instance);

                try {
                    return(GetJniTypeNameFromClass(lref));
                }
                finally {
                    JniObjectReference.Dispose(ref lref, JniObjectReferenceOptions.CopyAndDispose);
                }
            }
Exemple #16
0
 void Initialize(ref JniObjectReference peerReference, JniObjectReferenceOptions transfer)
 {
     if (!peerReference.IsValid)
     {
         throw new ArgumentException("handle must be valid.", nameof(peerReference));
     }
     try {
         this.peerReference = peerReference.NewGlobalRef();
     } finally {
         JniObjectReference.Dispose(ref peerReference, transfer);
     }
 }
        /// <summary>
        ///   Try to garbage collect <paramref name="value"/>.
        /// </summary>
        /// <returns>
        ///   <c>true</c>, if <paramref name="value"/> was collected and
        ///   <paramref name="handle"/> is invalid; otherwise <c>false</c>.
        /// </returns>
        /// <param name="value">
        ///   The <see cref="T:Java.Interop.IJavaPeerable"/> instance to collect.
        /// </param>
        /// <param name="handle">
        ///   The <see cref="T:Java.Interop.JniObjectReference"/> of <paramref name="value"/>.
        ///   This value may be updated, and <see cref="P:Java.Interop.IJavaObject.PeerReference"/>
        ///   will be updated with this value.
        /// </param>
        internal protected virtual bool TryGC(IJavaPeerable value, ref JniObjectReference handle)
        {
            if (!handle.IsValid)
            {
                return(true);
            }
            var wgref = handle.NewWeakGlobalRef();

            JniObjectReference.Dispose(ref handle);
            JniGC.Collect();
            handle = wgref.NewGlobalRef();
            JniObjectReference.Dispose(ref wgref);
            return(!handle.IsValid);
        }
Exemple #18
0
        public override void DestroyGenericArgumentState(object value, ref JniValueMarshalerState state, ParameterAttributes synchronize)
        {
            var vm = state.Extra as JniValueMarshaler;

            if (vm != null)
            {
                vm.DestroyArgumentState(value, ref state, synchronize);
                return;
            }
            var r = state.ReferenceValue;

            JniObjectReference.Dispose(ref r);
            state = new JniValueMarshalerState();
        }
Exemple #19
0
 public void Dispose()
 {
     if (!PeerReference.IsValid)
     {
         return;
     }
     if (registered)
     {
         JniEnvironment.Runtime.UnTrack(PeerReference.Handle);
     }
     if (methods != null)
     {
         UnregisterNativeMethods();
     }
     JniObjectReference.Dispose(ref peerReference);
 }
Exemple #20
0
        public unsafe JavaException(string message, Exception innerException)
            : base(message, innerException)
        {
            const string signature      = "(Ljava/lang/String;)V";
            var          native_message = JniEnvironment.Strings.NewString(message);

            try {
                var args = stackalloc JniArgumentValue [1];
                args [0] = new JniArgumentValue(native_message);
                var peer = JniPeerMembers.InstanceMethods.StartCreateInstance(signature, GetType(), args);
                Construct(ref peer, JniObjectReferenceOptions.CopyAndDispose);
                JniPeerMembers.InstanceMethods.FinishCreateInstance(signature, this, args);
            } finally {
                JniObjectReference.Dispose(ref native_message, JniObjectReferenceOptions.CopyAndDispose);
            }
            javaStackTrace = _GetJavaStack(PeerReference);
        }
Exemple #21
0
        protected void SetPeerReference(ref JniObjectReference reference, JniObjectReferenceOptions options)
        {
            if (options == JniObjectReferenceOptions.None)
            {
                ((IJavaPeerable)this).SetPeerReference(new JniObjectReference());
                return;
            }

#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
            this.reference = reference;
#endif  // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
            this.handle      = reference.Handle;
            this.handle_type = reference.Type;
#endif  // FEATURE_JNIOBJECTREFERENCE_INTPTRS

            JniObjectReference.Dispose(ref reference, options);
        }
Exemple #22
0
            public T CreateValue <T> (ref JniObjectReference reference, JniObjectReferenceOptions options, Type targetType = null)
            {
                if (disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                if (!reference.IsValid)
                {
                    return(default(T));
                }

                if (targetType != null && !typeof(T).GetTypeInfo().IsAssignableFrom(targetType.GetTypeInfo()))
                {
                    throw new ArgumentException(
                              string.Format("Requested runtime '{0}' value of '{1}' is not compatible with requested compile-time type T of '{2}'.",
                                            nameof(targetType),
                                            targetType,
                                            typeof(T)),
                              nameof(targetType));
                }

                var boxed = PeekBoxedObject(reference);

                if (boxed != null)
                {
                    JniObjectReference.Dispose(ref reference, options);
                    return((T)Convert.ChangeType(boxed, targetType ?? typeof(T)));
                }

                targetType = targetType ?? typeof(T);

                if (typeof(IJavaPeerable).GetTypeInfo().IsAssignableFrom(targetType.GetTypeInfo()))
                {
                    return((T)JavaPeerableValueMarshaler.Instance.CreateGenericValue(ref reference, options, targetType));
                }

                var marshaler = GetValueMarshaler <T> ();

                return(marshaler.CreateGenericValue(ref reference, options, targetType));
            }
        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;
            }

            RemovePeer(value);
            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.SetPeerReference(new JniObjectReference());
            JniObjectReference.Dispose(ref h);
            value.Finalized();
        }
Exemple #24
0
        static IntPtr ToString(IntPtr jnienv, IntPtr n_self)
        {
            var envp = new JniTransition(jnienv);

            try {
                var self = (JavaProxyObject?)JniEnvironment.Runtime.ValueManager.PeekPeer(new JniObjectReference(n_self));
                var s    = self?.ToString();
                var r    = JniEnvironment.Strings.NewString(s);
                try {
                    return(JniEnvironment.References.NewReturnToJniRef(r));
                } finally {
                    JniObjectReference.Dispose(ref r);
                }
            }
            catch (Exception e) when(JniEnvironment.Runtime.ExceptionShouldTransitionToJni(e))
            {
                envp.SetPendingException(e);
                return(IntPtr.Zero);
            }
            finally {
                envp.Dispose();
            }
        }
Exemple #25
0
            public static unsafe JniObjectReference FindClass(string classname)
            {
                if (classname == null)
                {
                    throw new ArgumentNullException("classname");
                }
                if (classname.Length == 0)
                {
                    throw new ArgumentException("'classname' cannot be a zero-length string.", nameof(classname));
                }

                var info = JniEnvironment.CurrentInfo;

#if FEATURE_JNIENVIRONMENT_JI_PINVOKES
                IntPtr thrown;
                var    c = NativeMethods.java_interop_jnienv_find_class(info.EnvironmentPointer, out thrown, classname);
                if (thrown == IntPtr.Zero)
                {
                    var r = new JniObjectReference(c, JniObjectReferenceType.Local);
                    JniEnvironment.LogCreateLocalRef(r);
                    return(r);
                }
                NativeMethods.java_interop_jnienv_exception_clear(info.EnvironmentPointer);
                var e = new JniObjectReference(thrown, JniObjectReferenceType.Local);
                LogCreateLocalRef(e);

                var java   = info.ToJavaName(classname);
                var __args = stackalloc JniArgumentValue [1];
                __args [0] = new JniArgumentValue(java);

                IntPtr ignoreThrown;
                c = NativeMethods.java_interop_jnienv_call_object_method_a(info.EnvironmentPointer, out ignoreThrown, info.Runtime.ClassLoader.Handle, info.Runtime.ClassLoader_LoadClass.ID, (IntPtr)__args);
                JniObjectReference.Dispose(ref java);
                if (ignoreThrown == IntPtr.Zero)
                {
                    JniObjectReference.Dispose(ref e);
                    var r = new JniObjectReference(c, JniObjectReferenceType.Local);
                    JniEnvironment.LogCreateLocalRef(r);
                    return(r);
                }
                NativeMethods.java_interop_jnienv_exception_clear(info.EnvironmentPointer);
                NativeMethods.java_interop_jnienv_delete_local_ref(info.EnvironmentPointer, ignoreThrown);
                throw info.Runtime.GetExceptionForThrowable(ref e, JniObjectReferenceOptions.CopyAndDispose);
#endif  // !FEATURE_JNIENVIRONMENT_JI_PINVOKES
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
                var c      = info.Invoker.FindClass(info.EnvironmentPointer, classname);
                var thrown = info.Invoker.ExceptionOccurred(info.EnvironmentPointer);
                if (thrown.IsInvalid)
                {
                    JniEnvironment.LogCreateLocalRef(c);
                    return(new JniObjectReference(c, JniObjectReferenceType.Local));
                }
                info.Invoker.ExceptionClear(info.EnvironmentPointer);
                LogCreateLocalRef(thrown);

                var java   = info.ToJavaName(classname);
                var __args = stackalloc JniArgumentValue [1];
                __args [0] = new JniArgumentValue(java);

                c = info.Invoker.CallObjectMethodA(info.EnvironmentPointer, info.Runtime.ClassLoader.SafeHandle, info.Runtime.ClassLoader_LoadClass.ID, __args);
                JniObjectReference.Dispose(ref java);
                var ignoreThrown = info.Invoker.ExceptionOccurred(info.EnvironmentPointer);
                if (ignoreThrown.IsInvalid)
                {
                    thrown.Dispose();
                    JniEnvironment.LogCreateLocalRef(c);
                    return(new JniObjectReference(c, JniObjectReferenceType.Local));
                }
                info.Invoker.ExceptionClear(info.EnvironmentPointer);
                LogCreateLocalRef(ignoreThrown);
                ignoreThrown.Dispose();
                var e = new JniObjectReference(thrown, JniObjectReferenceType.Local);
                throw info.Runtime.GetExceptionForThrowable(ref e, JniObjectReferenceOptions.CopyAndDispose);
#endif  // !FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
            }
Exemple #26
0
            public static unsafe JniObjectReference FindClass(string classname)
            {
                if (classname == null)
                {
                    throw new ArgumentNullException(nameof(classname));
                }
                if (classname.Length == 0)
                {
                    throw new ArgumentException("'classname' cannot be a zero-length string.", nameof(classname));
                }

                var info = JniEnvironment.CurrentInfo;

#if FEATURE_JNIENVIRONMENT_JI_PINVOKES
                IntPtr thrown;
                var    c = NativeMethods.java_interop_jnienv_find_class(info.EnvironmentPointer, out thrown, classname);
                if (thrown == IntPtr.Zero)
                {
                    var r = new JniObjectReference(c, JniObjectReferenceType.Local);
                    JniEnvironment.LogCreateLocalRef(r);
                    return(r);
                }

                // If the Java-side exception stack trace is *lost* a'la 89a5a229,
                // change `false` to `true` and rebuild+re-run.
#if false
                NativeMethods.java_interop_jnienv_exception_describe(info.EnvironmentPointer);
#endif

                NativeMethods.java_interop_jnienv_exception_clear(info.EnvironmentPointer);

                var findClassThrown = new JniObjectReference(thrown, JniObjectReferenceType.Local);
                LogCreateLocalRef(findClassThrown);
                var pendingException = info.Runtime.GetExceptionForThrowable(ref findClassThrown, JniObjectReferenceOptions.CopyAndDispose);

                if (info.Runtime.ClassLoader_LoadClass != null)
                {
                    var java   = info.ToJavaName(classname);
                    var __args = stackalloc JniArgumentValue [1];
                    __args [0] = new JniArgumentValue(java);

                    c = NativeMethods.java_interop_jnienv_call_object_method_a(info.EnvironmentPointer, out thrown, info.Runtime.ClassLoader.Handle, info.Runtime.ClassLoader_LoadClass.ID, (IntPtr)__args);
                    JniObjectReference.Dispose(ref java);
                    if (thrown == IntPtr.Zero)
                    {
                        (pendingException as IJavaPeerable)?.Dispose();
                        var r = new JniObjectReference(c, JniObjectReferenceType.Local);
                        JniEnvironment.LogCreateLocalRef(r);
                        return(r);
                    }
                    NativeMethods.java_interop_jnienv_exception_clear(info.EnvironmentPointer);

                    if (pendingException != null)
                    {
                        NativeMethods.java_interop_jnienv_delete_local_ref(info.EnvironmentPointer, thrown);
                    }
                    else
                    {
                        var loadClassThrown = new JniObjectReference(thrown, JniObjectReferenceType.Local);
                        LogCreateLocalRef(loadClassThrown);
                        pendingException = info.Runtime.GetExceptionForThrowable(ref loadClassThrown, JniObjectReferenceOptions.CopyAndDispose);
                    }
                }

                throw pendingException !;
#endif  // !FEATURE_JNIENVIRONMENT_JI_PINVOKES
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
                var c      = info.Invoker.FindClass(info.EnvironmentPointer, classname);
                var thrown = info.Invoker.ExceptionOccurred(info.EnvironmentPointer);
                if (thrown.IsInvalid)
                {
                    JniEnvironment.LogCreateLocalRef(c);
                    return(new JniObjectReference(c, JniObjectReferenceType.Local));
                }
                info.Invoker.ExceptionClear(info.EnvironmentPointer);
                var findClassThrown = new JniObjectReference(thrown, JniObjectReferenceType.Local);
                LogCreateLocalRef(findClassThrown);
                var pendingException = info.Runtime.GetExceptionForThrowable(ref findClassThrown, JniObjectReferenceOptions.CopyAndDispose);

                var java   = info.ToJavaName(classname);
                var __args = stackalloc JniArgumentValue [1];
                __args [0] = new JniArgumentValue(java);

                c = info.Invoker.CallObjectMethodA(info.EnvironmentPointer, info.Runtime.ClassLoader.SafeHandle, info.Runtime.ClassLoader_LoadClass.ID, __args);
                JniObjectReference.Dispose(ref java);
                thrown = info.Invoker.ExceptionOccurred(info.EnvironmentPointer);
                if (ignoreThrown.IsInvalid)
                {
                    (pendingException as IJavaPeerable)?.Dispose();
                    var r = new JniObjectReference(c, JniObjectReferenceType.Local);
                    JniEnvironment.LogCreateLocalRef(r);
                    return(r);
                }
                info.Invoker.ExceptionClear(info.EnvironmentPointer);
                if (pendingException != null)
                {
                    thrown.Dispose();
                    throw pendingException;
                }
                var loadClassThrown = new JniObjectReference(thrown, JniObjectReferenceType.Local);
                LogCreateLocalRef(loadClassThrown);
                pendingException = info.Runtime.GetExceptionForThrowable(ref loadClassThrown, JniObjectReferenceOptions.CopyAndDispose);
                throw pendingException !;
#endif  // !FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
            }
        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));
            }
        }