// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//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.Runtime;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Threading;
using Internal.Runtime;
using Internal.Reflection.Core.NonPortable;
using Internal.Runtime.CompilerServices;
using Volatile = System.Threading.Volatile;
namespace Internal.Runtime.Augments
{
[ReflectionBlocked]
public static class RuntimeAugments
{
///
/// Callbacks used for metadata-based stack trace resolution.
///
private static StackTraceMetadataCallbacks s_stackTraceMetadataCallbacks;
//==============================================================================================
// One-time initialization.
//==============================================================================================
[CLSCompliant(false)]
public static void Initialize(ReflectionExecutionDomainCallbacks callbacks)
{
s_reflectionExecutionDomainCallbacks = callbacks;
}
[CLSCompliant(false)]
public static void InitializeLookups(TypeLoaderCallbacks callbacks)
{
s_typeLoaderCallbacks = callbacks;
}
[CLSCompliant(false)]
public static void InitializeInteropLookups(InteropCallbacks callbacks)
{
s_interopCallbacks = callbacks;
}
[CLSCompliant(false)]
public static void InitializeStackTraceMetadataSupport(StackTraceMetadataCallbacks callbacks)
{
s_stackTraceMetadataCallbacks = callbacks;
}
//==============================================================================================
// Access to the underlying execution engine's object allocation routines.
//==============================================================================================
//
// Perform the equivalent of a "newobj", but without invoking any constructors. Other than the EEType, the result object is zero-initialized.
//
// Special cases:
//
// Strings: The .ctor performs both the construction and initialization
// and compiler special cases these.
//
// Nullable: the boxed result is the underlying type rather than Nullable so the constructor
// cannot truly initialize it.
//
// In these cases, this helper returns "null" and ConstructorInfo.Invoke() must deal with these specially.
//
public static object NewObject(RuntimeTypeHandle typeHandle)
{
EETypePtr eeType = typeHandle.ToEETypePtr();
if (eeType.IsNullable
|| eeType == EETypePtr.EETypePtrOf()
)
return null;
return RuntimeImports.RhNewObject(eeType);
}
//
// Helper API to perform the equivalent of a "newobj" for any EEType.
// Unlike the NewObject API, this is the raw version that does not special case any EEType, and should be used with
// caution for very specific scenarios.
//
public static object RawNewObject(RuntimeTypeHandle typeHandle)
{
return RuntimeImports.RhNewObject(typeHandle.ToEETypePtr());
}
//
// 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 EEType rather than the "array of element" EEType.
Debug.Assert(typeHandleForArrayType.ToEETypePtr().IsSzArray);
return RuntimeImports.RhNewArray(typeHandleForArrayType.ToEETypePtr(), 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.
//
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.Arg_NotSupportedNonZeroLowerBound);
}
}
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.
RuntimeTypeHandle elementTypeHandle = new RuntimeTypeHandle(typeHandleForArrayType.ToEETypePtr().ArrayElementType);
int length = lengths[0];
if (length < 0)
throw new OverflowException(); // For compat: we need to throw OverflowException(): Array.CreateInstance throws ArgumentOutOfRangeException()
return Array.CreateInstance(Type.GetTypeFromHandle(elementTypeHandle), length);
}
// Create a local copy of the lenghts that cannot be motified by the caller
int* pLengths = stackalloc int[lengths.Length];
for (int i = 0; i < lengths.Length; i++)
pLengths[i] = lengths[i];
return Array.NewMultiDimArray(typeHandleForArrayType.ToEETypePtr(), pLengths, lengths.Length);
}
public static IntPtr GetAllocateObjectHelperForType(RuntimeTypeHandle type)
{
return RuntimeImports.RhGetRuntimeHelperForType(CreateEETypePtr(type), RuntimeImports.RuntimeHelperKind.AllocateObject);
}
public static IntPtr GetAllocateArrayHelperForType(RuntimeTypeHandle type)
{
return RuntimeImports.RhGetRuntimeHelperForType(CreateEETypePtr(type), RuntimeImports.RuntimeHelperKind.AllocateArray);
}
public static IntPtr GetCastingHelperForType(RuntimeTypeHandle type, bool throwing)
{
return RuntimeImports.RhGetRuntimeHelperForType(CreateEETypePtr(type),
throwing ? RuntimeImports.RuntimeHelperKind.CastClass : RuntimeImports.RuntimeHelperKind.IsInst);
}
public static IntPtr GetCheckArrayElementTypeHelperForType(RuntimeTypeHandle type)
{
return RuntimeImports.RhGetRuntimeHelperForType(CreateEETypePtr(type), RuntimeImports.RuntimeHelperKind.CheckArrayElementType);
}
public static IntPtr GetDispatchMapForType(RuntimeTypeHandle typeHandle)
{
return RuntimeImports.RhGetDispatchMapForType(CreateEETypePtr(typeHandle));
}
public static IntPtr GetFallbackDefaultConstructor()
{
return System.Runtime.InteropServices.AddrofIntrinsics.AddrOf(System.Activator.ClassWithMissingConstructor.MissingDefaultConstructorStaticEntryPoint);
}
//
// 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.ToEETypePtr(), ldftnResult, thisObject, isStatic: isStatic, isOpen: isOpen);
}
//
// Helper to extract the artifact that uniquely identifies a method in the runtime mapping tables.
//
public static IntPtr GetDelegateLdFtnResult(Delegate d, out RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate, out bool isOpenResolver, out bool isInterpreterEntrypoint)
{
return d.GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out isOpenResolver, out isInterpreterEntrypoint);
}
public static void GetDelegateData(Delegate delegateObj, out object firstParameter, out object helperObject, out IntPtr extraFunctionPointerOrData, out IntPtr functionPointer)
{
firstParameter = delegateObj.m_firstParameter;
helperObject = delegateObj.m_helperObject;
extraFunctionPointerOrData = delegateObj.m_extraFunctionPointerOrData;
functionPointer = delegateObj.m_functionPointer;
}
public static int GetLoadedModules(TypeManagerHandle[] resultArray)
{
return Internal.Runtime.CompilerHelpers.StartupCodeHelpers.GetLoadedModules(resultArray);
}
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 typeHandle.ToEETypePtr().RawValue;
}
public static TypeManagerHandle GetModuleFromTypeHandle(RuntimeTypeHandle typeHandle)
{
return RuntimeImports.RhGetModuleFromEEType(GetPointerFromTypeHandle(typeHandle));
}
public static RuntimeTypeHandle CreateRuntimeTypeHandle(IntPtr ldTokenResult)
{
return new RuntimeTypeHandle(new EETypePtr(ldTokenResult));
}
public static unsafe IntPtr GetThreadStaticFieldAddress(RuntimeTypeHandle typeHandle, int threadStaticsBlockOffset, int fieldOffset)
{
return new IntPtr(RuntimeImports.RhGetThreadStaticFieldAddress(typeHandle.ToEETypePtr(), threadStaticsBlockOffset, fieldOffset));
}
public static unsafe void StoreValueTypeField(IntPtr address, object fieldValue, RuntimeTypeHandle fieldType)
{
RuntimeImports.RhUnbox(fieldValue, *(void**)&address, fieldType.ToEETypePtr());
}
public static unsafe ref byte GetRawData(object obj)
{
return ref obj.GetRawData();
}
public static unsafe object LoadValueTypeField(IntPtr address, RuntimeTypeHandle fieldType)
{
return RuntimeImports.RhBox(fieldType.ToEETypePtr(), *(void**)&address);
}
public static unsafe object LoadPointerTypeField(IntPtr address, RuntimeTypeHandle fieldType)
{
return Pointer.Box(*(void**)address, Type.GetTypeFromHandle(fieldType));
}
public static unsafe void StoreValueTypeField(ref byte address, object fieldValue, RuntimeTypeHandle fieldType)
{
RuntimeImports.RhUnbox(fieldValue, ref address, fieldType.ToEETypePtr());
}
public static unsafe void StoreValueTypeField(object obj, int fieldOffset, object fieldValue, RuntimeTypeHandle fieldType)
{
fixed (IntPtr* pObj = &obj.m_pEEType)
{
IntPtr pData = (IntPtr)pObj;
IntPtr pField = pData + fieldOffset;
StoreValueTypeField(pField, fieldValue, fieldType);
}
}
public static unsafe object LoadValueTypeField(object obj, int fieldOffset, RuntimeTypeHandle fieldType)
{
fixed (IntPtr* pObj = &obj.m_pEEType)
{
IntPtr pData = (IntPtr)pObj;
IntPtr pField = pData + fieldOffset;
return LoadValueTypeField(pField, fieldType);
}
}
public static unsafe object LoadPointerTypeField(object obj, int fieldOffset, RuntimeTypeHandle fieldType)
{
fixed (IntPtr* pObj = &obj.m_pEEType)
{
IntPtr pData = (IntPtr)pObj;
IntPtr pField = pData + fieldOffset;
return LoadPointerTypeField(pField, fieldType);
}
}
public static unsafe void StoreReferenceTypeField(IntPtr address, object fieldValue)
{
Volatile.Write