File: src\System\Reflection\LoaderAllocator.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.InteropServices;
 
namespace System.Reflection
{
    //
    // We can destroy the unmanaged part of collectible type only after the managed part is definitely gone and thus
    // nobody can call/allocate/reference anything related to the collectible assembly anymore. A call to finalizer
    // alone does not guarantee that the managed part is gone. A malicious code can keep a reference to some object
    // in a way that it survives finalization, or we can be running during shutdown where everything is finalized.
    //
    // The unmanaged LoaderAllocator keeps a reference to the managed LoaderAllocator in long weak handle. If the long
    // weak handle is null, we can be sure that the managed part of the LoaderAllocator is definitely gone and that it
    // is safe to destroy the unmanaged part. Unfortunately, we can not perform the above check in a finalizer on the
    // LoaderAllocator, but it can be performed on a helper object.
    //
    // The finalization does not have to be done using CriticalFinalizerObject. We have to go over all LoaderAllocators
    // during AppDomain shutdown anyway to avoid leaks e.g. if somebody stores reference to LoaderAllocator in a static.
    //
    internal sealed partial class LoaderAllocatorScout
    {
        // This field is set by the VM to atomically transfer the ownership to the managed loader allocator
        internal IntPtr m_nativeLoaderAllocator;
 
        [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "LoaderAllocator_Destroy")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static partial bool Destroy(IntPtr nativeLoaderAllocator);
 
        ~LoaderAllocatorScout()
        {
            if (m_nativeLoaderAllocator == IntPtr.Zero)
                return;
 
            // Destroy returns false if the managed LoaderAllocator is still alive.
            if (!Destroy(m_nativeLoaderAllocator))
            {
                // Somebody might have been holding a reference on us via weak handle.
                // We will keep trying. It will be hopefully released eventually.
                GC.ReRegisterForFinalize(this);
            }
        }
    }
 
    internal sealed class LoaderAllocator
    {
        private LoaderAllocator()
        {
            m_slots = new object[5];
            // m_slotsUsed = 0;
 
            m_scout = new LoaderAllocatorScout();
        }
 
#pragma warning disable CA1823, 414, 169
        private LoaderAllocatorScout m_scout;
        private object[] m_slots;
        internal CerHashtable<RuntimeMethodInfo, RuntimeMethodInfo> m_methodInstantiations;
        private int m_slotsUsed;
#pragma warning restore CA1823, 414, 169
    }
}