|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//Internal.Runtime.Augments
//-------------------------------------------------
// Why does this exist?:
// Reflection.Execution cannot physically live in System.Private.CoreLib.dll
// as it has a dependency on System.Reflection.Metadata. Its inherently
// low-level nature means, however, it is closely tied to System.Private.CoreLib.dll.
// This contract provides the two-communication between those two .dll's.
//
//
// Implemented by:
// System.Private.CoreLib.dll
//
// Consumed by:
// Reflection.Execution.dll
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Internal.Reflection.Core.Execution;
using Internal.Runtime.CompilerHelpers;
using Internal.Runtime.CompilerServices;
using ExceptionStringID = Internal.TypeSystem.ExceptionStringID;
using ReflectionPointer = System.Reflection.Pointer;
namespace Internal.Runtime.Augments
{
public static unsafe class RuntimeAugments
{
/// <summary>
/// Callbacks used for metadata-based stack trace resolution.
/// </summary>
private static StackTraceMetadataCallbacks s_stackTraceMetadataCallbacks;
//==============================================================================================
// One-time initialization.
//==============================================================================================
[CLSCompliant(false)]
public static void InitializeLookups(TypeLoaderCallbacks callbacks)
{
s_typeLoaderCallbacks = callbacks;
}
[CLSCompliant(false)]
public static void InitializeStackTraceMetadataSupport(StackTraceMetadataCallbacks callbacks)
{
s_stackTraceMetadataCallbacks = callbacks;
}
//==============================================================================================
// Access to the underlying execution engine's object allocation routines.
//==============================================================================================
//
// Helper API to perform the equivalent of a "newobj" for any MethodTable.
// This is the raw version that does not special case any MethodTable, and should be used with
// caution for very specific scenarios.
//
public static object RawNewObject(RuntimeTypeHandle typeHandle)
{
return RuntimeImports.RhNewObject(typeHandle.ToMethodTable());
}
internal static void EnsureMethodTableSafeToAllocate(MethodTable* mt)
{
// We might be dealing with a "necessary" MethodTable (in the ILCompiler terms).
// This MethodTable is okay for casting, but must not be allocated on the GC heap.
Debug.Assert(MethodTable.Of<object>()->NumVtableSlots > 0);
if (mt->NumVtableSlots == 0)
{
// This is a type without a vtable or GCDesc. We must not allow creating an instance of it
throw ReflectionCoreExecution.ExecutionEnvironment.CreateMissingMetadataException(Type.GetTypeFromMethodTable(mt));
}
// Paranoid check: not-meant-for-GC-heap types should be reliably identifiable by empty vtable.
Debug.Assert(!mt->ContainsGCPointers || RuntimeImports.RhGetGCDescSize(mt) != 0);
}
//
// Perform the equivalent of a "newarr" The resulting array is zero-initialized.
//
public static Array NewArray(RuntimeTypeHandle typeHandleForArrayType, int count)
{
// Don't make the easy mistake of passing in the element MethodTable rather than the "array of element" MethodTable.
Debug.Assert(typeHandleForArrayType.ToMethodTable()->IsSzArray);
MethodTable* mt = typeHandleForArrayType.ToMethodTable();
EnsureMethodTableSafeToAllocate(mt);
return RuntimeImports.RhNewArray(mt, count);
}
//
// Perform the equivalent of a "newarr" The resulting array is zero-initialized.
//
// Note that invoking NewMultiDimArray on a rank-1 array type is not the same thing as invoking NewArray().
//
// As a concession to the fact that we don't actually support non-zero lower bounds, "lowerBounds" accepts "null"
// to avoid unnecessary array allocations by the caller.
//
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "The compiler ensures that if we have a TypeHandle of a Rank-1 MdArray, we also generated the SzArray.")]
public static unsafe Array NewMultiDimArray(RuntimeTypeHandle typeHandleForArrayType, int[] lengths, int[]? lowerBounds)
{
Debug.Assert(lengths != null);
Debug.Assert(lowerBounds == null || lowerBounds.Length == lengths.Length);
if (lowerBounds != null)
{
foreach (int lowerBound in lowerBounds)
{
if (lowerBound != 0)
throw new PlatformNotSupportedException(SR.PlatformNotSupported_NonZeroLowerBound);
}
}
if (lengths.Length == 1)
{
// We just checked above that all lower bounds are zero. In that case, we should actually allocate
// a new SzArray instead.
Type elementType = Type.GetTypeFromHandle(new RuntimeTypeHandle(typeHandleForArrayType.ToMethodTable()->RelatedParameterType))!;
return NewArray(elementType.MakeArrayType().TypeHandle, lengths[0]);
}
// Create a local copy of the lengths that cannot be modified by the caller
int* pImmutableLengths = stackalloc int[lengths.Length];
for (int i = 0; i < lengths.Length; i++)
pImmutableLengths[i] = lengths[i];
return Array.NewMultiDimArray(typeHandleForArrayType.ToMethodTable(), pImmutableLengths, lengths.Length);
}
public static unsafe void SetArrayValue(Array array, int[] indices, object value)
{
MethodTable* elementMT = array.ElementMethodTable;
if (elementMT->IsPointer || elementMT->IsFunctionPointer)
{
Debug.Assert(value.GetMethodTable()->ValueTypeSize == IntPtr.Size);
elementMT = value.GetMethodTable();
}
if (elementMT->IsValueType)
{
Debug.Assert(value.GetMethodTable()->IsValueType && elementMT->ValueTypeSize == value.GetMethodTable()->ValueTypeSize);
nint flattenedIndex = array.GetFlattenedIndex(indices);
ref byte element = ref Unsafe.AddByteOffset(ref MemoryMarshal.GetArrayDataReference(array), (nuint)flattenedIndex * array.ElementSize);
RuntimeImports.RhUnbox(value, ref element, elementMT);
}
else
{
RuntimeImports.RhCheckArrayStore(array, value);
nint flattenedIndex = array.GetFlattenedIndex(indices);
ref object element = ref Unsafe.Add(ref Unsafe.As<byte, object>(ref MemoryMarshal.GetArrayDataReference(array)), flattenedIndex);
element = value;
}
}
public static IntPtr GetAllocateObjectHelperForType(RuntimeTypeHandle type)
{
return RuntimeImports.RhGetNewObjectHelper(type.ToMethodTable());
}
public static IntPtr GetFallbackDefaultConstructor()
{
return Activator.GetFallbackDefaultConstructor();
}
//
// Helper to create a delegate on a runtime-supplied type.
//
public static Delegate CreateDelegate(RuntimeTypeHandle typeHandleForDelegate, IntPtr ldftnResult, object thisObject, bool isStatic, bool isOpen)
{
return Delegate.CreateDelegate(typeHandleForDelegate.ToMethodTable(), ldftnResult, thisObject, isStatic: isStatic, isOpen: isOpen);
}
//
// Helper to extract the artifact that identifies a reflectable delegate target in the runtime mapping tables.
//
public static IntPtr GetDelegateLdFtnResult(Delegate d, out RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate, out bool isOpenResolver)
{
return d.GetDelegateLdFtnResult(out typeOfFirstParameterIfInstanceDelegate, out isOpenResolver);
}
// Low level method that returns the loaded modules as array. ReadOnlySpan returning overload
// cannot be used early during startup.
public static int GetLoadedModules(TypeManagerHandle[] resultArray)
{
return Internal.Runtime.CompilerHelpers.StartupCodeHelpers.GetLoadedModules(resultArray);
}
public static ReadOnlySpan<TypeManagerHandle> GetLoadedModules()
{
return Internal.Runtime.CompilerHelpers.StartupCodeHelpers.GetLoadedModules();
}
public static IntPtr GetOSModuleFromPointer(IntPtr pointerVal)
{
return RuntimeImports.RhGetOSModuleFromPointer(pointerVal);
}
public static unsafe bool FindBlob(TypeManagerHandle typeManager, int blobId, IntPtr ppbBlob, IntPtr pcbBlob)
{
return RuntimeImports.RhFindBlob(typeManager, (uint)blobId, (byte**)ppbBlob, (uint*)pcbBlob);
}
public static IntPtr GetPointerFromTypeHandle(RuntimeTypeHandle typeHandle)
{
return (IntPtr)typeHandle.ToMethodTable();
}
public static unsafe TypeManagerHandle GetModuleFromTypeHandle(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->TypeManager;
}
public static unsafe RuntimeTypeHandle CreateRuntimeTypeHandle(IntPtr ldTokenResult)
{
return new RuntimeTypeHandle((MethodTable*)ldTokenResult);
}
public static unsafe void StoreValueTypeField(IntPtr address, object fieldValue, RuntimeTypeHandle fieldType)
{
RuntimeImports.RhUnbox(fieldValue, ref *(byte*)address, fieldType.ToMethodTable());
}
public static unsafe object LoadValueTypeField(IntPtr address, RuntimeTypeHandle fieldType)
{
return RuntimeExports.RhBox(fieldType.ToMethodTable(), ref *(byte*)address);
}
public static unsafe object LoadPointerTypeField(IntPtr address, RuntimeTypeHandle fieldType)
{
if (fieldType.ToMethodTable()->IsFunctionPointer)
return *(IntPtr*)address;
return ReflectionPointer.Box(*(void**)address, Type.GetTypeFromHandle(fieldType));
}
public static unsafe void StoreValueTypeField(object obj, int fieldOffset, object fieldValue, RuntimeTypeHandle fieldType)
{
ref byte address = ref Unsafe.AddByteOffset(ref obj.GetRawData(), new IntPtr(fieldOffset - ObjectHeaderSize));
RuntimeImports.RhUnbox(fieldValue, ref address, fieldType.ToMethodTable());
}
public static unsafe object LoadValueTypeField(object obj, int fieldOffset, RuntimeTypeHandle fieldType)
{
ref byte address = ref Unsafe.AddByteOffset(ref obj.GetRawData(), new IntPtr(fieldOffset - ObjectHeaderSize));
return RuntimeExports.RhBox(fieldType.ToMethodTable(), ref address);
}
public static unsafe object LoadPointerTypeField(object obj, int fieldOffset, RuntimeTypeHandle fieldType)
{
ref byte address = ref Unsafe.AddByteOffset(ref obj.GetRawData(), new IntPtr(fieldOffset - ObjectHeaderSize));
if (fieldType.ToMethodTable()->IsFunctionPointer)
return RuntimeExports.RhBox(MethodTable.Of<IntPtr>(), ref address);
return ReflectionPointer.Box((void*)Unsafe.As<byte, IntPtr>(ref address), Type.GetTypeFromHandle(fieldType));
}
public static unsafe void StoreReferenceTypeField(IntPtr address, object fieldValue)
{
Volatile.Write<object>(ref Unsafe.As<IntPtr, object>(ref *(IntPtr*)address), fieldValue);
}
public static unsafe object LoadReferenceTypeField(IntPtr address)
{
return Volatile.Read<object>(ref Unsafe.As<IntPtr, object>(ref *(IntPtr*)address));
}
public static void StoreReferenceTypeField(object obj, int fieldOffset, object fieldValue)
{
ref byte address = ref Unsafe.AddByteOffset(ref obj.GetRawData(), new IntPtr(fieldOffset - ObjectHeaderSize));
Volatile.Write<object>(ref Unsafe.As<byte, object>(ref address), fieldValue);
}
public static object LoadReferenceTypeField(object obj, int fieldOffset)
{
ref byte address = ref Unsafe.AddByteOffset(ref obj.GetRawData(), new IntPtr(fieldOffset - ObjectHeaderSize));
return Unsafe.As<byte, object>(ref address);
}
[CLSCompliant(false)]
public static void StoreValueTypeFieldValueIntoValueType(TypedReference typedReference, int fieldOffset, object fieldValue, RuntimeTypeHandle fieldTypeHandle)
{
Debug.Assert(TypedReference.TargetTypeToken(typedReference).ToMethodTable()->IsValueType);
RuntimeImports.RhUnbox(fieldValue, ref Unsafe.Add<byte>(ref typedReference.Value, fieldOffset), fieldTypeHandle.ToMethodTable());
}
[CLSCompliant(false)]
public static object LoadValueTypeFieldValueFromValueType(TypedReference typedReference, int fieldOffset, RuntimeTypeHandle fieldTypeHandle)
{
Debug.Assert(TypedReference.TargetTypeToken(typedReference).ToMethodTable()->IsValueType);
Debug.Assert(fieldTypeHandle.ToMethodTable()->IsValueType);
return RuntimeExports.RhBox(fieldTypeHandle.ToMethodTable(), ref Unsafe.Add<byte>(ref typedReference.Value, fieldOffset));
}
[CLSCompliant(false)]
public static void StoreReferenceTypeFieldValueIntoValueType(TypedReference typedReference, int fieldOffset, object fieldValue)
{
Debug.Assert(TypedReference.TargetTypeToken(typedReference).ToMethodTable()->IsValueType);
Unsafe.As<byte, object>(ref Unsafe.Add<byte>(ref typedReference.Value, fieldOffset)) = fieldValue;
}
[CLSCompliant(false)]
public static object LoadReferenceTypeFieldValueFromValueType(TypedReference typedReference, int fieldOffset)
{
Debug.Assert(TypedReference.TargetTypeToken(typedReference).ToMethodTable()->IsValueType);
return Unsafe.As<byte, object>(ref Unsafe.Add<byte>(ref typedReference.Value, fieldOffset));
}
[CLSCompliant(false)]
public static unsafe object LoadPointerTypeFieldValueFromValueType(TypedReference typedReference, int fieldOffset, RuntimeTypeHandle fieldTypeHandle)
{
Debug.Assert(TypedReference.TargetTypeToken(typedReference).ToMethodTable()->IsValueType);
IntPtr ptrValue = Unsafe.As<byte, IntPtr>(ref Unsafe.Add<byte>(ref typedReference.Value, fieldOffset));
if (fieldTypeHandle.ToMethodTable()->IsFunctionPointer)
return ptrValue;
return ReflectionPointer.Box((void*)ptrValue, Type.GetTypeFromHandle(fieldTypeHandle));
}
public static unsafe object GetThreadStaticBase(IntPtr cookie)
{
return ThreadStatics.GetThreadStaticBaseForType(*(TypeManagerSlot**)cookie, (int)*((IntPtr*)(cookie) + 1));
}
public static int GetHighestStaticThreadStaticIndex(TypeManagerHandle typeManager)
{
RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.ThreadStaticRegion, out int length);
return length / IntPtr.Size;
}
public static unsafe int ObjectHeaderSize => sizeof(ObjHeader);
public static unsafe void EnsureClassConstructorRun(IntPtr staticClassConstructionContext)
{
StaticClassConstructionContext* context = (StaticClassConstructionContext*)staticClassConstructionContext;
ClassConstructorRunner.EnsureClassConstructorRun(context);
}
public static Type GetEnumUnderlyingType(RuntimeTypeHandle enumTypeHandle)
{
Debug.Assert(enumTypeHandle.ToMethodTable()->IsEnum);
EETypeElementType elementType = enumTypeHandle.ToMethodTable()->ElementType;
switch (elementType)
{
case EETypeElementType.Boolean:
return typeof(bool);
case EETypeElementType.Char:
return typeof(char);
case EETypeElementType.SByte:
return typeof(sbyte);
case EETypeElementType.Byte:
return typeof(byte);
case EETypeElementType.Int16:
return typeof(short);
case EETypeElementType.UInt16:
return typeof(ushort);
case EETypeElementType.Int32:
return typeof(int);
case EETypeElementType.UInt32:
return typeof(uint);
case EETypeElementType.Int64:
return typeof(long);
case EETypeElementType.UInt64:
return typeof(ulong);
default:
throw new NotSupportedException();
}
}
public static RuntimeTypeHandle GetRelatedParameterTypeHandle(RuntimeTypeHandle parameterTypeHandle)
{
MethodTable* elementType = parameterTypeHandle.ToMethodTable()->RelatedParameterType;
return new RuntimeTypeHandle(elementType);
}
public static unsafe int GetArrayRankOrMinusOneForSzArray(RuntimeTypeHandle arrayHandle)
{
Debug.Assert(IsArrayType(arrayHandle));
return arrayHandle.ToMethodTable()->IsSzArray ? -1 : arrayHandle.ToMethodTable()->ArrayRank;
}
public static bool IsValueType(RuntimeTypeHandle type)
{
return type.ToMethodTable()->IsValueType;
}
public static bool IsInterface(RuntimeTypeHandle type)
{
return type.ToMethodTable()->IsInterface;
}
public static unsafe object Box(RuntimeTypeHandle type, IntPtr address)
{
return RuntimeExports.RhBox(type.ToMethodTable(), ref *(byte*)address);
}
//==============================================================================================
// Execution engine policies.
//==============================================================================================
//
// This returns a generic type with one generic parameter (representing the array element type)
// whose base type and interface list determines what TypeInfo.BaseType and TypeInfo.ImplementedInterfaces
// return for types that return true for IsArray.
//
public static RuntimeTypeHandle ProjectionTypeForArrays
{
get
{
return typeof(Array<>).TypeHandle;
}
}
//
// This implements the "IsAssignableFrom()" api for runtime-created types. By policy, we let the underlying runtime decide assignability.
//
public static bool IsAssignableFrom(RuntimeTypeHandle dstType, RuntimeTypeHandle srcType)
{
MethodTable* dstEEType = dstType.ToMethodTable();
MethodTable* srcEEType = srcType.ToMethodTable();
return RuntimeImports.AreTypesAssignable(srcEEType, dstEEType);
}
//
// Return a type's base type using the runtime type system. If the underlying runtime type system does not support
// this operation, return false and TypeInfo.BaseType will fall back to metadata.
//
// Note that "default(RuntimeTypeHandle)" is a valid result that will map to a null result. (For example, System.Object has a "null" base type.)
//
public static bool TryGetBaseType(RuntimeTypeHandle typeHandle, out RuntimeTypeHandle baseTypeHandle)
{
MethodTable* eeType = typeHandle.ToMethodTable();
if (eeType->IsGenericTypeDefinition || eeType->IsPointer || eeType->IsByRef || eeType->IsFunctionPointer)
{
baseTypeHandle = default(RuntimeTypeHandle);
return false;
}
baseTypeHandle = new RuntimeTypeHandle(eeType->BaseType);
return true;
}
public static int GetGCDescSize(RuntimeTypeHandle typeHandle)
{
return RuntimeImports.RhGetGCDescSize(typeHandle.ToMethodTable());
}
public static int GetInterfaceCount(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->NumInterfaces;
}
public static RuntimeTypeHandle GetInterface(RuntimeTypeHandle typeHandle, int index)
{
return new RuntimeTypeHandle(typeHandle.ToMethodTable()->InterfaceMap[index]);
}
public static IntPtr NewInterfaceDispatchCell(RuntimeTypeHandle interfaceTypeHandle, int slotNumber)
{
IntPtr cell = RuntimeImports.RhNewInterfaceDispatchCell(interfaceTypeHandle.ToMethodTable(), slotNumber);
if (cell == IntPtr.Zero)
throw new OutOfMemoryException();
return cell;
}
[Intrinsic]
public static RuntimeTypeHandle GetCanonType()
{
// Compiler needs to expand this. This is not expressible in IL.
throw new NotSupportedException();
}
public static RuntimeTypeHandle GetGenericDefinition(RuntimeTypeHandle typeHandle)
{
MethodTable* eeType = typeHandle.ToMethodTable();
Debug.Assert(eeType->IsGeneric);
return new RuntimeTypeHandle(eeType->GenericDefinition);
}
public static RuntimeTypeHandle GetGenericArgument(RuntimeTypeHandle typeHandle, int argumentIndex)
{
MethodTable* eeType = typeHandle.ToMethodTable();
Debug.Assert(eeType->IsGeneric);
return new RuntimeTypeHandle(eeType->GenericArguments[argumentIndex]);
}
public static RuntimeTypeHandle GetGenericInstantiation(RuntimeTypeHandle typeHandle, out RuntimeTypeHandle[] genericTypeArgumentHandles)
{
MethodTable* eeType = typeHandle.ToMethodTable();
Debug.Assert(eeType->IsGeneric);
MethodTableList instantiation = eeType->GenericArguments;
genericTypeArgumentHandles = new RuntimeTypeHandle[eeType->GenericArity];
for (int i = 0; i < genericTypeArgumentHandles.Length; i++)
{
genericTypeArgumentHandles[i] = new RuntimeTypeHandle(instantiation[i]);
}
return new RuntimeTypeHandle(eeType->GenericDefinition);
}
public static bool IsGenericType(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->IsGeneric;
}
public static bool IsArrayType(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->IsArray;
}
public static bool IsByRefLike(RuntimeTypeHandle typeHandle) => typeHandle.ToMethodTable()->IsByRefLike;
public static bool IsDynamicType(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->IsDynamicType;
}
public static unsafe IntPtr ResolveStaticDispatchOnType(RuntimeTypeHandle instanceType, RuntimeTypeHandle interfaceType, int slot, out RuntimeTypeHandle genericContext)
{
MethodTable* genericContextPtr = default;
IntPtr result = RuntimeImports.RhResolveStaticDispatchOnType(instanceType.ToMethodTable(), interfaceType.ToMethodTable(), checked((ushort)slot), &genericContextPtr);
if (result != IntPtr.Zero)
genericContext = new RuntimeTypeHandle(genericContextPtr);
else
genericContext = default;
return result;
}
public static unsafe IntPtr ResolveDispatchOnType(RuntimeTypeHandle instanceType, RuntimeTypeHandle interfaceType, int slot)
{
return RuntimeImports.RhResolveDispatchOnType(instanceType.ToMethodTable(), interfaceType.ToMethodTable(), checked((ushort)slot));
}
public static bool IsUnmanagedPointerType(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->IsPointer;
}
public static bool IsFunctionPointerType(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->IsFunctionPointer;
}
public static unsafe RuntimeTypeHandle GetFunctionPointerReturnType(RuntimeTypeHandle typeHandle)
{
return new RuntimeTypeHandle(typeHandle.ToMethodTable()->FunctionPointerReturnType);
}
public static unsafe int GetFunctionPointerParameterCount(RuntimeTypeHandle typeHandle)
{
return (int)typeHandle.ToMethodTable()->NumFunctionPointerParameters;
}
public static unsafe RuntimeTypeHandle GetFunctionPointerParameterType(RuntimeTypeHandle typeHandle, int argumentIndex)
{
Debug.Assert(argumentIndex < GetFunctionPointerParameterCount(typeHandle));
return new RuntimeTypeHandle(typeHandle.ToMethodTable()->FunctionPointerParameters[argumentIndex]);
}
public static unsafe RuntimeTypeHandle[] GetFunctionPointerParameterTypes(RuntimeTypeHandle typeHandle)
{
int paramCount = GetFunctionPointerParameterCount(typeHandle);
if (paramCount == 0)
return Array.Empty<RuntimeTypeHandle>();
RuntimeTypeHandle[] result = new RuntimeTypeHandle[paramCount];
MethodTableList parameters = typeHandle.ToMethodTable()->FunctionPointerParameters;
for (int i = 0; i < result.Length; i++)
{
result[i] = new RuntimeTypeHandle(parameters[i]);
}
return result;
}
public static unsafe bool IsUnmanagedFunctionPointerType(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->IsUnmanagedFunctionPointer;
}
public static bool IsByRefType(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->IsByRef;
}
public static bool IsGenericTypeDefinition(RuntimeTypeHandle typeHandle)
{
return typeHandle.ToMethodTable()->IsGenericTypeDefinition;
}
public static object CheckArgument(object srcObject, RuntimeTypeHandle dstType, BinderBundle? binderBundle)
{
return InvokeUtils.CheckArgument(srcObject, dstType.ToMethodTable(), InvokeUtils.CheckArgumentSemantics.DynamicInvoke, binderBundle);
}
// FieldInfo.SetValueDirect() has a completely different set of rules on how to coerce the argument from
// the other Reflection api.
public static object CheckArgumentForDirectFieldAccess(object srcObject, RuntimeTypeHandle dstType)
{
return InvokeUtils.CheckArgument(srcObject, dstType.ToMethodTable(), InvokeUtils.CheckArgumentSemantics.SetFieldDirect, binderBundle: null);
}
public static bool IsAssignable(object srcObject, RuntimeTypeHandle dstType)
{
MethodTable* srcEEType = srcObject.GetMethodTable();
return RuntimeImports.AreTypesAssignable(srcEEType, dstType.ToMethodTable());
}
//==============================================================================================
// Nullable<> support
//==============================================================================================
public static bool IsNullable(RuntimeTypeHandle declaringTypeHandle)
{
return declaringTypeHandle.ToMethodTable()->IsNullable;
}
public static RuntimeTypeHandle GetNullableType(RuntimeTypeHandle nullableType)
{
MethodTable* theT = nullableType.ToMethodTable()->NullableType;
return new RuntimeTypeHandle(theT);
}
/// <summary>
/// Locate the file path for a given native application module.
/// </summary>
/// <param name="ip">Address inside the module</param>
/// <param name="moduleBase">Module base address</param>
public static unsafe string TryGetFullPathToApplicationModule(IntPtr ip, out IntPtr moduleBase)
{
moduleBase = RuntimeImports.RhGetOSModuleFromPointer(ip);
if (moduleBase == IntPtr.Zero)
return null;
#if TARGET_UNIX
// RhGetModuleFileName on Unix calls dladdr that accepts any ip. Avoid the redundant lookup
// and pass the ip into RhGetModuleFileName directly. Also, older versions of Musl have a bug
// that leads to crash with the redundant lookup.
byte* pModuleNameUtf8;
int numUtf8Chars = RuntimeImports.RhGetModuleFileName(ip, out pModuleNameUtf8);
string modulePath = System.Text.Encoding.UTF8.GetString(pModuleNameUtf8, numUtf8Chars);
#else // TARGET_UNIX
char* pModuleName;
int numChars = RuntimeImports.RhGetModuleFileName(moduleBase, out pModuleName);
string modulePath = new string(pModuleName, 0, numChars);
#endif // TARGET_UNIX
return modulePath;
}
// if functionPointer points at an import or unboxing stub, find the target of the stub
public static IntPtr GetCodeTarget(IntPtr functionPointer)
{
return RuntimeImports.RhGetCodeTarget(functionPointer);
}
public static IntPtr GetTargetOfUnboxingAndInstantiatingStub(IntPtr functionPointer)
{
return RuntimeImports.RhGetTargetOfUnboxingAndInstantiatingStub(functionPointer);
}
//==============================================================================================
// Internals
//==============================================================================================
internal static TypeLoaderCallbacks TypeLoaderCallbacks
{
get
{
TypeLoaderCallbacks callbacks = s_typeLoaderCallbacks;
Debug.Assert(callbacks != null);
return callbacks;
}
}
internal static StackTraceMetadataCallbacks StackTraceCallbacksIfAvailable
{
get
{
return s_stackTraceMetadataCallbacks;
}
}
private static TypeLoaderCallbacks s_typeLoaderCallbacks;
public static object CreateThunksHeap(IntPtr commonStubAddress)
{
return ThunksHeap.CreateThunksHeap(commonStubAddress);
}
public static IntPtr AllocateThunk(object thunksHeap)
{
return ((ThunksHeap)thunksHeap).AllocateThunk();
}
public static void FreeThunk(object thunksHeap, IntPtr thunkAddress)
{
((ThunksHeap)thunksHeap).FreeThunk(thunkAddress);
}
public static void SetThunkData(object thunksHeap, IntPtr thunkAddress, IntPtr context, IntPtr target)
{
((ThunksHeap)thunksHeap).SetThunkData(thunkAddress, context, target);
}
public static bool TryGetThunkData(object thunksHeap, IntPtr thunkAddress, out IntPtr context, out IntPtr target)
{
return ((ThunksHeap)thunksHeap).TryGetThunkData(thunkAddress, out context, out target);
}
public static IntPtr RhHandleAlloc(object value, GCHandleType type)
{
return RuntimeImports.RhHandleAlloc(value, type);
}
public static void RhHandleFree(IntPtr handle)
{
RuntimeImports.RhHandleFree(handle);
}
public static void ThrowTypeLoadExceptionWithArgument(ExceptionStringID id, string className, string typeName, string messageArg)
{
throw TypeLoaderExceptionHelper.CreateTypeLoadException(id, className, typeName, messageArg);
}
public static void ThrowTypeLoadException(ExceptionStringID id, string className, string typeName)
{
throw TypeLoaderExceptionHelper.CreateTypeLoadException(id, className, typeName);
}
public static void ThrowMissingMethodException(ExceptionStringID id, string methodName)
{
throw TypeLoaderExceptionHelper.CreateMissingMethodException(id, methodName);
}
public static void ThrowMissingFieldException(ExceptionStringID id, string fieldName)
{
throw TypeLoaderExceptionHelper.CreateMissingFieldException(id, fieldName);
}
public static void ThrowFileNotFoundException(ExceptionStringID id, string fileName)
{
throw TypeLoaderExceptionHelper.CreateFileNotFoundException(id, fileName);
}
public static void ThrowInvalidProgramException(ExceptionStringID id)
{
throw TypeLoaderExceptionHelper.CreateInvalidProgramException(id);
}
public static void ThrowInvalidProgramExceptionWithArgument(ExceptionStringID id, string methodName)
{
throw TypeLoaderExceptionHelper.CreateInvalidProgramException(id, methodName);
}
public static void ThrowBadImageFormatException(ExceptionStringID id)
{
throw TypeLoaderExceptionHelper.CreateBadImageFormatException(id);
}
}
}
|