Skip to content

Commit 664b962

Browse files
authored
Reduce RuntimeType.MakeGenericType overheads (#45137)
- Avoid an extra GetGenericArguments() call for all arities. - Special-case a Type[] with just one type. In looking at all calls to MakeGenericType when starting up a basic ASP.NET MVC app, 70% were for a single generic argument (the rest were for two).
1 parent aebd598 commit 664b962

File tree

2 files changed

+30
-7
lines changed

2 files changed

+30
-7
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,17 @@ internal Type[] GetInstantiationPublic()
522522
[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
523523
private static extern void Instantiate(QCallTypeHandle handle, IntPtr* pInst, int numGenericArgs, ObjectHandleOnStack type);
524524

525+
internal RuntimeType Instantiate(RuntimeType inst)
526+
{
527+
IntPtr ptr = inst.TypeHandle.Value;
528+
529+
RuntimeType? type = null;
530+
RuntimeTypeHandle nativeHandle = GetNativeHandle();
531+
Instantiate(new QCallTypeHandle(ref nativeHandle), &ptr, 1, ObjectHandleOnStack.Create(ref type));
532+
GC.KeepAlive(inst);
533+
return type!;
534+
}
535+
525536
internal RuntimeType Instantiate(Type[]? inst)
526537
{
527538
IntPtr[]? instHandles = CopyRuntimeTypeHandles(inst, out int instCount);

src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3238,15 +3238,29 @@ public override Type MakeGenericType(Type[] instantiation)
32383238
if (instantiation == null)
32393239
throw new ArgumentNullException(nameof(instantiation));
32403240

3241-
RuntimeType[] instantiationRuntimeType = new RuntimeType[instantiation.Length];
3242-
32433241
if (!IsGenericTypeDefinition)
3244-
throw new InvalidOperationException(
3245-
SR.Format(SR.Arg_NotGenericTypeDefinition, this));
3242+
throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericTypeDefinition, this));
32463243

3247-
if (GetGenericArguments().Length != instantiation.Length)
3244+
RuntimeType[] genericParameters = GetGenericArgumentsInternal();
3245+
if (genericParameters.Length != instantiation.Length)
32483246
throw new ArgumentException(SR.Argument_GenericArgsCount, nameof(instantiation));
32493247

3248+
if (instantiation.Length == 1 && instantiation[0] is RuntimeType rt)
3249+
{
3250+
ThrowIfTypeNeverValidGenericArgument(rt);
3251+
try
3252+
{
3253+
return new RuntimeTypeHandle(this).Instantiate(rt);
3254+
}
3255+
catch (TypeLoadException e)
3256+
{
3257+
ValidateGenericArguments(this, new[] { rt }, e);
3258+
throw;
3259+
}
3260+
}
3261+
3262+
RuntimeType[] instantiationRuntimeType = new RuntimeType[instantiation.Length];
3263+
32503264
bool foundSigType = false;
32513265
bool foundNonRuntimeType = false;
32523266
for (int i = 0; i < instantiation.Length; i++)
@@ -3277,8 +3291,6 @@ public override Type MakeGenericType(Type[] instantiation)
32773291
return System.Reflection.Emit.TypeBuilderInstantiation.MakeGenericType(this, (Type[])(instantiation.Clone()));
32783292
}
32793293

3280-
RuntimeType[] genericParameters = GetGenericArgumentsInternal();
3281-
32823294
SanityCheckGenericArguments(instantiationRuntimeType, genericParameters);
32833295

32843296
Type ret;

0 commit comments

Comments
 (0)