summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs
blob: b86835f778cfabf89ccd68b821a4cf812fd503e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// 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<T>(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<T>(Object o) where T : class
        {
            T ret = UnsafeCastInternal<T>(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<T>(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>(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<T>(val);
        }

        static private int UnsafeEnumCastInternal<T>(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>(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<T>(val);
        }

        static private long UnsafeEnumCastLongInternal<T>(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<T>(ref T val)
        {
            IntPtr p = UnsafeCastToStackPointerInternal<T>(ref val);
            Debug.Assert(IsAddressInStack(p), "Pointer not in the stack!");
            return p;
        }

        static private IntPtr UnsafeCastToStackPointerInternal<T>(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<T>(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>(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>(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<T>(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<PinningHelper>(o);
#else
            return UnsafeCast<PinningHelper>(o);
#endif
        }

#if _DEBUG
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private extern static bool IsAddressInStack(IntPtr ptr);
#endif

        static internal bool ByRefLessThan<T>(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();
        }

        static internal ref T GetArrayData<T>(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();
        }
    }
}