Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of Activator.CreateInstance #32520

Merged
Merged
Show file tree
Hide file tree
Changes from 73 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
d0bde83
Fast object instantiation, take two
GrabYourPitchforks May 9, 2020
67539c2
Merge remote-tracking branch 'origin/master' into fast_createinstance…
GrabYourPitchforks Jul 8, 2020
edf3858
PR feedback
GrabYourPitchforks Jul 7, 2020
c5ae79f
Re-enable analyzers in project
GrabYourPitchforks Jul 8, 2020
e09e91b
Don't run COM tests on non-Windows
GrabYourPitchforks Jul 8, 2020
17a3bde
PR feedback
GrabYourPitchforks Jul 8, 2020
2467fdd
Fix mergeMerge remote-tracking branch 'origin/master' into fast_creat…
GrabYourPitchforks Nov 17, 2020
eb368eb
Cleanup + PR feedback
GrabYourPitchforks Nov 17, 2020
b85fb74
Merge remote-tracking branch 'origin/master' into fast_createinstance
GrabYourPitchforks Nov 18, 2020
faeef8c
Remove 'unwrapNullable' parameter
GrabYourPitchforks Nov 18, 2020
bdb403a
Quick GetDefaultCtor helper
GrabYourPitchforks Nov 18, 2020
c173fda
Remove unmanaged Allocate / CreateInstance
GrabYourPitchforks Nov 18, 2020
5c52acd
Fix GetDefaultConstructor signature
GrabYourPitchforks Nov 19, 2020
a1c362c
Fix AV in allocator
GrabYourPitchforks Nov 19, 2020
3ce9c41
Fix indentation
GrabYourPitchforks Nov 19, 2020
904b25d
Fix COM instantiation
GrabYourPitchforks Nov 19, 2020
1f6434a
Remove COM allocator special-case
GrabYourPitchforks Nov 19, 2020
c1ecb07
Fix mono build break; quick code cleanup
GrabYourPitchforks Nov 19, 2020
a071262
Rename GetNewobjHelperFnPtr -> GetAllocatorFtn
GrabYourPitchforks Nov 19, 2020
dc417fd
Cleanup in the allocator routines
GrabYourPitchforks Nov 19, 2020
6904495
Fix linker failures, add asserts
GrabYourPitchforks Nov 19, 2020
05c35a8
Remove unwanted CreateInstanceDefaultCtor overload
GrabYourPitchforks Nov 19, 2020
3d8515a
Use WeakRef in ActivatorCache
GrabYourPitchforks Nov 19, 2020
5acef41
Reintroduce COM specialization
GrabYourPitchforks Nov 20, 2020
adfae42
Allow runtime to create unboxing stub on my behalf
GrabYourPitchforks Nov 20, 2020
49a8de1
Fix linker warning
GrabYourPitchforks Nov 20, 2020
98c7941
Update error conditions
GrabYourPitchforks Nov 20, 2020
0a443c2
Friendlier exception messages when activation fails
GrabYourPitchforks Nov 20, 2020
3b34ae6
Cleanup usings
GrabYourPitchforks Nov 20, 2020
6e1b7cd
Move friendly exception messages to common place
GrabYourPitchforks Nov 20, 2020
b588d5d
Fix TIE wrappers
GrabYourPitchforks Nov 20, 2020
55aa128
Update unit tests
GrabYourPitchforks Nov 20, 2020
0ef275c
Call CreateInstanceCheckThis for better exception handling
GrabYourPitchforks Nov 20, 2020
4c1f5dd
PR feedback + fix failing coreclr unit tests
GrabYourPitchforks Nov 20, 2020
97f5f60
Fix build breaks
GrabYourPitchforks Nov 20, 2020
867bdc0
Merge remote-tracking branch 'levib/fast_createinstance' into fast_cr…
GrabYourPitchforks Nov 20, 2020
2e44013
Fix strings.resx whitespace
GrabYourPitchforks Nov 20, 2020
9c267fd
Fix build breaks on mono & non-Windows
GrabYourPitchforks Nov 20, 2020
bead4c6
PR feedback
GrabYourPitchforks Nov 20, 2020
8f12dd8
Fix GC hole in AllocateComObject
GrabYourPitchforks Nov 21, 2020
3a2021d
Refactor GetActivationInfo
GrabYourPitchforks Nov 22, 2020
46ed0b8
Refactor RunClassConstructor
GrabYourPitchforks Nov 22, 2020
d3bc632
Update GetUninitializedObject to call the new APIs
GrabYourPitchforks Nov 22, 2020
3f362f2
Hook up ActivatorCache to new system
GrabYourPitchforks Nov 22, 2020
879937b
Fix typo causing build break
GrabYourPitchforks Nov 22, 2020
93bcedb
Change GetActivationInfo to QCALL
GrabYourPitchforks Nov 22, 2020
e04401f
Simplify some call sites
GrabYourPitchforks Nov 22, 2020
9887e9a
Merge remote-tracking branch 'origin/master' into fast_createinstance…
GrabYourPitchforks Nov 22, 2020
186fd83
Fix failing tests
GrabYourPitchforks Nov 22, 2020
4d3d9db
Fix bad assert
GrabYourPitchforks Nov 22, 2020
036cbf0
Add managed _AllocateComObject member to make FCall checks happier
GrabYourPitchforks Nov 22, 2020
882b63e
Avoid using GetEEFuncEntryPoint
GrabYourPitchforks Nov 22, 2020
0b0c8db
Fix build error in ecalllist.h
GrabYourPitchforks Nov 22, 2020
c50d287
Update COM invocation unit tests
GrabYourPitchforks Nov 22, 2020
e2235cc
Merge remote-tracking branch 'origin/master' into fast_createinstance…
GrabYourPitchforks Nov 22, 2020
cebbf48
Allow propagation of PNSE in RuntimeHandles
GrabYourPitchforks Nov 22, 2020
d373fe7
Merge remote-tracking branch 'origin/master' into fast_createinstance…
GrabYourPitchforks Nov 24, 2020
12b4578
Remove _AllocateComObject sentinel
GrabYourPitchforks Nov 24, 2020
a7fa617
PR feedback
GrabYourPitchforks Nov 24, 2020
3e9438c
PR feedback - simplify GetActivationInfo out params
GrabYourPitchforks Nov 25, 2020
9c20d84
Merge remote-tracking branch 'origin/master' into fast_createinstance…
GrabYourPitchforks Nov 25, 2020
4b38b6c
Add missing ifdef around _AllocateComInterop
GrabYourPitchforks Nov 25, 2020
9ed2b9b
Final inspection + code cleanup
GrabYourPitchforks Nov 25, 2020
0ebebd6
Fix compilation error on non-Windows
GrabYourPitchforks Nov 25, 2020
374cf34
Code cleanup & PR feedback
GrabYourPitchforks Nov 25, 2020
6b23817
Merge remote-tracking branch 'origin/master' into fast_createinstance…
GrabYourPitchforks Nov 25, 2020
11be754
More code cleanup
GrabYourPitchforks Nov 26, 2020
5d43a91
Rename ActivatorCache source file
GrabYourPitchforks Nov 26, 2020
0635399
Remove unnecessary asserts, underscores, indentation
GrabYourPitchforks Nov 26, 2020
9ac3c3f
Fix [DynamicallyAccessedMembers] annotations
GrabYourPitchforks Nov 26, 2020
a06ef73
Fix bad assert
GrabYourPitchforks Nov 26, 2020
1b1261f
Update src/coreclr/src/vm/reflectioninvocation.cpp
GrabYourPitchforks Nov 26, 2020
94f8614
PR feedback
GrabYourPitchforks Nov 26, 2020
c73e9fa
Update src/coreclr/src/vm/reflectioninvocation.cpp
jkotas Nov 26, 2020
359a588
Remove incorrect assert in ActivatorCache
GrabYourPitchforks Nov 26, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@
<Compile Include="$(BclSourcesRoot)\System\Runtime\Versioning\CompatibilitySwitch.cs" />
<Compile Include="$(BclSourcesRoot)\System\RuntimeArgumentHandle.cs" />
<Compile Include="$(BclSourcesRoot)\System\RuntimeHandles.cs" />
<Compile Include="$(BclSourcesRoot)\System\RuntimeType.ActivatorCache.cs" />
<Compile Include="$(BclSourcesRoot)\System\RuntimeType.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Security\DynamicSecurityMethodAttribute.cs" />
<Compile Include="$(BclSourcesRoot)\System\StartupHookProvider.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,6 @@ internal static bool HasElementType(RuntimeType type)
return outHandles;
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern object CreateInstance(RuntimeType type, bool publicOnly, bool wrapExceptions, ref bool canBeCached, ref RuntimeMethodHandleInternal ctor, ref bool hasNoDefaultCtor);

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern object Allocate(RuntimeType type);

internal static object CreateInstanceForAnotherGenericParameter(RuntimeType type, RuntimeType genericParameter)
{
object? instantiatedObject = null;
Expand Down Expand Up @@ -258,6 +252,51 @@ private static extern void CreateInstanceForAnotherGenericParameter(
int cTypeHandles,
ObjectHandleOnStack instantiatedObject);

/// <summary>
/// Given a RuntimeType, returns information about how to activate it via calli
/// semantics. This method will ensure the type object is fully initialized within
/// the VM, but it will not call any static ctors on the type.
/// </summary>
internal static void GetActivationInfo(
RuntimeType rt,
out delegate*<void*, object> pfnAllocator,
out void* vAllocatorFirstArg,
out delegate*<object, void> pfnCtor,
out bool ctorIsPublic)
{
Debug.Assert(rt != null);

delegate*<void*, object> pfnAllocatorTemp = default;
void* vAllocatorFirstArgTemp = default;
delegate*<object, void> pfnCtorTemp = default;
Interop.BOOL fCtorIsPublicTemp = default;

GetActivationInfo(
ObjectHandleOnStack.Create(ref rt),
&pfnAllocatorTemp, &vAllocatorFirstArgTemp,
&pfnCtorTemp, &fCtorIsPublicTemp);

pfnAllocator = pfnAllocatorTemp;
vAllocatorFirstArg = vAllocatorFirstArgTemp;
pfnCtor = pfnCtorTemp;
ctorIsPublic = fCtorIsPublicTemp != Interop.BOOL.FALSE;
}

[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern void GetActivationInfo(
ObjectHandleOnStack pRuntimeType,
delegate*<void*, object>* ppfnAllocator,
void** pvAllocatorFirstArg,
delegate*<object, void>* ppfnCtor,
Interop.BOOL* pfCtorIsPublic);

#if FEATURE_COMINTEROP
// Referenced by unmanaged layer (see GetActivationInfo).
// First parameter is ComClassFactory*.
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern object AllocateComObject(void* pClassFactory);
#endif

internal RuntimeType GetRuntimeType()
{
return m_type;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace System
{
internal sealed partial class RuntimeType
{
/// <summary>
/// A cache which allows optimizing <see cref="Activator.CreateInstance"/>,
/// <see cref="RuntimeType.CreateInstanceDefaultCtor"/>, and related APIs.
/// </summary>
private sealed unsafe class ActivatorCache
{
// The managed calli to the newobj allocator, plus its first argument (MethodTable*).
// In the case of the COM allocator, first arg is ComClassFactory*, not MethodTable*.
private readonly delegate*<void*, object?> _pfnAllocator;
private readonly void* _allocatorFirstArg;

// The managed calli to the parameterless ctor, taking "this" (as object) as its first argument.
private readonly delegate*<object?, void> _pfnCtor;
private readonly bool _ctorIsPublic;

#if DEBUG
private readonly RuntimeType _originalRuntimeType;
#endif

internal ActivatorCache(RuntimeType rt)
{
Debug.Assert(rt != null);

#if DEBUG
_originalRuntimeType = rt;
#endif

// The check below is redundant since these same checks are performed at the
// unmanaged layer, but this call will throw slightly different exceptions
// than the unmanaged layer, and callers might be dependent on this.

rt.CreateInstanceCheckThis();

try
{
RuntimeTypeHandle.GetActivationInfo(rt,
out _pfnAllocator!, out _allocatorFirstArg,
out _pfnCtor!, out _ctorIsPublic);
}
catch (Exception ex)
{
// Exception messages coming from the runtime won't include
// the type name. Let's include it here to improve the
// debugging experience for our callers.

string friendlyMessage = SR.Format(SR.Activator_CannotCreateInstance, rt, ex.Message);
switch (ex)
{
case ArgumentException: throw new ArgumentException(friendlyMessage);
case PlatformNotSupportedException: throw new PlatformNotSupportedException(friendlyMessage);
case NotSupportedException: throw new NotSupportedException(friendlyMessage);
case MethodAccessException: throw new MethodAccessException(friendlyMessage);
case MissingMethodException: throw new MissingMethodException(friendlyMessage);
case MemberAccessException: throw new MemberAccessException(friendlyMessage);
}

throw; // can't make a friendlier message, rethrow original exception
}
Comment on lines +51 to +69
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this better than, say:

catch (ArgumentException e) { throw new ArgumentException(CreateFriendlyMessage(rt, e)); }
catch (PlatformNotSupportedException e) { throw new PlatformNotSupportedException(CreateFriendlyMessage(rt, e)); }
... // etc.

? I realize the above is probably a bit more IL, but it also means you won't catch and rethrow if the exception didn't match one of the special-cased types. I don't know how common that will be.

Copy link
Member Author

@GrabYourPitchforks GrabYourPitchforks Dec 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not ignoring this, but leaving this thread marked unresolved for now because I think we can address it as part of #36194.


// Activator.CreateInstance returns null given typeof(Nullable<T>).

if (_pfnAllocator == null)
{
Debug.Assert(Nullable.GetUnderlyingType(rt) != null,
"Null allocator should only be returned for Nullable<T>.");

static object? ReturnNull(void* _) => null;
_pfnAllocator = &ReturnNull;
}

// If no ctor is provided, we have Nullable<T>, a ctorless value type T,
// or a ctorless __ComObject. In any case, we should replace the
// ctor call with our no-op stub. The unmanaged GetActivationInfo layer
// would have thrown an exception if 'rt' were a normal reference type
// without a ctor.

if (_pfnCtor == null)
{
static void CtorNoopStub(object? uninitializedObject) { }
_pfnCtor = &CtorNoopStub; // we use null singleton pattern if no ctor call is necessary

Debug.Assert(_ctorIsPublic); // implicit parameterless ctor is always considered public
}

// We don't need to worry about invoking cctors here. The runtime will figure it
// out for us when the instance ctor is called. For value types, because we're
// creating a boxed default(T), the static cctor is called when *any* instance
// method is invoked.
}

internal bool CtorIsPublic => _ctorIsPublic;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal object? CreateUninitializedObject(RuntimeType rt)
{
// We don't use RuntimeType, but we force the caller to pass it so
// that we can keep it alive on their behalf. Once the object is
// constructed, we no longer need the reference to the type instance,
// as the object itself will keep the type alive.

#if DEBUG
if (_originalRuntimeType != rt)
{
Debug.Fail("Caller passed the wrong RuntimeType to this routine."
+ Environment.NewLineConst + "Expected: " + (_originalRuntimeType ?? (object)"<null>")
+ Environment.NewLineConst + "Actual: " + (rt ?? (object)"<null>"));
}
#endif

object? retVal = _pfnAllocator(_allocatorFirstArg);
GC.KeepAlive(rt);
return retVal;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void CallConstructor(object? uninitializedObject)
{
#if DEBUG
if (uninitializedObject != null && !uninitializedObject.GetType().IsEquivalentTo(_originalRuntimeType))
{
Debug.Fail("Caller passed an unexpected 'this' parameter to ctor - possible type safety violation."
+ Environment.NewLineConst + "Expected type: " + (_originalRuntimeType ?? (object)"<null>")
+ Environment.NewLineConst + "Actual type: " + uninitializedObject.GetType());
}
#endif

_pfnCtor(uninitializedObject);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@

namespace System
{
// this is a work around to get the concept of a calli. It's not as fast but it would be interesting to
// see how it compares to the current implementation.
// This delegate will disappear at some point in favor of calli

internal delegate void CtorDelegate(object instance);

// Keep this in sync with FormatFlags defined in typestring.h
internal enum TypeNameFormatFlags
{
Expand Down Expand Up @@ -3968,113 +3962,45 @@ private void CreateInstanceCheckThis()
return instance;
}

// the cache entry
private sealed class ActivatorCache
{
// the delegate containing the call to the ctor
internal readonly RuntimeMethodHandleInternal _hCtorMethodHandle;
internal MethodAttributes _ctorAttributes;
internal CtorDelegate? _ctor;

// Lazy initialization was performed
internal volatile bool _isFullyInitialized;

private static ConstructorInfo? s_delegateCtorInfo;

internal ActivatorCache(RuntimeMethodHandleInternal rmh)
{
_hCtorMethodHandle = rmh;
}

private void Initialize()
{
if (!_hCtorMethodHandle.IsNullHandle())
{
_ctorAttributes = RuntimeMethodHandle.GetAttributes(_hCtorMethodHandle);

// The default ctor path is optimized for reference types only
ConstructorInfo delegateCtorInfo = s_delegateCtorInfo ??= typeof(CtorDelegate).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })!;

// No synchronization needed here. In the worst case we create extra garbage
GrabYourPitchforks marked this conversation as resolved.
Show resolved Hide resolved
_ctor = (CtorDelegate)delegateCtorInfo.Invoke(new object?[] { null, RuntimeMethodHandle.GetFunctionPointer(_hCtorMethodHandle) });
}
_isFullyInitialized = true;
}

public void EnsureInitialized()
{
if (!_isFullyInitialized)
Initialize();
}
}

/// <summary>
/// The slow path of CreateInstanceDefaultCtor
/// Helper to invoke the default (parameterless) constructor.
/// </summary>
private object? CreateInstanceDefaultCtorSlow(bool publicOnly, bool wrapExceptions, bool fillCache)
[DebuggerStepThrough]
[DebuggerHidden]
internal object? CreateInstanceDefaultCtor(bool publicOnly, bool skipCheckThis, bool fillCache, bool wrapExceptions)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaning up these useless args is left for future PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Wanted to avoid causing churn in the mono codebase at the moment.

{
RuntimeMethodHandleInternal runtimeCtor = default;
bool canBeCached = false;
bool hasNoDefaultCtor = false;
// Get or create the cached factory. Creating the cache will fail if one
// of our invariant checks fails; e.g., no appropriate ctor found.
//
// n.b. In coreclr we ignore 'skipCheckThis' (assumed to be false)
// and 'fillCache' (assumed to be true).

object instance = RuntimeTypeHandle.CreateInstance(this, publicOnly, wrapExceptions, ref canBeCached, ref runtimeCtor, ref hasNoDefaultCtor);
if (hasNoDefaultCtor)
if (GenericCache is not ActivatorCache cache)
{
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, this));
cache = new ActivatorCache(this);
GenericCache = cache;
}

if (canBeCached && fillCache)
if (!cache.CtorIsPublic && publicOnly)
{
// cache the ctor
GenericCache = new ActivatorCache(runtimeCtor);
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, this));
}

return instance;
}
// Compat: allocation always takes place outside the try block so that OOMs
// bubble up to the caller; the ctor invocation is within the try block so
// that it can be wrapped in TIE if needed.

/// <summary>
/// Helper to invoke the default (parameterless) constructor.
/// </summary>
[DebuggerStepThrough]
[DebuggerHidden]
internal object? CreateInstanceDefaultCtor(bool publicOnly, bool skipCheckThis, bool fillCache, bool wrapExceptions)
{
// Call the cached
if (GenericCache is ActivatorCache cacheEntry)
object? obj = cache.CreateUninitializedObject(this);
try
{
cacheEntry.EnsureInitialized();

if (publicOnly)
{
if (cacheEntry._ctor != null &&
(cacheEntry._ctorAttributes & MethodAttributes.MemberAccessMask) != MethodAttributes.Public)
{
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, this));
}
}

// Allocate empty object and call the default constructor if present.
object instance = RuntimeTypeHandle.Allocate(this);
GrabYourPitchforks marked this conversation as resolved.
Show resolved Hide resolved
Debug.Assert(cacheEntry._ctor != null || IsValueType);
if (cacheEntry._ctor != null)
{
try
{
cacheEntry._ctor(instance);
}
catch (Exception e) when (wrapExceptions)
{
throw new TargetInvocationException(e);
}
}

return instance;
cache.CallConstructor(obj);
}
catch (Exception e) when (wrapExceptions)
{
throw new TargetInvocationException(e);
}

if (!skipCheckThis)
CreateInstanceCheckThis();

return CreateInstanceDefaultCtorSlow(publicOnly, wrapExceptions, fillCache);
return obj;
}

internal void InvalidateCachedNestedType() => Cache.InvalidateCachedNestedType();
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/src/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,9 @@ DEFINE_CLASS(RT_TYPE_HANDLE, System, RuntimeTypeHandle)
DEFINE_METHOD(RT_TYPE_HANDLE, GET_TYPE_HELPER, GetTypeHelper, SM_Type_ArrType_IntPtr_int_RetType)
DEFINE_METHOD(RT_TYPE_HANDLE, PVOID_CTOR, .ctor, IM_RuntimeType_RetVoid)
DEFINE_METHOD(RT_TYPE_HANDLE, GETVALUEINTERNAL, GetValueInternal, SM_RuntimeTypeHandle_RetIntPtr)
#ifdef FEATURE_COMINTEROP
DEFINE_METHOD(RT_TYPE_HANDLE, ALLOCATECOMOBJECT, AllocateComObject, SM_VoidPtr_RetObj)
#endif
DEFINE_FIELD(RT_TYPE_HANDLE, M_TYPE, m_type)

DEFINE_CLASS_U(Reflection, RtFieldInfo, NoClass)
Expand Down
6 changes: 4 additions & 2 deletions src/coreclr/src/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ FCFuncStart(gSystem_RuntimeType)
FCFuncEnd()

FCFuncStart(gCOMTypeHandleFuncs)
FCFuncElement("CreateInstance", RuntimeTypeHandle::CreateInstance)
QCFuncElement("CreateInstanceForAnotherGenericParameter", RuntimeTypeHandle::CreateInstanceForAnotherGenericParameter)
QCFuncElement("GetGCHandle", RuntimeTypeHandle::GetGCHandle)
QCFuncElement("FreeGCHandle", RuntimeTypeHandle::FreeGCHandle)
Expand Down Expand Up @@ -239,7 +238,10 @@ FCFuncStart(gCOMTypeHandleFuncs)
FCFuncElement("IsGenericTypeDefinition", RuntimeTypeHandle::IsGenericTypeDefinition)
FCFuncElement("ContainsGenericVariables", RuntimeTypeHandle::ContainsGenericVariables)
FCFuncElement("SatisfiesConstraints", RuntimeTypeHandle::SatisfiesConstraints)
FCFuncElement("Allocate", RuntimeTypeHandle::Allocate) //for A.CI
QCFuncElement("GetActivationInfo", RuntimeTypeHandle::GetActivationInfo)
#ifdef FEATURE_COMINTEROP
FCFuncElement("AllocateComObject", RuntimeTypeHandle::AllocateComObject)
#endif // FEATURE_COMINTEROP
FCFuncElement("CompareCanonicalHandles", RuntimeTypeHandle::CompareCanonicalHandles)
FCIntrinsic("GetValueInternal", RuntimeTypeHandle::GetValueInternal, CORINFO_INTRINSIC_RTH_GetValueInternal)
FCFuncElement("IsEquivalentTo", RuntimeTypeHandle::IsEquivalentTo)
Expand Down
Loading