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

Allow CreateInstanceForAnotherGenericParameter to take multi args #45085

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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 @@ -27,7 +27,7 @@ private static IArraySortHelper<T> CreateArraySortHelper()

if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
defaultArraySortHelper = (IArraySortHelper<T>)RuntimeTypeHandle.Allocate(typeof(GenericArraySortHelper<string>).TypeHandle.Instantiate(new Type[] { typeof(T) }));
defaultArraySortHelper = (IArraySortHelper<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericArraySortHelper<string>), (RuntimeType)typeof(T));
}
else
{
Expand Down Expand Up @@ -62,7 +62,7 @@ private static IArraySortHelper<TKey, TValue> CreateArraySortHelper()

if (typeof(IComparable<TKey>).IsAssignableFrom(typeof(TKey)))
{
defaultArraySortHelper = (IArraySortHelper<TKey, TValue>)RuntimeTypeHandle.Allocate(typeof(GenericArraySortHelper<string, string>).TypeHandle.Instantiate(new Type[] { typeof(TKey), typeof(TValue) }));
defaultArraySortHelper = (IArraySortHelper<TKey, TValue>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericArraySortHelper<string, string>), (RuntimeType)typeof(TKey), (RuntimeType)typeof(TValue));
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,49 @@ internal static bool HasElementType(RuntimeType type)
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern object Allocate(RuntimeType type);

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern object CreateInstanceForAnotherGenericParameter(RuntimeType type, RuntimeType genericParameter);
internal static object CreateInstanceForAnotherGenericParameter(RuntimeType type, RuntimeType genericParameter)
{
object? instantiatedObject = null;

IntPtr typeHandle = genericParameter.GetTypeHandleInternal().Value;
_CreateInstanceForAnotherGenericParameter(
new QCallTypeHandle(ref type),
&typeHandle,
1,
ObjectHandleOnStack.Create(ref instantiatedObject));

GC.KeepAlive(genericParameter);
return instantiatedObject!;
}

internal static object CreateInstanceForAnotherGenericParameter(RuntimeType type, RuntimeType genericParameter1, RuntimeType genericParameter2)
{
object? instantiatedObject = null;

IntPtr* pTypeHandles = stackalloc IntPtr[]
{
genericParameter1.GetTypeHandleInternal().Value,
genericParameter2.GetTypeHandleInternal().Value
};

_CreateInstanceForAnotherGenericParameter(
new QCallTypeHandle(ref type),
pTypeHandles,
2,
ObjectHandleOnStack.Create(ref instantiatedObject));

GC.KeepAlive(genericParameter1);
GC.KeepAlive(genericParameter2);

return instantiatedObject!;
}

[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern void _CreateInstanceForAnotherGenericParameter(
QCallTypeHandle baseType,
IntPtr* pTypeHandles,
int cTypeHandles,
ObjectHandleOnStack instantiatedObject);

internal RuntimeType GetRuntimeType()
{
Expand Down Expand Up @@ -471,7 +512,12 @@ internal Type[] GetInstantiationPublic()

internal RuntimeType Instantiate(Type[]? inst)
{
// defensive copy to be sure array is not mutated from the outside during processing
// Defensive copy to ensure array is not mutated while during processing.
// Otherwise another thread could mutate the array after we've already
// fetched the underlying handles, resulting in our KeepAlive tracking
// the wrong values.

inst = (Type[]?)inst?.Clone();
IntPtr[]? instHandles = CopyRuntimeTypeHandles(inst, out int instCount);

fixed (IntPtr* pInst = instHandles)
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/src/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ FCFuncEnd()

FCFuncStart(gCOMTypeHandleFuncs)
FCFuncElement("CreateInstance", RuntimeTypeHandle::CreateInstance)
FCFuncElement("CreateInstanceForAnotherGenericParameter", RuntimeTypeHandle::CreateInstanceForGenericType)
QCFuncElement("_CreateInstanceForAnotherGenericParameter", RuntimeTypeHandle::CreateInstanceForGenericType)
QCFuncElement("GetGCHandle", RuntimeTypeHandle::GetGCHandle)
QCFuncElement("FreeGCHandle", RuntimeTypeHandle::FreeGCHandle)

Expand Down
62 changes: 33 additions & 29 deletions src/coreclr/src/vm/reflectioninvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,55 +515,59 @@ FCIMPL6(Object*, RuntimeTypeHandle::CreateInstance, ReflectClassBaseObject* refT
}
FCIMPLEND

FCIMPL2(Object*, RuntimeTypeHandle::CreateInstanceForGenericType, ReflectClassBaseObject* pTypeUNSAFE, ReflectClassBaseObject* pParameterTypeUNSAFE) {
FCALL_CONTRACT;

struct _gc
{
OBJECTREF rv;
REFLECTCLASSBASEREF refType;
REFLECTCLASSBASEREF refParameterType;
} gc;

gc.rv = NULL;
gc.refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
gc.refParameterType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pParameterTypeUNSAFE);
void QCALLTYPE RuntimeTypeHandle::CreateInstanceForGenericType(
QCall::TypeHandle pTypeHandle,
TypeHandle* pInstArray,
INT32 cInstArray,
QCall::ObjectHandleOnStack pInstantiatedObject
)
{
CONTRACTL{
QCALL_CHECK;
PRECONDITION(!pTypeHandle.AsTypeHandle().IsNull());
PRECONDITION(cInstArray >= 0);
PRECONDITION(cInstArray == 0 || pInstArray != NULL);
}
CONTRACTL_END;

MethodDesc* pMeth;
TypeHandle genericType = gc.refType->GetType();
TypeHandle genericType = pTypeHandle.AsTypeHandle();

TypeHandle parameterHandle = gc.refParameterType->GetType();
BEGIN_QCALL;

_ASSERTE (genericType.HasInstantiation());

HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);

TypeHandle instantiatedType = ((TypeHandle)genericType.GetCanonicalMethodTable()).Instantiate(Instantiation(&parameterHandle, 1));
TypeHandle instantiatedType = ((TypeHandle)genericType.GetCanonicalMethodTable()).Instantiate(Instantiation(pInstArray, (DWORD)cInstArray));

// Get the type information associated with refThis
MethodTable* pVMT = instantiatedType.GetMethodTable();
_ASSERTE (pVMT != 0 && !instantiatedType.IsTypeDesc());
_ASSERTE( !pVMT->IsAbstract() ||! instantiatedType.ContainsGenericVariables());
_ASSERTE(!pVMT->IsByRefLike() && pVMT->HasDefaultConstructor());

pMeth = pVMT->GetDefaultConstructor();
MethodDescCallSite ctor(pMeth);

// We've got the class, lets allocate it and call the constructor

// Nullables don't take this path, if they do we need special logic to make an instance
_ASSERTE(!Nullable::IsNullableType(instantiatedType));
gc.rv = instantiatedType.GetMethodTable()->Allocate();

ARG_SLOT arg = ObjToArgSlot(gc.rv);
{
GCX_COOP();

OBJECTREF newObj = instantiatedType.GetMethodTable()->Allocate();
GCPROTECT_BEGIN(newObj);

// Call the method
TryCallMethod(&ctor, &arg, true);
MethodDesc* pMeth = pVMT->GetDefaultConstructor();
MethodDescCallSite ctor(pMeth);

HELPER_METHOD_FRAME_END();
return OBJECTREFToObject(gc.rv);
// Call the method
ARG_SLOT arg = ObjToArgSlot(newObj);
TryCallMethod(&ctor, &arg, true);
GCPROTECT_END();

pInstantiatedObject.Set(newObj);
}

END_QCALL;
}
FCIMPLEND

NOINLINE FC_BOOL_RET IsInstanceOfTypeHelper(OBJECTREF obj, REFLECTCLASSBASEREF refType)
{
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/src/vm/runtimehandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ class RuntimeTypeHandle {
static FCDECL1(MethodDesc *, GetFirstIntroducedMethod, ReflectClassBaseObject* pType);
static FCDECL1(void, GetNextIntroducedMethod, MethodDesc **ppMethod);

static FCDECL2(Object*, CreateInstanceForGenericType, ReflectClassBaseObject* pType
, ReflectClassBaseObject* parameterType );
static
void QCALLTYPE CreateInstanceForGenericType(QCall::TypeHandle pTypeHandle, TypeHandle *pInstArray, INT32 cInstArray, QCall::ObjectHandleOnStack pInstantiatedObject);

static
FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectClassBaseObject * pModuleUNSAFE);
Expand Down