Skip to content

Commit

Permalink
Reduce RuntimeType.MakeGenericType overheads (#45137)
Browse files Browse the repository at this point in the history
- 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).
  • Loading branch information
stephentoub authored Nov 24, 2020
1 parent aebd598 commit 664b962
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,17 @@ internal Type[] GetInstantiationPublic()
[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern void Instantiate(QCallTypeHandle handle, IntPtr* pInst, int numGenericArgs, ObjectHandleOnStack type);

internal RuntimeType Instantiate(RuntimeType inst)
{
IntPtr ptr = inst.TypeHandle.Value;

RuntimeType? type = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
Instantiate(new QCallTypeHandle(ref nativeHandle), &ptr, 1, ObjectHandleOnStack.Create(ref type));
GC.KeepAlive(inst);
return type!;
}

internal RuntimeType Instantiate(Type[]? inst)
{
IntPtr[]? instHandles = CopyRuntimeTypeHandles(inst, out int instCount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3238,15 +3238,29 @@ public override Type MakeGenericType(Type[] instantiation)
if (instantiation == null)
throw new ArgumentNullException(nameof(instantiation));

RuntimeType[] instantiationRuntimeType = new RuntimeType[instantiation.Length];

if (!IsGenericTypeDefinition)
throw new InvalidOperationException(
SR.Format(SR.Arg_NotGenericTypeDefinition, this));
throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericTypeDefinition, this));

if (GetGenericArguments().Length != instantiation.Length)
RuntimeType[] genericParameters = GetGenericArgumentsInternal();
if (genericParameters.Length != instantiation.Length)
throw new ArgumentException(SR.Argument_GenericArgsCount, nameof(instantiation));

if (instantiation.Length == 1 && instantiation[0] is RuntimeType rt)
{
ThrowIfTypeNeverValidGenericArgument(rt);
try
{
return new RuntimeTypeHandle(this).Instantiate(rt);
}
catch (TypeLoadException e)
{
ValidateGenericArguments(this, new[] { rt }, e);
throw;
}
}

RuntimeType[] instantiationRuntimeType = new RuntimeType[instantiation.Length];

bool foundSigType = false;
bool foundNonRuntimeType = false;
for (int i = 0; i < instantiation.Length; i++)
Expand Down Expand Up @@ -3277,8 +3291,6 @@ public override Type MakeGenericType(Type[] instantiation)
return System.Reflection.Emit.TypeBuilderInstantiation.MakeGenericType(this, (Type[])(instantiation.Clone()));
}

RuntimeType[] genericParameters = GetGenericArgumentsInternal();

SanityCheckGenericArguments(instantiationRuntimeType, genericParameters);

Type ret;
Expand Down

0 comments on commit 664b962

Please sign in to comment.