File: src\System\Runtime\InteropServices\Java\JavaMarshal.CoreCLR.cs
Web Access
Project: src\src\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
 
namespace System.Runtime.InteropServices.Java
{
    /// <summary>
    /// Provides helpers to create and manage GC handles used for tracking references
    /// between the managed runtime and a Java VM.
    /// </summary>
    /// <remarks>
    /// The APIs provided by this type allow managed objects to be referenced from native
    /// Java code so the runtime can participate in cross-reference processing and
    /// correctly control object lifetime across the managed/native boundary.
    /// </remarks>
    [CLSCompliant(false)]
    [SupportedOSPlatform("android")]
    public static partial class JavaMarshal
    {
        /// <summary>
        /// Initializes the Java marshal subsystem with a callback used when the runtime
        /// needs to mark managed objects that are referenced from Java during cross-
        /// reference processing.
        /// </summary>
        /// <param name="markCrossReferences">A pointer to an unmanaged callback that
        /// will be invoked to enumerate or mark managed objects referenced from Java
        /// during a cross-reference sweep. The callback is expected to accept a
        /// <see cref="MarkCrossReferencesArgs"/> pointer describing the objects to mark.</param>
        /// <exception cref="ArgumentNullException"><paramref name="markCrossReferences"/> is null.</exception>
        /// <exception cref="InvalidOperationException">The subsystem cannot be initialized or is reinitialized.</exception>
        /// <exception cref="PlatformNotSupportedException">The runtime or platform does not support Java cross-reference marshalling.</exception>
        /// <remarks>
        /// Only a single initialization is supported for the process. The runtime
        /// stores the provided function pointer and will invoke it from internal
        /// runtime code when cross-reference marking is required.
        /// Additionally, this callback must be implemented in unmanaged code.
        /// </remarks>
        public static unsafe void Initialize(delegate* unmanaged<MarkCrossReferencesArgs*, void> markCrossReferences)
        {
            ArgumentNullException.ThrowIfNull(markCrossReferences);
 
            if (!InitializeInternal((IntPtr)markCrossReferences))
            {
                throw new InvalidOperationException(SR.InvalidOperation_ReinitializeJavaMarshal);
            }
        }
 
        /// <summary>
        /// Creates a GC handle that native Java code can hold to reference a managed
        /// object. The handle prevents the object from being reclaimed while the
        /// native side holds the reference, and an opaque <paramref name="context"/>
        /// value can be associated with the handle for later retrieval.
        /// </summary>
        /// <param name="obj">The managed object to be referenced from native code.</param>
        /// <param name="context">An opaque pointer-sized value that will be associated
        /// with the handle and can be retrieved by the runtime via <see cref="GetContext(GCHandle)"/>.
        /// Callers can use this to store native-side state or identifiers alongside
        /// the handle.</param>
        /// <returns>A <see cref="GCHandle"/> that represents the allocated reference-tracking handle.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="obj"/> is null.</exception>
        /// <exception cref="PlatformNotSupportedException">The runtime or platform does not support Java cross-reference marshalling.</exception>
        public static unsafe GCHandle CreateReferenceTrackingHandle(object obj, void* context)
        {
            ArgumentNullException.ThrowIfNull(obj);
 
            IntPtr handle = CreateReferenceTrackingHandleInternal(ObjectHandleOnStack.Create(ref obj), context);
            return GCHandle.FromIntPtr(handle);
        }
 
        /// <summary>
        /// Retrieves the opaque context pointer associated with a reference-tracking
        /// GC handle previously created using <see cref="CreateReferenceTrackingHandle(object, void*)"/>.
        /// </summary>
        /// <param name="obj">The <see cref="GCHandle"/> whose context should be returned.</param>
        /// <returns>The opaque context pointer associated with the handle.</returns>
        /// <exception cref="InvalidOperationException">The provided handle is null or does not represent a reference-tracking handle.</exception>
        /// <exception cref="PlatformNotSupportedException">The runtime or platform does not support Java cross-reference marshalling.</exception>
        /// <remarks>
        /// The returned pointer is the exact value that was originally provided as
        /// the context parameter when the handle was created.
        /// </remarks>
        public static unsafe void* GetContext(GCHandle obj)
        {
            IntPtr handle = GCHandle.ToIntPtr(obj);
            if (handle == IntPtr.Zero
                || !GetContextInternal(handle, out void* context))
            {
                throw new InvalidOperationException(SR.InvalidOperation_IncorrectGCHandleType);
            }
 
            return context;
        }
 
        /// <summary>
        /// Completes processing of cross references after the runtime has invoked the
        /// callback provided to <see cref="Initialize" />. This notifies the runtime of
        /// handles that are no longer reachable from native Java code so the runtime
        /// can release or update them accordingly.
        /// </summary>
        /// <param name="crossReferences">A pointer to the structure containing cross-reference information produced during marking.</param>
        /// <param name="unreachableObjectHandles">A span of <see cref="GCHandle"/> values that were determined to be unreachable from the native side.</param>
        /// <exception cref="PlatformNotSupportedException">The runtime or platform does not support Java cross-reference marshalling.</exception>
        public static unsafe void FinishCrossReferenceProcessing(
            MarkCrossReferencesArgs* crossReferences,
            ReadOnlySpan<GCHandle> unreachableObjectHandles)
        {
            fixed (GCHandle* pHandles = unreachableObjectHandles)
            {
                FinishCrossReferenceProcessing(
                    crossReferences,
                    (nuint)unreachableObjectHandles.Length,
                    pHandles);
            }
        }
 
        [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_Initialize")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static partial bool InitializeInternal(IntPtr callback);
 
        [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_CreateReferenceTrackingHandle")]
        private static unsafe partial IntPtr CreateReferenceTrackingHandleInternal(ObjectHandleOnStack obj, void* context);
 
        [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_FinishCrossReferenceProcessing")]
        private static unsafe partial void FinishCrossReferenceProcessing(MarkCrossReferencesArgs* crossReferences, nuint length, void* unreachableObjectHandles);
 
        [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "JavaMarshal_GetContext")]
        [SuppressGCTransition]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static unsafe partial bool GetContextInternal(IntPtr handle, out void* context);
    }
}