Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -80,6 +80,9 @@ public static void PrepareMethod(RuntimeMethodHandle method)

public static void PrepareMethod(RuntimeMethodHandle method, RuntimeTypeHandle[]? instantiation)
{
// defensive copy of user-provided array, per CopyRuntimeTypeHandles contract
instantiation = (RuntimeTypeHandle[]?)instantiation?.Clone();

unsafe
{
IntPtr[]? instantiationHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(instantiation, out int length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ internal static bool HasElementType(RuntimeType type)
|| (corElemType == CorElementType.ELEMENT_TYPE_BYREF); // IsByRef
}

// ** WARNING **
// Caller bears responsibility for ensuring that the provided Types remain
// GC-reachable while the unmanaged handles are being manipulated. The caller
// may need to make a defensive copy of the input array to ensure it's not
// mutated by another thread, and this defensive copy should be passed to
// a KeepAlive routine.
internal static IntPtr[]? CopyRuntimeTypeHandles(RuntimeTypeHandle[]? inHandles, out int length)
{
if (inHandles == null || inHandles.Length == 0)
Expand All @@ -179,6 +185,12 @@ internal static bool HasElementType(RuntimeType type)
return outHandles;
}

// ** WARNING **
// Caller bears responsibility for ensuring that the provided Types remain
// GC-reachable while the unmanaged handles are being manipulated. The caller
// may need to make a defensive copy of the input array to ensure it's not
// mutated by another thread, and this defensive copy should be passed to
// a KeepAlive routine.
internal static IntPtr[]? CopyRuntimeTypeHandles(Type[]? inHandles, out int length)
{
if (inHandles == null || inHandles.Length == 0)
Expand All @@ -202,8 +214,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 +524,6 @@ internal Type[] GetInstantiationPublic()

internal RuntimeType Instantiate(Type[]? inst)
{
// defensive copy to be sure array is not mutated from the outside during processing
IntPtr[]? instHandles = CopyRuntimeTypeHandles(inst, out int instCount);

fixed (IntPtr* pInst = instHandles)
Expand Down Expand Up @@ -1199,6 +1251,10 @@ internal static RuntimeType ResolveTypeHandleInternal(RuntimeModule module, int
throw new ArgumentOutOfRangeException(nameof(typeToken),
SR.Format(SR.Argument_InvalidToken, typeToken, new ModuleHandle(module)));

// defensive copy of user-provided array, per CopyRuntimeTypeHandles contract
typeInstantiationContext = (RuntimeTypeHandle[]?)typeInstantiationContext?.Clone();
methodInstantiationContext = (RuntimeTypeHandle[]?)methodInstantiationContext?.Clone();

IntPtr[]? typeInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(typeInstantiationContext, out int typeInstCount);
IntPtr[]? methodInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(methodInstantiationContext, out int methodInstCount);

Expand Down Expand Up @@ -1232,6 +1288,9 @@ public RuntimeMethodHandle ResolveMethodHandle(int methodToken, RuntimeTypeHandl

internal static IRuntimeMethodInfo ResolveMethodHandleInternal(RuntimeModule module, int methodToken, RuntimeTypeHandle[]? typeInstantiationContext, RuntimeTypeHandle[]? methodInstantiationContext)
{
// defensive copy of user-provided array, per CopyRuntimeTypeHandles contract
typeInstantiationContext = (RuntimeTypeHandle[]?)typeInstantiationContext?.Clone();
methodInstantiationContext = (RuntimeTypeHandle[]?)methodInstantiationContext?.Clone();

IntPtr[]? typeInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(typeInstantiationContext, out int typeInstCount);
IntPtr[]? methodInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(methodInstantiationContext, out int methodInstCount);
Expand Down Expand Up @@ -1277,6 +1336,10 @@ internal static IRuntimeFieldInfo ResolveFieldHandleInternal(RuntimeModule modul
throw new ArgumentOutOfRangeException(nameof(fieldToken),
SR.Format(SR.Argument_InvalidToken, fieldToken, new ModuleHandle(module)));

// defensive copy of user-provided array, per CopyRuntimeTypeHandles contract
typeInstantiationContext = (RuntimeTypeHandle[]?)typeInstantiationContext?.Clone();
methodInstantiationContext = (RuntimeTypeHandle[]?)methodInstantiationContext?.Clone();

// defensive copy to be sure array is not mutated from the outside during processing
IntPtr[]? typeInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(typeInstantiationContext, out int typeInstCount);
IntPtr[]? methodInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(methodInstantiationContext, out int methodInstCount);
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::CreateInstanceForAnotherGenericParameter)
QCFuncElement("GetGCHandle", RuntimeTypeHandle::GetGCHandle)
QCFuncElement("FreeGCHandle", RuntimeTypeHandle::FreeGCHandle)

Expand Down
56 changes: 27 additions & 29 deletions src/coreclr/src/vm/reflectioninvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,55 +515,53 @@ 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::CreateInstanceForAnotherGenericParameter(
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();

// Call the method
TryCallMethod(&ctor, &arg, true);
OBJECTREF newObj = instantiatedType.GetMethodTable()->Allocate();
GCPROTECT_BEGIN(newObj);
CallDefaultConstructor(newObj);
GCPROTECT_END();

HELPER_METHOD_FRAME_END();
return OBJECTREFToObject(gc.rv);
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 CreateInstanceForAnotherGenericParameter(QCall::TypeHandle pTypeHandle, TypeHandle *pInstArray, INT32 cInstArray, QCall::ObjectHandleOnStack pInstantiatedObject);

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