Skip to content

Commit 3e18c03

Browse files
Simplify managed MetadataImport creation (#101353)
* Simplify managed MetadataImport creation Consolidate the create mechanism for the managed MetadataImport type. This also removes some Helper Method Frame usage. * Always get the latest metadataimport instance. The field on the managed object can become stale during HotReload or EnC scenarios. --------- Co-authored-by: Jan Kotas <jkotas@microsoft.com>
1 parent a2bd583 commit 3e18c03

13 files changed

+91
-102
lines changed

src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs

+9-6
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,6 @@ internal readonly partial struct MetadataImport
205205
#pragma warning restore CA1067
206206
{
207207
private readonly IntPtr m_metadataImport2;
208-
private readonly object? m_keepalive;
209-
210-
internal static MetadataImport EmptyImport => new MetadataImport(IntPtr.Zero, null);
211208

212209
#region Override methods from Object
213210
public override int GetHashCode()
@@ -304,10 +301,16 @@ internal static unsafe MarshalAsAttribute GetMarshalAs(ConstArray nativeType, Ru
304301
#endregion
305302

306303
#region Constructor
307-
internal MetadataImport(IntPtr metadataImport2, object? keepalive)
304+
[MethodImpl(MethodImplOptions.InternalCall)]
305+
private static extern unsafe IntPtr GetMetadataImport(RuntimeModule module);
306+
307+
internal MetadataImport(RuntimeModule module)
308308
{
309-
m_metadataImport2 = metadataImport2;
310-
m_keepalive = keepalive;
309+
ArgumentNullException.ThrowIfNull(module);
310+
311+
// The MetadataImport instance needs to be acquired in this manner
312+
// since the instance can be replaced during HotReload and EnC scenarios.
313+
m_metadataImport2 = GetMetadataImport(module);
311314
}
312315
#endregion
313316

src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs

+23-12
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ internal static CustomAttributeRecord[] GetCustomAttributeRecords(RuntimeModule
215215
scope.GetCustomAttributeProps(tkCustomAttributeTokens[i],
216216
out records[i].tkCtor.Value, out records[i].blob);
217217
}
218+
GC.KeepAlive(module);
218219

219220
return records;
220221
}
@@ -250,13 +251,13 @@ internal static CustomAttributeTypedArgument Filter(IList<CustomAttributeData> a
250251
private RuntimeCustomAttributeData(RuntimeModule scope, MetadataToken caCtorToken, in ConstArray blob)
251252
{
252253
m_scope = scope;
253-
m_ctor = (RuntimeConstructorInfo)RuntimeType.GetMethodBase(scope, caCtorToken)!;
254+
m_ctor = (RuntimeConstructorInfo)RuntimeType.GetMethodBase(m_scope, caCtorToken)!;
254255

255256
if (m_ctor!.DeclaringType!.IsGenericType)
256257
{
257-
MetadataImport metadataScope = scope.MetadataImport;
258-
Type attributeType = scope.ResolveType(metadataScope.GetParentToken(caCtorToken), null, null)!;
259-
m_ctor = (RuntimeConstructorInfo)scope.ResolveMethod(caCtorToken, attributeType.GenericTypeArguments, null)!.MethodHandle.GetMethodInfo();
258+
MetadataImport metadataScope = m_scope.MetadataImport;
259+
Type attributeType = m_scope.ResolveType(metadataScope.GetParentToken(caCtorToken), null, null)!;
260+
m_ctor = (RuntimeConstructorInfo)m_scope.ResolveMethod(caCtorToken, attributeType.GenericTypeArguments, null)!.MethodHandle.GetMethodInfo();
260261
}
261262

262263
ReadOnlySpan<ParameterInfo> parameters = m_ctor.GetParametersAsSpan();
@@ -1466,6 +1467,7 @@ private static bool IsCustomAttributeDefined(
14661467
}
14671468
}
14681469
}
1470+
GC.KeepAlive(decoratedModule);
14691471

14701472
return false;
14711473
}
@@ -1615,6 +1617,7 @@ private static void AddCustomAttributes(
16151617

16161618
attributes.Add(attribute);
16171619
}
1620+
GC.KeepAlive(decoratedModule);
16181621
}
16191622

16201623
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
@@ -2194,10 +2197,11 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
21942197
if ((method.Attributes & MethodAttributes.PinvokeImpl) == 0)
21952198
return null;
21962199

2197-
MetadataImport scope = ModuleHandle.GetMetadataImport(method.Module.ModuleHandle.GetRuntimeModule());
2200+
RuntimeModule module = method.Module.ModuleHandle.GetRuntimeModule();
2201+
MetadataImport scope = module.MetadataImport;
21982202
int token = method.MetadataToken;
2199-
22002203
scope.GetPInvokeMap(token, out PInvokeAttributes flags, out string entryPoint, out string dllName);
2204+
GC.KeepAlive(module);
22012205

22022206
CharSet charSet = CharSet.None;
22032207

@@ -2252,7 +2256,7 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
22522256

22532257
private static MarshalAsAttribute? GetMarshalAsCustomAttribute(int token, RuntimeModule scope)
22542258
{
2255-
ConstArray nativeType = ModuleHandle.GetMetadataImport(scope).GetFieldMarshal(token);
2259+
ConstArray nativeType = scope.MetadataImport.GetFieldMarshal(token);
22562260

22572261
if (nativeType.Length == 0)
22582262
return null;
@@ -2262,10 +2266,15 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
22622266

22632267
private static FieldOffsetAttribute? GetFieldOffsetCustomAttribute(RuntimeFieldInfo field)
22642268
{
2265-
if (field.DeclaringType is not null &&
2266-
field.GetRuntimeModule().MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out int fieldOffset))
2267-
return new FieldOffsetAttribute(fieldOffset);
2268-
2269+
if (field.DeclaringType is not null)
2270+
{
2271+
RuntimeModule module = field.GetRuntimeModule();
2272+
if (module.MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out int fieldOffset))
2273+
{
2274+
return new FieldOffsetAttribute(fieldOffset);
2275+
}
2276+
GC.KeepAlive(module);
2277+
}
22692278
return null;
22702279
}
22712280

@@ -2291,7 +2300,9 @@ internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType? caType)
22912300
case TypeAttributes.UnicodeClass: charSet = CharSet.Unicode; break;
22922301
default: Debug.Fail("Unreachable code"); break;
22932302
}
2294-
type.GetRuntimeModule().MetadataImport.GetClassLayout(type.MetadataToken, out int pack, out int size);
2303+
RuntimeModule module = type.GetRuntimeModule();
2304+
module.MetadataImport.GetClassLayout(type.MetadataToken, out int pack, out int size);
2305+
GC.KeepAlive(module);
22952306

22962307
StructLayoutAttribute attribute = new StructLayoutAttribute(layoutKind);
22972308

src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ public override byte[] ResolveSignature(int metadataToken)
202202

203203
if (declaringType.IsGenericType || declaringType.IsArray)
204204
{
205-
int tkDeclaringType = ModuleHandle.GetMetadataImport(this).GetParentToken(metadataToken);
205+
int tkDeclaringType = MetadataImport.GetParentToken(metadataToken);
206206
declaringType = (RuntimeType)ResolveType(tkDeclaringType, genericTypeArguments, genericMethodArguments);
207207
}
208208

@@ -353,7 +353,7 @@ public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFile
353353
#region Internal Members
354354
internal RuntimeType RuntimeType => m_runtimeType ??= ModuleHandle.GetModuleType(this);
355355

356-
internal MetadataImport MetadataImport => ModuleHandle.GetMetadataImport(this);
356+
internal MetadataImport MetadataImport => new MetadataImport(this);
357357
#endregion
358358

359359
#region ICustomAttributeProvider Members

src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs

+14-7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ internal static ParameterInfo GetReturnParameter(IRuntimeMethodInfo method, Memb
2929
private static ParameterInfo[] GetParameters(
3030
IRuntimeMethodInfo methodHandle, MemberInfo member, Signature sig, out ParameterInfo? returnParameter, bool fetchReturnParameter)
3131
{
32+
// The lifetime rules for MetadataImport expect these two objects to be the same instance.
33+
// See the lifetime of MetadataImport, acquired through IRuntimeMethodInfo, but extended
34+
// through the MemberInfo instance.
35+
Debug.Assert(ReferenceEquals(methodHandle, member));
36+
3237
returnParameter = null;
3338
int sigArgCount = sig.Arguments.Length;
3439
ParameterInfo[] args =
@@ -43,7 +48,7 @@ private static ParameterInfo[] GetParameters(
4348
// are generated on the fly by the runtime.
4449
if (!MdToken.IsNullToken(tkMethodDef))
4550
{
46-
MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(RuntimeMethodHandle.GetDeclaringType(methodHandle));
51+
MetadataImport scope = RuntimeMethodHandle.GetDeclaringType(methodHandle).GetRuntimeModule().MetadataImport;
4752

4853
scope.EnumParams(tkMethodDef, out MetadataEnumResult tkParamDefs);
4954

@@ -73,7 +78,7 @@ private static ParameterInfo[] GetParameters(
7378
}
7479
else if (!fetchReturnParameter && position >= 0)
7580
{
76-
// position beyong sigArgCount?
81+
// position beyond sigArgCount?
7782
if (position >= sigArgCount)
7883
throw new BadImageFormatException(SR.BadImageFormat_ParameterSignatureMismatch);
7984

@@ -86,7 +91,7 @@ private static ParameterInfo[] GetParameters(
8691
// Fill in empty ParameterInfos for those without tokens
8792
if (fetchReturnParameter)
8893
{
89-
returnParameter ??= new RuntimeParameterInfo(sig, MetadataImport.EmptyImport, 0, -1, (ParameterAttributes)0, member);
94+
returnParameter ??= new RuntimeParameterInfo(sig, default, 0, -1, (ParameterAttributes)0, member);
9095
}
9196
else
9297
{
@@ -97,7 +102,7 @@ private static ParameterInfo[] GetParameters(
97102
if (args[i] != null)
98103
continue;
99104

100-
args[i] = new RuntimeParameterInfo(sig, MetadataImport.EmptyImport, 0, i, (ParameterAttributes)0, member);
105+
args[i] = new RuntimeParameterInfo(sig, default, 0, i, (ParameterAttributes)0, member);
101106
}
102107
}
103108
}
@@ -165,7 +170,7 @@ private RuntimeParameterInfo(RuntimeParameterInfo accessor, MemberInfo member)
165170
PositionImpl = accessor.Position;
166171
AttrsImpl = accessor.Attributes;
167172

168-
// Strictly speeking, property's don't contain parameter tokens
173+
// Strictly speaking, properties don't contain parameter tokens
169174
// However we need this to make ca's work... oh well...
170175
m_tkParamDef = MdToken.IsNullToken(accessor.MetadataToken) ? (int)MetadataTokenType.ParamDef : accessor.MetadataToken;
171176
m_scope = accessor.m_scope;
@@ -176,7 +181,7 @@ private RuntimeParameterInfo(
176181
int position, ParameterAttributes attributes, MemberInfo member)
177182
{
178183
Debug.Assert(member != null);
179-
Debug.Assert(MdToken.IsNullToken(tkParamDef) == scope.Equals(MetadataImport.EmptyImport));
184+
Debug.Assert(MdToken.IsNullToken(tkParamDef) == scope.Equals((MetadataImport)default));
180185
Debug.Assert(MdToken.IsNullToken(tkParamDef) || MdToken.IsTokenOfType(tkParamDef, MetadataTokenType.ParamDef));
181186

182187
PositionImpl = position;
@@ -201,7 +206,7 @@ internal RuntimeParameterInfo(MethodInfo owner, string? name, Type parameterType
201206
PositionImpl = position;
202207
AttrsImpl = ParameterAttributes.None;
203208
m_tkParamDef = (int)MetadataTokenType.ParamDef;
204-
m_scope = MetadataImport.EmptyImport;
209+
m_scope = default;
205210
}
206211
#endregion
207212

@@ -239,6 +244,7 @@ public override string? Name
239244
if (!MdToken.IsNullToken(m_tkParamDef))
240245
{
241246
string name = m_scope.GetName(m_tkParamDef).ToString();
247+
GC.KeepAlive(this);
242248
NameImpl = name;
243249
}
244250

@@ -339,6 +345,7 @@ private bool TryGetDefaultValueInternal(bool raw, out object? defaultValue)
339345
#region Look for a default value in metadata
340346
// This will return DBNull.Value if no constant value is defined on m_tkParamDef in the metadata.
341347
defaultValue = MdConstant.GetValue(m_scope, m_tkParamDef, ParameterType.TypeHandle, raw);
348+
GC.KeepAlive(this);
342349

343350
// If default value is not specified in metadata, look for it in custom attributes
344351
if (defaultValue == DBNull.Value)

src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ internal RuntimePropertyInfo(
3535
Debug.Assert(reflectedTypeCache != null);
3636
Debug.Assert(!reflectedTypeCache.IsGlobal);
3737

38-
MetadataImport scope = declaredType.GetRuntimeModule().MetadataImport;
38+
RuntimeModule module = declaredType.GetRuntimeModule();
39+
MetadataImport scope = module.MetadataImport;
3940

4041
m_token = tkProperty;
4142
m_reflectedTypeCache = reflectedTypeCache;
@@ -47,6 +48,7 @@ internal RuntimePropertyInfo(
4748
out _, out _, out _,
4849
out m_getterMethod, out m_setterMethod, out m_otherMethod,
4950
out isPrivate, out m_bindingFlags);
51+
GC.KeepAlive(module);
5052
}
5153
#endregion
5254

@@ -65,9 +67,9 @@ internal Signature Signature
6567
{
6668
if (m_signature == null)
6769
{
68-
6970
GetRuntimeModule().MetadataImport.GetPropertyProps(
7071
m_token, out _, out _, out ConstArray sig);
72+
GC.KeepAlive(this);
7173

7274
m_signature = new Signature(sig.Signature.ToPointer(), sig.Length, m_declaringType);
7375
}
@@ -210,6 +212,7 @@ public override Type[] GetOptionalCustomModifiers()
210212
internal object GetConstantValue(bool raw)
211213
{
212214
object? defaultValue = MdConstant.GetValue(GetRuntimeModule().MetadataImport, m_token, PropertyType.TypeHandle, raw);
215+
GC.KeepAlive(this);
213216

214217
if (defaultValue == DBNull.Value)
215218
// Arg_EnumLitValueNotFound -> "Literal value was not found."

src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs

+4-21
Original file line numberDiff line numberDiff line change
@@ -650,14 +650,6 @@ internal static bool SatisfiesConstraints(RuntimeType paramType, RuntimeType[]?
650650
}
651651
}
652652

653-
[MethodImpl(MethodImplOptions.InternalCall)]
654-
private static extern IntPtr _GetMetadataImport(RuntimeType type);
655-
656-
internal static MetadataImport GetMetadataImport(RuntimeType type)
657-
{
658-
return new MetadataImport(_GetMetadataImport(type), type);
659-
}
660-
661653
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_RegisterCollectibleTypeDependency")]
662654
private static partial void RegisterCollectibleTypeDependency(QCallTypeHandle type, QCallAssembly assembly);
663655

@@ -1247,8 +1239,6 @@ internal ModuleHandle(RuntimeModule module)
12471239
}
12481240
#endregion
12491241

1250-
#region Internal FCalls
1251-
12521242
internal RuntimeModule GetRuntimeModule()
12531243
{
12541244
return m_ptr;
@@ -1278,6 +1268,7 @@ public bool Equals(ModuleHandle handle)
12781268

12791269
public static bool operator !=(ModuleHandle left, ModuleHandle right) => !left.Equals(right);
12801270

1271+
#region Internal FCalls
12811272
[MethodImpl(MethodImplOptions.InternalCall)]
12821273
internal static extern IRuntimeMethodInfo GetDynamicMethod(Reflection.Emit.DynamicMethod method, RuntimeModule module, string name, byte[] sig, Resolver resolver);
12831274

@@ -1336,7 +1327,7 @@ public RuntimeTypeHandle ResolveTypeHandle(int typeToken, RuntimeTypeHandle[]? t
13361327
}
13371328
catch (Exception)
13381329
{
1339-
if (!GetMetadataImport(module).IsValidToken(typeToken))
1330+
if (!module.MetadataImport.IsValidToken(typeToken))
13401331
throw new ArgumentOutOfRangeException(nameof(typeToken),
13411332
SR.Format(SR.Argument_InvalidToken, typeToken, new ModuleHandle(module)));
13421333
throw;
@@ -1389,7 +1380,7 @@ internal static RuntimeMethodHandleInternal ResolveMethodHandleInternal(RuntimeM
13891380
}
13901381
catch (Exception)
13911382
{
1392-
if (!GetMetadataImport(module).IsValidToken(methodToken))
1383+
if (!module.MetadataImport.IsValidToken(methodToken))
13931384
throw new ArgumentOutOfRangeException(nameof(methodToken),
13941385
SR.Format(SR.Argument_InvalidToken, methodToken, new ModuleHandle(module)));
13951386
throw;
@@ -1442,7 +1433,7 @@ public RuntimeFieldHandle ResolveFieldHandle(int fieldToken, RuntimeTypeHandle[]
14421433
}
14431434
catch (Exception)
14441435
{
1445-
if (!GetMetadataImport(module).IsValidToken(fieldToken))
1436+
if (!module.MetadataImport.IsValidToken(fieldToken))
14461437
throw new ArgumentOutOfRangeException(nameof(fieldToken),
14471438
SR.Format(SR.Argument_InvalidToken, fieldToken, new ModuleHandle(module)));
14481439
throw;
@@ -1485,14 +1476,6 @@ internal static void GetPEKind(RuntimeModule module, out PortableExecutableKinds
14851476
internal static extern int GetMDStreamVersion(RuntimeModule module);
14861477

14871478
public int MDStreamVersion => GetMDStreamVersion(GetRuntimeModule());
1488-
1489-
[MethodImpl(MethodImplOptions.InternalCall)]
1490-
private static extern IntPtr _GetMetadataImport(RuntimeModule module);
1491-
1492-
internal static MetadataImport GetMetadataImport(RuntimeModule module)
1493-
{
1494-
return new MetadataImport(_GetMetadataImport(module), module);
1495-
}
14961479
#endregion
14971480
}
14981481

0 commit comments

Comments
 (0)