// 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. //////////////////////////////////////////////////////////////////////////////// // JitHelpers // Low-level Jit Helpers //////////////////////////////////////////////////////////////////////////////// using System; using System.Threading; using System.Runtime; using System.Runtime.Versioning; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime.InteropServices; using System.Security; namespace System.Runtime.CompilerServices { // Wrapper for address of a string variable on stack internal struct StringHandleOnStack { private IntPtr m_ptr; internal StringHandleOnStack(IntPtr pString) { m_ptr = pString; } } // Wrapper for address of a object variable on stack internal struct ObjectHandleOnStack { private IntPtr m_ptr; internal ObjectHandleOnStack(IntPtr pObject) { m_ptr = pObject; } } // Wrapper for StackCrawlMark internal struct StackCrawlMarkHandle { private IntPtr m_ptr; internal StackCrawlMarkHandle(IntPtr stackMark) { m_ptr = stackMark; } } // Helper class to assist with unsafe pinning of arbitrary objects. The typical usage pattern is: // fixed (byte * pData = &JitHelpers.GetPinningHelper(value).m_data) // { // ... pData is what Object::GetData() returns in VM ... // } internal class PinningHelper { public byte m_data; } internal class ArrayPinningHelper { public IntPtr m_lengthAndPadding; public byte m_arrayData; } [FriendAccessAllowed] internal static class JitHelpers { // The special dll name to be used for DllImport of QCalls internal const string QCall = "QCall"; // Wraps object variable into a handle. Used to return managed strings from QCalls. // s has to be a local variable on the stack. static internal StringHandleOnStack GetStringHandleOnStack(ref string s) { return new StringHandleOnStack(UnsafeCastToStackPointer(ref s)); } // Wraps object variable into a handle. Used to pass managed object references in and out of QCalls. // o has to be a local variable on the stack. static internal ObjectHandleOnStack GetObjectHandleOnStack(ref T o) where T : class { return new ObjectHandleOnStack(UnsafeCastToStackPointer(ref o)); } // Wraps StackCrawlMark into a handle. Used to pass StackCrawlMark to QCalls. // stackMark has to be a local variable on the stack. static internal StackCrawlMarkHandle GetStackCrawlMarkHandle(ref StackCrawlMark stackMark) { return new StackCrawlMarkHandle(UnsafeCastToStackPointer(ref stackMark)); } #if _DEBUG [FriendAccessAllowed] static internal T UnsafeCast(Object o) where T : class { T ret = UnsafeCastInternal(o); Debug.Assert(ret == (o as T), "Invalid use of JitHelpers.UnsafeCast!"); return ret; } // The IL body of this method is not critical, but its body will be replaced with unsafe code, so // this method is effectively critical static private T UnsafeCastInternal(Object o) where T : class { // The body of this function will be replaced by the EE with unsafe code that just returns o!!! // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } static internal int UnsafeEnumCast(T val) where T : struct // Actually T must be 4 byte (or less) enum { Debug.Assert(typeof(T).IsEnum && (Enum.GetUnderlyingType(typeof(T)) == typeof(int) || Enum.GetUnderlyingType(typeof(T)) == typeof(uint) || Enum.GetUnderlyingType(typeof(T)) == typeof(short) || Enum.GetUnderlyingType(typeof(T)) == typeof(ushort) || Enum.GetUnderlyingType(typeof(T)) == typeof(byte) || Enum.GetUnderlyingType(typeof(T)) == typeof(sbyte)), "Error, T must be an 4 byte (or less) enum JitHelpers.UnsafeEnumCast!"); return UnsafeEnumCastInternal(val); } static private int UnsafeEnumCastInternal(T val) where T : struct // Actually T must be 4 (or less) byte enum { // should be return (int) val; but C# does not allow, runtime does this magically // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } static internal long UnsafeEnumCastLong(T val) where T : struct // Actually T must be 8 byte enum { Debug.Assert(typeof(T).IsEnum && (Enum.GetUnderlyingType(typeof(T)) == typeof(long) || Enum.GetUnderlyingType(typeof(T)) == typeof(ulong)), "Error, T must be an 8 byte enum JitHelpers.UnsafeEnumCastLong!"); return UnsafeEnumCastLongInternal(val); } static private long UnsafeEnumCastLongInternal(T val) where T : struct // Actually T must be 8 byte enum { // should be return (int) val; but C# does not allow, runtime does this magically // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } // Internal method for getting a raw pointer for handles in JitHelpers. // The reference has to point into a local stack variable in order so it can not be moved by the GC. static internal IntPtr UnsafeCastToStackPointer(ref T val) { IntPtr p = UnsafeCastToStackPointerInternal(ref val); Debug.Assert(IsAddressInStack(p), "Pointer not in the stack!"); return p; } static private IntPtr UnsafeCastToStackPointerInternal(ref T val) { // The body of this function will be replaced by the EE with unsafe code that just returns val!!! // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } #else // _DEBUG // The IL body of this method is not critical, but its body will be replaced with unsafe code, so // this method is effectively critical [FriendAccessAllowed] static internal T UnsafeCast(Object o) where T : class { // The body of this function will be replaced by the EE with unsafe code that just returns o!!! // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } static internal int UnsafeEnumCast(T val) where T : struct // Actually T must be 4 byte (or less) enum { // should be return (int) val; but C# does not allow, runtime does this magically // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } static internal long UnsafeEnumCastLong(T val) where T : struct // Actually T must be 8 byte enum { // should be return (long) val; but C# does not allow, runtime does this magically // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } static internal IntPtr UnsafeCastToStackPointer(ref T val) { // The body of this function will be replaced by the EE with unsafe code that just returns o!!! // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } #endif // _DEBUG // Set the given element in the array without any type or range checks [MethodImplAttribute(MethodImplOptions.InternalCall)] extern static internal void UnsafeSetArrayElement(Object[] target, int index, Object element); // Used for unsafe pinning of arbitrary objects. static internal PinningHelper GetPinningHelper(Object o) { // This cast is really unsafe - call the private version that does not assert in debug #if _DEBUG return UnsafeCastInternal(o); #else return UnsafeCast(o); #endif } #if _DEBUG [MethodImplAttribute(MethodImplOptions.InternalCall)] extern static bool IsAddressInStack(IntPtr ptr); #endif static internal bool ByRefLessThan(ref T refA, ref T refB) { // The body of this function will be replaced by the EE with unsafe code!!! // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } /// true if given type is reference type or value type that contains references static internal bool ContainsReferences() { // The body of this function will be replaced by the EE with unsafe code!!! // See getILIntrinsicImplementation for how this happens. throw new InvalidOperationException(); } static internal ref T GetArrayData(T[] array) { // The body of this function will be replaced by the EE with unsafe code!!! // See getILIntrinsicImplementation for how this happens. typeof(ArrayPinningHelper).ToString(); // Type used by the actual method body throw new InvalidOperationException(); } } }