From 59e0f4f8a37b2c779bc3551651388a209fd0a06b Mon Sep 17 00:00:00 2001
From: Aaron R Robinson <arobins@microsoft.com>
Date: Sun, 21 Apr 2024 10:11:46 -0700
Subject: [PATCH 1/6] Simplify managed MetadataImport creation

Consolidate the create mechanism for the managed
MetadataImport type. This also removes some
Helper Method Frame usage.
---
 .../src/System/Reflection/MdImport.cs         | 16 ++++++++--
 .../src/System/RuntimeHandles.cs              | 10 ++-----
 src/coreclr/vm/ecalllist.h                    |  3 +-
 src/coreclr/vm/managedmdimport.cpp            | 10 +++++++
 src/coreclr/vm/managedmdimport.hpp            |  1 +
 src/coreclr/vm/runtimehandles.cpp             | 29 -------------------
 src/coreclr/vm/runtimehandles.h               | 10 +------
 7 files changed, 28 insertions(+), 51 deletions(-)

diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
index febf1a5055568f..f821181b1fbc30 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
@@ -207,7 +207,7 @@ internal readonly partial struct MetadataImport
         private readonly IntPtr m_metadataImport2;
         private readonly object? m_keepalive;
 
-        internal static MetadataImport EmptyImport => new MetadataImport(IntPtr.Zero, null);
+        internal static MetadataImport EmptyImport => new MetadataImport();
 
         #region Override methods from Object
         public override int GetHashCode()
@@ -304,9 +304,19 @@ internal static unsafe MarshalAsAttribute GetMarshalAs(ConstArray nativeType, Ru
         #endregion
 
         #region Constructor
-        internal MetadataImport(IntPtr metadataImport2, object? keepalive)
+        public MetadataImport()
         {
-            m_metadataImport2 = metadataImport2;
+            m_metadataImport2 = IntPtr.Zero;
+            m_keepalive = null;
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern unsafe IntPtr GetMetadataImport(RuntimeModule module);
+
+        internal MetadataImport(RuntimeModule module, object keepalive)
+        {
+            ArgumentNullException.ThrowIfNull(module);
+            m_metadataImport2 = GetMetadataImport(module);
             m_keepalive = keepalive;
         }
         #endregion
diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
index 001a9fcdfee6a8..08a25b3ab4b4f4 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
@@ -650,12 +650,9 @@ internal static bool SatisfiesConstraints(RuntimeType paramType, RuntimeType[]?
             }
         }
 
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern IntPtr _GetMetadataImport(RuntimeType type);
-
         internal static MetadataImport GetMetadataImport(RuntimeType type)
         {
-            return new MetadataImport(_GetMetadataImport(type), type);
+            return new MetadataImport(type.GetRuntimeModule(), type);
         }
 
         [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_RegisterCollectibleTypeDependency")]
@@ -1486,12 +1483,9 @@ internal static void GetPEKind(RuntimeModule module, out PortableExecutableKinds
 
         public int MDStreamVersion => GetMDStreamVersion(GetRuntimeModule());
 
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern IntPtr _GetMetadataImport(RuntimeModule module);
-
         internal static MetadataImport GetMetadataImport(RuntimeModule module)
         {
-            return new MetadataImport(_GetMetadataImport(module), module);
+            return new MetadataImport(module, module);
         }
         #endregion
     }
diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h
index 5406bc85c7a1c3..98a38b8603419c 100644
--- a/src/coreclr/vm/ecalllist.h
+++ b/src/coreclr/vm/ecalllist.h
@@ -137,7 +137,6 @@ FCFuncStart(gCOMTypeHandleFuncs)
     FCFuncElement("GetFields", RuntimeTypeHandle::GetFields)
     FCFuncElement("GetInterfaces", RuntimeTypeHandle::GetInterfaces)
     FCFuncElement("GetAttributes", RuntimeTypeHandle::GetAttributes)
-    FCFuncElement("_GetMetadataImport", RuntimeTypeHandle::GetMetadataImport)
     FCFuncElement("GetNumVirtuals", RuntimeTypeHandle::GetNumVirtuals)
     FCFuncElement("GetNumVirtualsAndStaticVirtuals", RuntimeTypeHandle::GetNumVirtualsAndStaticVirtuals)
     FCFuncElement("CanCastTo", RuntimeTypeHandle::CanCastTo)
@@ -156,6 +155,7 @@ FCFuncStart(gCOMTypeHandleFuncs)
 FCFuncEnd()
 
 FCFuncStart(gMetaDataImport)
+    FCFuncElement("GetMetadataImport", MetaDataImport::GetMetadataImport)
     FCFuncElement("GetDefaultValue", MetaDataImport::GetDefaultValue)
     FCFuncElement("GetName", MetaDataImport::GetName)
     FCFuncElement("GetUserString", MetaDataImport::GetUserString)
@@ -236,7 +236,6 @@ FCFuncEnd()
 FCFuncStart(gCOMModuleHandleFuncs)
     FCFuncElement("GetToken", ModuleHandle::GetToken)
     FCFuncElement("GetDynamicMethod", ModuleHandle::GetDynamicMethod)
-    FCFuncElement("_GetMetadataImport", ModuleHandle::GetMetadataImport)
     FCFuncElement("GetMDStreamVersion", ModuleHandle::GetMDStreamVersion)
 FCFuncEnd()
 
diff --git a/src/coreclr/vm/managedmdimport.cpp b/src/coreclr/vm/managedmdimport.cpp
index 200a330df62c67..8ab00a85f5320c 100644
--- a/src/coreclr/vm/managedmdimport.cpp
+++ b/src/coreclr/vm/managedmdimport.cpp
@@ -67,6 +67,16 @@ FCIMPL11(FC_BOOL_RET, MetaDataImport::GetMarshalAs,
 }
 FCIMPLEND
 
+FCIMPL1(IMDInternalImport*, MetaDataImport::GetMetadataImport, ReflectModuleBaseObject * pModuleUNSAFE)
+{
+    FCALL_CONTRACT;
+
+    REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE);
+    Module *pModule = refModule->GetModule();
+    return pModule->GetMDImport();
+}
+FCIMPLEND
+
 FCIMPL6(HRESULT, MetaDataImport::GetDefaultValue, IMDInternalImport* pScope, mdToken tk, INT64* pDefaultValue, LPCWSTR* pStringValue, INT32* pLength, INT32* pCorElementType)
 {
     FCALL_CONTRACT;
diff --git a/src/coreclr/vm/managedmdimport.hpp b/src/coreclr/vm/managedmdimport.hpp
index 817c5fa426a4c5..4db05291d6fd0b 100644
--- a/src/coreclr/vm/managedmdimport.hpp
+++ b/src/coreclr/vm/managedmdimport.hpp
@@ -27,6 +27,7 @@ typedef struct
 class MetaDataImport
 {
 public:
+    static FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectModuleBaseObject* pModuleUNSAFE);
     static FCDECL2(HRESULT, GetScopeProps, IMDInternalImport* pScope, GUID* pmvid);
     static FCDECL3(HRESULT, GetMemberRefProps, IMDInternalImport* pScope, mdMemberRef mr, ConstArray* ppvSigBlob);
 
diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp
index 4598f4d1e49a4b..c660763f11577b 100644
--- a/src/coreclr/vm/runtimehandles.cpp
+++ b/src/coreclr/vm/runtimehandles.cpp
@@ -1488,21 +1488,6 @@ FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::ContainsGenericVariables, PTR_ReflectCla
 }
 FCIMPLEND
 
-FCIMPL1(IMDInternalImport*, RuntimeTypeHandle::GetMetadataImport, ReflectClassBaseObject * pTypeUNSAFE)
-{
-    FCALL_CONTRACT;
-
-    REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
-
-    if (refType == NULL)
-        FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
-
-    Module *pModule = refType->GetType().GetModule();
-
-    return pModule->GetMDImport();
-}
-FCIMPLEND
-
 extern "C" void* QCALLTYPE RuntimeTypeHandle_AllocateTypeAssociatedMemory(QCall::TypeHandle type, uint32_t size)
 {
     QCALL_CONTRACT;
@@ -2790,20 +2775,6 @@ FCIMPL1(INT32, ModuleHandle::GetToken, ReflectModuleBaseObject * pModuleUNSAFE)
 }
 FCIMPLEND
 
-FCIMPL1(IMDInternalImport*, ModuleHandle::GetMetadataImport, ReflectModuleBaseObject * pModuleUNSAFE)
-{
-    FCALL_CONTRACT;
-
-    REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE);
-
-    if (refModule == NULL)
-        FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
-
-    Module *pModule = refModule->GetModule();
-    return pModule->GetMDImport();
-}
-FCIMPLEND
-
 extern "C" void QCALLTYPE ModuleHandle_ResolveType(QCall::ModuleHandle pModule, INT32 tkType, TypeHandle *typeArgs, INT32 typeArgsCount, TypeHandle *methodArgs, INT32 methodArgsCount, QCall::ObjectHandleOnStack retType)
 {
     QCALL_CONTRACT;
diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h
index 6b0d995977c654..56bb2df245f9f7 100644
--- a/src/coreclr/vm/runtimehandles.h
+++ b/src/coreclr/vm/runtimehandles.h
@@ -163,8 +163,6 @@ class RuntimeTypeHandle {
     static FCDECL1(MethodDesc *, GetFirstIntroducedMethod, ReflectClassBaseObject* pType);
     static FCDECL1(void, GetNextIntroducedMethod, MethodDesc **ppMethod);
 
-    static FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectClassBaseObject * pModuleUNSAFE);
-
     // Helper methods not called by managed code
 
     static void ValidateTypeAbleToBeInstantiated(TypeHandle typeHandle, bool fGetUninitializedObject);
@@ -316,13 +314,7 @@ class ModuleHandle {
 public:
     static FCDECL5(ReflectMethodObject*, GetDynamicMethod, ReflectMethodObject *pMethodUNSAFE, ReflectModuleBaseObject *pModuleUNSAFE, StringObject *name, U1Array *sig, Object *resolver);
     static FCDECL1(INT32, GetToken, ReflectModuleBaseObject *pModuleUNSAFE);
-
-    static
-    FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectModuleBaseObject * pModuleUNSAFE);
-
-    static
-    FCDECL1(INT32, GetMDStreamVersion, ReflectModuleBaseObject * pModuleUNSAFE);
-
+    static FCDECL1(INT32, GetMDStreamVersion, ReflectModuleBaseObject * pModuleUNSAFE);
 };
 
 extern "C" void QCALLTYPE ModuleHandle_GetModuleType(QCall::ModuleHandle pModule, QCall::ObjectHandleOnStack retType);

From 59fb7c8c8551b5627ab11b733d1ff48f7ea7789d Mon Sep 17 00:00:00 2001
From: Aaron R Robinson <arobins@microsoft.com>
Date: Sun, 21 Apr 2024 17:40:02 -0700
Subject: [PATCH 2/6] Remove MetadataImport.EmptyImport

---
 .../src/System/Reflection/MdImport.cs                     | 8 --------
 .../src/System/Reflection/RuntimeParameterInfo.cs         | 8 ++++----
 2 files changed, 4 insertions(+), 12 deletions(-)

diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
index f821181b1fbc30..73a1aca0c04586 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
@@ -207,8 +207,6 @@ internal readonly partial struct MetadataImport
         private readonly IntPtr m_metadataImport2;
         private readonly object? m_keepalive;
 
-        internal static MetadataImport EmptyImport => new MetadataImport();
-
         #region Override methods from Object
         public override int GetHashCode()
         {
@@ -304,12 +302,6 @@ internal static unsafe MarshalAsAttribute GetMarshalAs(ConstArray nativeType, Ru
         #endregion
 
         #region Constructor
-        public MetadataImport()
-        {
-            m_metadataImport2 = IntPtr.Zero;
-            m_keepalive = null;
-        }
-
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern unsafe IntPtr GetMetadataImport(RuntimeModule module);
 
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs
index 5af77b790f49c3..96fca0c411cf83 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs
@@ -86,7 +86,7 @@ private static ParameterInfo[] GetParameters(
             // Fill in empty ParameterInfos for those without tokens
             if (fetchReturnParameter)
             {
-                returnParameter ??= new RuntimeParameterInfo(sig, MetadataImport.EmptyImport, 0, -1, (ParameterAttributes)0, member);
+                returnParameter ??= new RuntimeParameterInfo(sig, default, 0, -1, (ParameterAttributes)0, member);
             }
             else
             {
@@ -97,7 +97,7 @@ private static ParameterInfo[] GetParameters(
                         if (args[i] != null)
                             continue;
 
-                        args[i] = new RuntimeParameterInfo(sig, MetadataImport.EmptyImport, 0, i, (ParameterAttributes)0, member);
+                        args[i] = new RuntimeParameterInfo(sig, default, 0, i, (ParameterAttributes)0, member);
                     }
                 }
             }
@@ -176,7 +176,7 @@ private RuntimeParameterInfo(
             int position, ParameterAttributes attributes, MemberInfo member)
         {
             Debug.Assert(member != null);
-            Debug.Assert(MdToken.IsNullToken(tkParamDef) == scope.Equals(MetadataImport.EmptyImport));
+            Debug.Assert(MdToken.IsNullToken(tkParamDef) == scope.Equals(default));
             Debug.Assert(MdToken.IsNullToken(tkParamDef) || MdToken.IsTokenOfType(tkParamDef, MetadataTokenType.ParamDef));
 
             PositionImpl = position;
@@ -201,7 +201,7 @@ internal RuntimeParameterInfo(MethodInfo owner, string? name, Type parameterType
             PositionImpl = position;
             AttrsImpl = ParameterAttributes.None;
             m_tkParamDef = (int)MetadataTokenType.ParamDef;
-            m_scope = MetadataImport.EmptyImport;
+            m_scope = default;
         }
         #endregion
 

From 004b6915c2f76978d02c2aa41b12af8e48b2a2f3 Mon Sep 17 00:00:00 2001
From: Aaron R Robinson <arobins@microsoft.com>
Date: Sun, 21 Apr 2024 21:21:01 -0700
Subject: [PATCH 3/6] Cast default appropriately.

---
 .../src/System/Reflection/RuntimeParameterInfo.cs               | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs
index 96fca0c411cf83..cba87d7184752d 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs
@@ -176,7 +176,7 @@ private RuntimeParameterInfo(
             int position, ParameterAttributes attributes, MemberInfo member)
         {
             Debug.Assert(member != null);
-            Debug.Assert(MdToken.IsNullToken(tkParamDef) == scope.Equals(default));
+            Debug.Assert(MdToken.IsNullToken(tkParamDef) == scope.Equals((MetadataImport)default));
             Debug.Assert(MdToken.IsNullToken(tkParamDef) || MdToken.IsTokenOfType(tkParamDef, MetadataTokenType.ParamDef));
 
             PositionImpl = position;

From 776ac98f18456898da39e163b228272d791058e7 Mon Sep 17 00:00:00 2001
From: Aaron R Robinson <arobins@microsoft.com>
Date: Mon, 22 Apr 2024 16:13:13 -0700
Subject: [PATCH 4/6] Remove keepalive member.

---
 .../src/System/Reflection/MdImport.cs         |  9 ++---
 .../Reflection/RuntimeCustomAttributeData.cs  | 35 ++++++++++++-------
 .../src/System/Reflection/RuntimeModule.cs    | 10 ++++--
 .../System/Reflection/RuntimeParameterInfo.cs | 13 +++++--
 .../System/Reflection/RuntimePropertyInfo.cs  |  7 ++--
 .../src/System/RuntimeHandles.cs              | 19 +++-------
 .../src/System/RuntimeType.CoreCLR.cs         | 25 ++++++++-----
 src/coreclr/vm/domainassembly.cpp             |  8 ++---
 src/coreclr/vm/ecalllist.h                    |  1 -
 src/coreclr/vm/managedmdimport.cpp            | 10 ------
 src/coreclr/vm/managedmdimport.hpp            |  1 -
 src/coreclr/vm/object.h                       |  6 +++-
 12 files changed, 78 insertions(+), 66 deletions(-)

diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
index 73a1aca0c04586..69f2dfc5f2389a 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
@@ -205,7 +205,6 @@ internal readonly partial struct MetadataImport
 #pragma warning restore CA1067
     {
         private readonly IntPtr m_metadataImport2;
-        private readonly object? m_keepalive;
 
         #region Override methods from Object
         public override int GetHashCode()
@@ -302,14 +301,10 @@ internal static unsafe MarshalAsAttribute GetMarshalAs(ConstArray nativeType, Ru
         #endregion
 
         #region Constructor
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern unsafe IntPtr GetMetadataImport(RuntimeModule module);
-
-        internal MetadataImport(RuntimeModule module, object keepalive)
+        internal MetadataImport(RuntimeModule module)
         {
             ArgumentNullException.ThrowIfNull(module);
-            m_metadataImport2 = GetMetadataImport(module);
-            m_keepalive = keepalive;
+            m_metadataImport2 = module.GetMDImport();
         }
         #endregion
 
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
index fd33d68fb0758e..a80787772b0fb7 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
@@ -215,6 +215,7 @@ internal static CustomAttributeRecord[] GetCustomAttributeRecords(RuntimeModule
                 scope.GetCustomAttributeProps(tkCustomAttributeTokens[i],
                     out records[i].tkCtor.Value, out records[i].blob);
             }
+            GC.KeepAlive(module);
 
             return records;
         }
@@ -250,13 +251,13 @@ internal static CustomAttributeTypedArgument Filter(IList<CustomAttributeData> a
         private RuntimeCustomAttributeData(RuntimeModule scope, MetadataToken caCtorToken, in ConstArray blob)
         {
             m_scope = scope;
-            m_ctor = (RuntimeConstructorInfo)RuntimeType.GetMethodBase(scope, caCtorToken)!;
+            m_ctor = (RuntimeConstructorInfo)RuntimeType.GetMethodBase(m_scope, caCtorToken)!;
 
             if (m_ctor!.DeclaringType!.IsGenericType)
             {
-                MetadataImport metadataScope = scope.MetadataImport;
-                Type attributeType = scope.ResolveType(metadataScope.GetParentToken(caCtorToken), null, null)!;
-                m_ctor = (RuntimeConstructorInfo)scope.ResolveMethod(caCtorToken, attributeType.GenericTypeArguments, null)!.MethodHandle.GetMethodInfo();
+                MetadataImport metadataScope = m_scope.MetadataImport;
+                Type attributeType = m_scope.ResolveType(metadataScope.GetParentToken(caCtorToken), null, null)!;
+                m_ctor = (RuntimeConstructorInfo)m_scope.ResolveMethod(caCtorToken, attributeType.GenericTypeArguments, null)!.MethodHandle.GetMethodInfo();
             }
 
             ReadOnlySpan<ParameterInfo> parameters = m_ctor.GetParametersAsSpan();
@@ -1466,6 +1467,7 @@ private static bool IsCustomAttributeDefined(
                     }
                 }
             }
+            GC.KeepAlive(decoratedModule);
 
             return false;
         }
@@ -1615,6 +1617,7 @@ private static void AddCustomAttributes(
 
                 attributes.Add(attribute);
             }
+            GC.KeepAlive(decoratedModule);
         }
 
         [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
@@ -2194,10 +2197,11 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
             if ((method.Attributes & MethodAttributes.PinvokeImpl) == 0)
                 return null;
 
-            MetadataImport scope = ModuleHandle.GetMetadataImport(method.Module.ModuleHandle.GetRuntimeModule());
+            RuntimeModule module = method.Module.ModuleHandle.GetRuntimeModule();
+            MetadataImport scope = module.MetadataImport;
             int token = method.MetadataToken;
-
             scope.GetPInvokeMap(token, out PInvokeAttributes flags, out string entryPoint, out string dllName);
+            GC.KeepAlive(module);
 
             CharSet charSet = CharSet.None;
 
@@ -2252,7 +2256,7 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
 
         private static MarshalAsAttribute? GetMarshalAsCustomAttribute(int token, RuntimeModule scope)
         {
-            ConstArray nativeType = ModuleHandle.GetMetadataImport(scope).GetFieldMarshal(token);
+            ConstArray nativeType = scope.MetadataImport.GetFieldMarshal(token);
 
             if (nativeType.Length == 0)
                 return null;
@@ -2262,10 +2266,15 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
 
         private static FieldOffsetAttribute? GetFieldOffsetCustomAttribute(RuntimeFieldInfo field)
         {
-            if (field.DeclaringType is not null &&
-                field.GetRuntimeModule().MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out int fieldOffset))
-                return new FieldOffsetAttribute(fieldOffset);
-
+            if (field.DeclaringType is not null)
+            {
+                RuntimeModule module= field.GetRuntimeModule();
+                if (module.MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out int fieldOffset))
+                {
+                    return new FieldOffsetAttribute(fieldOffset);
+                }
+                GC.KeepAlive(module);
+            }
             return null;
         }
 
@@ -2291,7 +2300,9 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
                 case TypeAttributes.UnicodeClass: charSet = CharSet.Unicode; break;
                 default: Debug.Fail("Unreachable code"); break;
             }
-            type.GetRuntimeModule().MetadataImport.GetClassLayout(type.MetadataToken, out int pack, out int size);
+            RuntimeModule module = type.GetRuntimeModule();
+            module.MetadataImport.GetClassLayout(type.MetadataToken, out int pack, out int size);
+            GC.KeepAlive(module);
 
             StructLayoutAttribute attribute = new StructLayoutAttribute(layoutKind);
 
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs
index 8e7e4a05c73dde..df41080a1f2448 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs
@@ -18,6 +18,7 @@ internal sealed partial class RuntimeModule : Module
         private RuntimeType m_runtimeType;
         private readonly RuntimeAssembly m_runtimeAssembly;
         private readonly IntPtr m_pData;
+        private readonly IntPtr m_metadataImport2;
 #pragma warning restore CA1823, 169
         #endregion
 
@@ -202,7 +203,7 @@ public override byte[] ResolveSignature(int metadataToken)
 
                 if (declaringType.IsGenericType || declaringType.IsArray)
                 {
-                    int tkDeclaringType = ModuleHandle.GetMetadataImport(this).GetParentToken(metadataToken);
+                    int tkDeclaringType = MetadataImport.GetParentToken(metadataToken);
                     declaringType = (RuntimeType)ResolveType(tkDeclaringType, genericTypeArguments, genericMethodArguments);
                 }
 
@@ -353,7 +354,7 @@ public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFile
         #region Internal Members
         internal RuntimeType RuntimeType => m_runtimeType ??= ModuleHandle.GetModuleType(this);
 
-        internal MetadataImport MetadataImport => ModuleHandle.GetMetadataImport(this);
+        internal MetadataImport MetadataImport => new MetadataImport(this);
         #endregion
 
         #region ICustomAttributeProvider Members
@@ -529,6 +530,11 @@ internal IntPtr GetUnderlyingNativeHandle()
         {
             return m_pData;
         }
+
+        internal IntPtr GetMDImport()
+        {
+            return m_metadataImport2;
+        }
         #endregion
     }
 }
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs
index cba87d7184752d..24dd89c2113172 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs
@@ -29,6 +29,11 @@ internal static ParameterInfo GetReturnParameter(IRuntimeMethodInfo method, Memb
         private static ParameterInfo[] GetParameters(
             IRuntimeMethodInfo methodHandle, MemberInfo member, Signature sig, out ParameterInfo? returnParameter, bool fetchReturnParameter)
         {
+            // The lifetime rules for MetadataImport expect these two objects to be the same instance.
+            // See the lifetime of MetadataImport, acquired through IRuntimeMethodInfo, but extended
+            // through the MemberInfo instance.
+            Debug.Assert(ReferenceEquals(methodHandle, member));
+
             returnParameter = null;
             int sigArgCount = sig.Arguments.Length;
             ParameterInfo[] args =
@@ -43,7 +48,7 @@ private static ParameterInfo[] GetParameters(
             // are generated on the fly by the runtime.
             if (!MdToken.IsNullToken(tkMethodDef))
             {
-                MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(RuntimeMethodHandle.GetDeclaringType(methodHandle));
+                MetadataImport scope = RuntimeMethodHandle.GetDeclaringType(methodHandle).GetRuntimeModule().MetadataImport;
 
                 scope.EnumParams(tkMethodDef, out MetadataEnumResult tkParamDefs);
 
@@ -73,7 +78,7 @@ private static ParameterInfo[] GetParameters(
                     }
                     else if (!fetchReturnParameter && position >= 0)
                     {
-                        // position beyong sigArgCount?
+                        // position beyond sigArgCount?
                         if (position >= sigArgCount)
                             throw new BadImageFormatException(SR.BadImageFormat_ParameterSignatureMismatch);
 
@@ -165,7 +170,7 @@ private RuntimeParameterInfo(RuntimeParameterInfo accessor, MemberInfo member)
             PositionImpl = accessor.Position;
             AttrsImpl = accessor.Attributes;
 
-            // Strictly speeking, property's don't contain parameter tokens
+            // Strictly speaking, properties don't contain parameter tokens
             // However we need this to make ca's work... oh well...
             m_tkParamDef = MdToken.IsNullToken(accessor.MetadataToken) ? (int)MetadataTokenType.ParamDef : accessor.MetadataToken;
             m_scope = accessor.m_scope;
@@ -239,6 +244,7 @@ public override string? Name
                     if (!MdToken.IsNullToken(m_tkParamDef))
                     {
                         string name = m_scope.GetName(m_tkParamDef).ToString();
+                        GC.KeepAlive(this);
                         NameImpl = name;
                     }
 
@@ -339,6 +345,7 @@ private bool TryGetDefaultValueInternal(bool raw, out object? defaultValue)
             #region Look for a default value in metadata
             // This will return DBNull.Value if no constant value is defined on m_tkParamDef in the metadata.
             defaultValue = MdConstant.GetValue(m_scope, m_tkParamDef, ParameterType.TypeHandle, raw);
+            GC.KeepAlive(this);
 
             // If default value is not specified in metadata, look for it in custom attributes
             if (defaultValue == DBNull.Value)
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs
index 933e05d0bf7854..d49ac821e684d9 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs
@@ -35,7 +35,8 @@ internal RuntimePropertyInfo(
             Debug.Assert(reflectedTypeCache != null);
             Debug.Assert(!reflectedTypeCache.IsGlobal);
 
-            MetadataImport scope = declaredType.GetRuntimeModule().MetadataImport;
+            RuntimeModule module = declaredType.GetRuntimeModule();
+            MetadataImport scope = module.MetadataImport;
 
             m_token = tkProperty;
             m_reflectedTypeCache = reflectedTypeCache;
@@ -47,6 +48,7 @@ internal RuntimePropertyInfo(
                 out _, out _, out _,
                 out m_getterMethod, out m_setterMethod, out m_otherMethod,
                 out isPrivate, out m_bindingFlags);
+            GC.KeepAlive(module);
         }
         #endregion
 
@@ -65,9 +67,9 @@ internal Signature Signature
             {
                 if (m_signature == null)
                 {
-
                     GetRuntimeModule().MetadataImport.GetPropertyProps(
                         m_token, out _, out _, out ConstArray sig);
+                    GC.KeepAlive(this);
 
                     m_signature = new Signature(sig.Signature.ToPointer(), sig.Length, m_declaringType);
                 }
@@ -210,6 +212,7 @@ public override Type[] GetOptionalCustomModifiers()
         internal object GetConstantValue(bool raw)
         {
             object? defaultValue = MdConstant.GetValue(GetRuntimeModule().MetadataImport, m_token, PropertyType.TypeHandle, raw);
+            GC.KeepAlive(this);
 
             if (defaultValue == DBNull.Value)
                 // Arg_EnumLitValueNotFound -> "Literal value was not found."
diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
index 08a25b3ab4b4f4..380981993451e9 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
@@ -650,11 +650,6 @@ internal static bool SatisfiesConstraints(RuntimeType paramType, RuntimeType[]?
             }
         }
 
-        internal static MetadataImport GetMetadataImport(RuntimeType type)
-        {
-            return new MetadataImport(type.GetRuntimeModule(), type);
-        }
-
         [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_RegisterCollectibleTypeDependency")]
         private static partial void RegisterCollectibleTypeDependency(QCallTypeHandle type, QCallAssembly assembly);
 
@@ -1244,8 +1239,6 @@ internal ModuleHandle(RuntimeModule module)
         }
         #endregion
 
-        #region Internal FCalls
-
         internal RuntimeModule GetRuntimeModule()
         {
             return m_ptr;
@@ -1275,6 +1268,7 @@ public bool Equals(ModuleHandle handle)
 
         public static bool operator !=(ModuleHandle left, ModuleHandle right) => !left.Equals(right);
 
+        #region Internal FCalls
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern IRuntimeMethodInfo GetDynamicMethod(Reflection.Emit.DynamicMethod method, RuntimeModule module, string name, byte[] sig, Resolver resolver);
 
@@ -1333,7 +1327,7 @@ public RuntimeTypeHandle ResolveTypeHandle(int typeToken, RuntimeTypeHandle[]? t
                 }
                 catch (Exception)
                 {
-                    if (!GetMetadataImport(module).IsValidToken(typeToken))
+                    if (!module.MetadataImport.IsValidToken(typeToken))
                         throw new ArgumentOutOfRangeException(nameof(typeToken),
                             SR.Format(SR.Argument_InvalidToken, typeToken, new ModuleHandle(module)));
                     throw;
@@ -1386,7 +1380,7 @@ internal static RuntimeMethodHandleInternal ResolveMethodHandleInternal(RuntimeM
             }
             catch (Exception)
             {
-                if (!GetMetadataImport(module).IsValidToken(methodToken))
+                if (!module.MetadataImport.IsValidToken(methodToken))
                     throw new ArgumentOutOfRangeException(nameof(methodToken),
                         SR.Format(SR.Argument_InvalidToken, methodToken, new ModuleHandle(module)));
                 throw;
@@ -1439,7 +1433,7 @@ public RuntimeFieldHandle ResolveFieldHandle(int fieldToken, RuntimeTypeHandle[]
                 }
                 catch (Exception)
                 {
-                    if (!GetMetadataImport(module).IsValidToken(fieldToken))
+                    if (!module.MetadataImport.IsValidToken(fieldToken))
                         throw new ArgumentOutOfRangeException(nameof(fieldToken),
                             SR.Format(SR.Argument_InvalidToken, fieldToken, new ModuleHandle(module)));
                     throw;
@@ -1482,11 +1476,6 @@ internal static void GetPEKind(RuntimeModule module, out PortableExecutableKinds
         internal static extern int GetMDStreamVersion(RuntimeModule module);
 
         public int MDStreamVersion => GetMDStreamVersion(GetRuntimeModule());
-
-        internal static MetadataImport GetMetadataImport(RuntimeModule module)
-        {
-            return new MetadataImport(module, module);
-        }
         #endregion
     }
 
diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
index 56ff2e26850ccc..c6ea76fde9b85f 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
@@ -932,7 +932,8 @@ private void PopulateLiteralFields(Filter filter, RuntimeType declaringType, ref
                     if (MdToken.IsNullToken(tkDeclaringType))
                         return;
 
-                    MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(declaringType);
+                    RuntimeModule module = declaringType.GetRuntimeModule();
+                    MetadataImport scope = module.MetadataImport;
 
                     scope.EnumFields(tkDeclaringType, out MetadataEnumResult tkFields);
 
@@ -976,6 +977,7 @@ private void PopulateLiteralFields(Filter filter, RuntimeType declaringType, ref
                             list.Add(runtimeFieldInfo);
                         }
                     }
+                    GC.KeepAlive(module);
                 }
 
                 private void AddSpecialInterface(
@@ -1102,7 +1104,7 @@ private RuntimeType[] PopulateNestedClasses(Filter filter)
                     ListBuilder<RuntimeType> list = default;
 
                     ModuleHandle moduleHandle = new ModuleHandle(RuntimeTypeHandle.GetModule(declaringType));
-                    MetadataImport scope = ModuleHandle.GetMetadataImport(moduleHandle.GetRuntimeModule());
+                    MetadataImport scope = moduleHandle.GetRuntimeModule().MetadataImport;
 
                     scope.EnumNestedTypes(tkEnclosingType, out MetadataEnumResult tkNestedClasses);
 
@@ -1174,7 +1176,8 @@ private void PopulateEvents(
                     if (MdToken.IsNullToken(tkDeclaringType))
                         return;
 
-                    MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(declaringType);
+                    RuntimeModule module = declaringType.GetRuntimeModule();
+                    MetadataImport scope = module.MetadataImport;
 
                     scope.EnumEvents(tkDeclaringType, out MetadataEnumResult tkEvents);
 
@@ -1220,6 +1223,7 @@ private void PopulateEvents(
 
                         list.Add(eventInfo);
                     }
+                    GC.KeepAlive(module);
                 }
 
                 private RuntimePropertyInfo[] PopulateProperties(Filter filter)
@@ -1286,7 +1290,8 @@ private void PopulateProperties(
                     if (MdToken.IsNullToken(tkDeclaringType))
                         return;
 
-                    MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(declaringType);
+                    RuntimeModule module = declaringType.GetRuntimeModule();
+                    MetadataImport scope = module.MetadataImport;
 
                     scope.EnumProperties(tkDeclaringType, out MetadataEnumResult tkProperties);
 
@@ -1304,7 +1309,7 @@ private void PopulateProperties(
 
                         if (filter.RequiresStringComparison())
                         {
-                            MdUtf8String name = declaringType.GetRuntimeModule().MetadataImport.GetName(tkProperty);
+                            MdUtf8String name = scope.GetName(tkProperty);
 
                             if (!filter.Match(name))
                                 continue;
@@ -1399,6 +1404,7 @@ private void PopulateProperties(
 
                         list.Add(propertyInfo);
                     }
+                    GC.KeepAlive(module);
                 }
                 #endregion
 
@@ -1571,7 +1577,9 @@ internal Type[] FunctionPointerReturnAndParameterTypes
                     while (type.IsNested)
                         type = type.DeclaringType!;
 
-                    m_namespace = RuntimeTypeHandle.GetMetadataImport((RuntimeType)type).GetNamespace(type.MetadataToken).ToString();
+                    RuntimeModule module = ((RuntimeType)type).GetRuntimeModule();
+                    m_namespace = module.MetadataImport.GetNamespace(type.MetadataToken).ToString();
+                    GC.KeepAlive(module);
                 }
 
                 return m_namespace;
@@ -3499,8 +3507,9 @@ public override GenericParameterAttributes GenericParameterAttributes
                 if (!IsGenericParameter)
                     throw new InvalidOperationException(SR.Arg_NotGenericParameter);
 
-
-                RuntimeTypeHandle.GetMetadataImport(this).GetGenericParamProps(MetadataToken, out GenericParameterAttributes attributes);
+                RuntimeModule module = GetRuntimeModule();
+                module.MetadataImport.GetGenericParamProps(MetadataToken, out GenericParameterAttributes attributes);
+                GC.KeepAlive(module);
 
                 return attributes;
             }
diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp
index 0e86d312ae88a3..a5cb3a763b861d 100644
--- a/src/coreclr/vm/domainassembly.cpp
+++ b/src/coreclr/vm/domainassembly.cpp
@@ -344,14 +344,14 @@ OBJECTREF DomainAssembly::GetExposedModuleObject()
     {
         REFLECTMODULEBASEREF refClass = NULL;
 
-        // Will be TRUE only if LoaderAllocator managed object was already collected and therefore we should
+        // Will be true only if LoaderAllocator managed object was already collected and therefore we should
         // return NULL
-        BOOL fIsLoaderAllocatorCollected = FALSE;
+        bool fIsLoaderAllocatorCollected = false;
 
         GCPROTECT_BEGIN(refClass);
 
         refClass = (REFLECTMODULEBASEREF) AllocateObject(CoreLibBinder::GetClass(CLASS__MODULE));
-        refClass->SetModule(m_pModule);
+        refClass->SetModuleDetails(GetModule(), GetModule()->GetMDImport());
 
         // Attach the reference to the assembly to keep the LoaderAllocator for this collectible type
         // alive as long as a reference to the module is kept alive.
@@ -360,7 +360,7 @@ OBJECTREF DomainAssembly::GetExposedModuleObject()
             OBJECTREF refAssembly = GetModule()->GetAssembly()->GetExposedObject();
             if ((refAssembly == NULL) && GetModule()->GetAssembly()->IsCollectible())
             {
-                fIsLoaderAllocatorCollected = TRUE;
+                fIsLoaderAllocatorCollected = true;
             }
             refClass->SetAssembly(refAssembly);
         }
diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h
index 98a38b8603419c..3baf5eb271dcc5 100644
--- a/src/coreclr/vm/ecalllist.h
+++ b/src/coreclr/vm/ecalllist.h
@@ -155,7 +155,6 @@ FCFuncStart(gCOMTypeHandleFuncs)
 FCFuncEnd()
 
 FCFuncStart(gMetaDataImport)
-    FCFuncElement("GetMetadataImport", MetaDataImport::GetMetadataImport)
     FCFuncElement("GetDefaultValue", MetaDataImport::GetDefaultValue)
     FCFuncElement("GetName", MetaDataImport::GetName)
     FCFuncElement("GetUserString", MetaDataImport::GetUserString)
diff --git a/src/coreclr/vm/managedmdimport.cpp b/src/coreclr/vm/managedmdimport.cpp
index 8ab00a85f5320c..200a330df62c67 100644
--- a/src/coreclr/vm/managedmdimport.cpp
+++ b/src/coreclr/vm/managedmdimport.cpp
@@ -67,16 +67,6 @@ FCIMPL11(FC_BOOL_RET, MetaDataImport::GetMarshalAs,
 }
 FCIMPLEND
 
-FCIMPL1(IMDInternalImport*, MetaDataImport::GetMetadataImport, ReflectModuleBaseObject * pModuleUNSAFE)
-{
-    FCALL_CONTRACT;
-
-    REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE);
-    Module *pModule = refModule->GetModule();
-    return pModule->GetMDImport();
-}
-FCIMPLEND
-
 FCIMPL6(HRESULT, MetaDataImport::GetDefaultValue, IMDInternalImport* pScope, mdToken tk, INT64* pDefaultValue, LPCWSTR* pStringValue, INT32* pLength, INT32* pCorElementType)
 {
     FCALL_CONTRACT;
diff --git a/src/coreclr/vm/managedmdimport.hpp b/src/coreclr/vm/managedmdimport.hpp
index 4db05291d6fd0b..817c5fa426a4c5 100644
--- a/src/coreclr/vm/managedmdimport.hpp
+++ b/src/coreclr/vm/managedmdimport.hpp
@@ -27,7 +27,6 @@ typedef struct
 class MetaDataImport
 {
 public:
-    static FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectModuleBaseObject* pModuleUNSAFE);
     static FCDECL2(HRESULT, GetScopeProps, IMDInternalImport* pScope, GUID* pmvid);
     static FCDECL3(HRESULT, GetMemberRefProps, IMDInternalImport* pScope, mdMemberRef mr, ConstArray* ppvSigBlob);
 
diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h
index a282dd867e94a9..178bc5e6b2f4cc 100644
--- a/src/coreclr/vm/object.h
+++ b/src/coreclr/vm/object.h
@@ -1171,15 +1171,19 @@ class ReflectModuleBaseObject : public Object
     OBJECTREF          m_runtimeType;
     OBJECTREF          m_runtimeAssembly;
     Module*            m_pData;         // Pointer to the Module
+    IMDInternalImport* m_metadataImport2;
 
   protected:
     ReflectModuleBaseObject() {LIMITED_METHOD_CONTRACT;}
    ~ReflectModuleBaseObject() {LIMITED_METHOD_CONTRACT;}
 
   public:
-    void SetModule(Module* p) {
+    void SetModuleDetails(Module* p, IMDInternalImport* import) {
         LIMITED_METHOD_CONTRACT;
+        _ASSERTE(p != NULL);
+        _ASSERTE(import != NULL);
         m_pData = p;
+        m_metadataImport2 = import;
     }
     Module* GetModule() {
         LIMITED_METHOD_CONTRACT;

From 7ceabf4b3e7aca25332eb8c00e077fb3103e3273 Mon Sep 17 00:00:00 2001
From: Aaron Robinson <arobins@microsoft.com>
Date: Mon, 22 Apr 2024 17:57:54 -0700
Subject: [PATCH 5/6] Update
 src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
---
 .../src/System/Reflection/RuntimeCustomAttributeData.cs         | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
index a80787772b0fb7..38663e57cde246 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs
@@ -2268,7 +2268,7 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
         {
             if (field.DeclaringType is not null)
             {
-                RuntimeModule module= field.GetRuntimeModule();
+                RuntimeModule module = field.GetRuntimeModule();
                 if (module.MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out int fieldOffset))
                 {
                     return new FieldOffsetAttribute(fieldOffset);

From a9bd0fc019e1bb0da939dc39cb6e162b51af4740 Mon Sep 17 00:00:00 2001
From: Aaron R Robinson <arobins@microsoft.com>
Date: Tue, 23 Apr 2024 09:57:25 -0700
Subject: [PATCH 6/6] Always get the latest metadataimport instance. The field
 on the managed object can become stale during HotReload or EnC scenarios.

---
 .../src/System/Reflection/MdImport.cs                  |  8 +++++++-
 .../src/System/Reflection/RuntimeModule.cs             |  6 ------
 src/coreclr/vm/domainassembly.cpp                      |  2 +-
 src/coreclr/vm/ecalllist.h                             |  1 +
 src/coreclr/vm/managedmdimport.cpp                     | 10 ++++++++++
 src/coreclr/vm/managedmdimport.hpp                     |  1 +
 src/coreclr/vm/object.h                                |  6 +-----
 7 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
index 69f2dfc5f2389a..6f74dde91fe7e0 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
@@ -301,10 +301,16 @@ internal static unsafe MarshalAsAttribute GetMarshalAs(ConstArray nativeType, Ru
         #endregion
 
         #region Constructor
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern unsafe IntPtr GetMetadataImport(RuntimeModule module);
+
         internal MetadataImport(RuntimeModule module)
         {
             ArgumentNullException.ThrowIfNull(module);
-            m_metadataImport2 = module.GetMDImport();
+
+            // The MetadataImport instance needs to be acquired in this manner
+            // since the instance can be replaced during HotReload and EnC scenarios.
+            m_metadataImport2 = GetMetadataImport(module);
         }
         #endregion
 
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs
index df41080a1f2448..4e9a4dffeb209a 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs
@@ -18,7 +18,6 @@ internal sealed partial class RuntimeModule : Module
         private RuntimeType m_runtimeType;
         private readonly RuntimeAssembly m_runtimeAssembly;
         private readonly IntPtr m_pData;
-        private readonly IntPtr m_metadataImport2;
 #pragma warning restore CA1823, 169
         #endregion
 
@@ -530,11 +529,6 @@ internal IntPtr GetUnderlyingNativeHandle()
         {
             return m_pData;
         }
-
-        internal IntPtr GetMDImport()
-        {
-            return m_metadataImport2;
-        }
         #endregion
     }
 }
diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp
index a5cb3a763b861d..ead21d61193433 100644
--- a/src/coreclr/vm/domainassembly.cpp
+++ b/src/coreclr/vm/domainassembly.cpp
@@ -351,7 +351,7 @@ OBJECTREF DomainAssembly::GetExposedModuleObject()
         GCPROTECT_BEGIN(refClass);
 
         refClass = (REFLECTMODULEBASEREF) AllocateObject(CoreLibBinder::GetClass(CLASS__MODULE));
-        refClass->SetModuleDetails(GetModule(), GetModule()->GetMDImport());
+        refClass->SetModule(GetModule());
 
         // Attach the reference to the assembly to keep the LoaderAllocator for this collectible type
         // alive as long as a reference to the module is kept alive.
diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h
index 3baf5eb271dcc5..98a38b8603419c 100644
--- a/src/coreclr/vm/ecalllist.h
+++ b/src/coreclr/vm/ecalllist.h
@@ -155,6 +155,7 @@ FCFuncStart(gCOMTypeHandleFuncs)
 FCFuncEnd()
 
 FCFuncStart(gMetaDataImport)
+    FCFuncElement("GetMetadataImport", MetaDataImport::GetMetadataImport)
     FCFuncElement("GetDefaultValue", MetaDataImport::GetDefaultValue)
     FCFuncElement("GetName", MetaDataImport::GetName)
     FCFuncElement("GetUserString", MetaDataImport::GetUserString)
diff --git a/src/coreclr/vm/managedmdimport.cpp b/src/coreclr/vm/managedmdimport.cpp
index 200a330df62c67..8ab00a85f5320c 100644
--- a/src/coreclr/vm/managedmdimport.cpp
+++ b/src/coreclr/vm/managedmdimport.cpp
@@ -67,6 +67,16 @@ FCIMPL11(FC_BOOL_RET, MetaDataImport::GetMarshalAs,
 }
 FCIMPLEND
 
+FCIMPL1(IMDInternalImport*, MetaDataImport::GetMetadataImport, ReflectModuleBaseObject * pModuleUNSAFE)
+{
+    FCALL_CONTRACT;
+
+    REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE);
+    Module *pModule = refModule->GetModule();
+    return pModule->GetMDImport();
+}
+FCIMPLEND
+
 FCIMPL6(HRESULT, MetaDataImport::GetDefaultValue, IMDInternalImport* pScope, mdToken tk, INT64* pDefaultValue, LPCWSTR* pStringValue, INT32* pLength, INT32* pCorElementType)
 {
     FCALL_CONTRACT;
diff --git a/src/coreclr/vm/managedmdimport.hpp b/src/coreclr/vm/managedmdimport.hpp
index 817c5fa426a4c5..4db05291d6fd0b 100644
--- a/src/coreclr/vm/managedmdimport.hpp
+++ b/src/coreclr/vm/managedmdimport.hpp
@@ -27,6 +27,7 @@ typedef struct
 class MetaDataImport
 {
 public:
+    static FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectModuleBaseObject* pModuleUNSAFE);
     static FCDECL2(HRESULT, GetScopeProps, IMDInternalImport* pScope, GUID* pmvid);
     static FCDECL3(HRESULT, GetMemberRefProps, IMDInternalImport* pScope, mdMemberRef mr, ConstArray* ppvSigBlob);
 
diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h
index 178bc5e6b2f4cc..a282dd867e94a9 100644
--- a/src/coreclr/vm/object.h
+++ b/src/coreclr/vm/object.h
@@ -1171,19 +1171,15 @@ class ReflectModuleBaseObject : public Object
     OBJECTREF          m_runtimeType;
     OBJECTREF          m_runtimeAssembly;
     Module*            m_pData;         // Pointer to the Module
-    IMDInternalImport* m_metadataImport2;
 
   protected:
     ReflectModuleBaseObject() {LIMITED_METHOD_CONTRACT;}
    ~ReflectModuleBaseObject() {LIMITED_METHOD_CONTRACT;}
 
   public:
-    void SetModuleDetails(Module* p, IMDInternalImport* import) {
+    void SetModule(Module* p) {
         LIMITED_METHOD_CONTRACT;
-        _ASSERTE(p != NULL);
-        _ASSERTE(import != NULL);
         m_pData = p;
-        m_metadataImport2 = import;
     }
     Module* GetModule() {
         LIMITED_METHOD_CONTRACT;