-
Notifications
You must be signed in to change notification settings - Fork 1
/
ObjectManipulation.cs
254 lines (234 loc) · 11.8 KB
/
ObjectManipulation.cs
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
using System;
using System.Reflection.Emit;
using JetBrains.Annotations;
namespace ILGeneratorExtensions
{
/// <summary>
/// Contains extension methods for the manipulation of objects
/// </summary>
[PublicAPI]
public static class ObjectManipulation
{
/// <summary>
/// Pops two addresses from the evaluation stack and copies the value type object (of the given type) in the first into the second
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="type">The type of the value type object</param>
[PublicAPI]
public static ILGenerator CopyObject(this ILGenerator generator, Type type)
{
if (!type.IsValueType)
{
throw new InvalidOperationException("Copying a non-value-type results in unspecified runtime behaviour");
}
return generator.FluentEmit(OpCodes.Cpobj, type);
}
/// <summary>
/// Pops two addresses from the evaluation stack and copies the value type object (of the given type) in the first into the second
/// </summary>
/// <typeparam name="T">The type of the value type object</typeparam>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator CopyObject<T>(this ILGenerator generator) where T : struct => generator.CopyObject(typeof (T));
/// <summary>
/// Pops two addresses and an integer from the evaluation stack, and copies that number of bytes from the first address to the second
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator CopyBlock(this ILGenerator generator) => generator.FluentEmit(OpCodes.Cpblk);
/// <summary>
/// Pops two address from the evaluation stack and copies the given number of bytes from the first to the second
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="bytes">The number of bytes to copy</param>
[PublicAPI]
public static ILGenerator CopyBlock(this ILGenerator generator, uint bytes)
{
return generator.LoadConstant(bytes)
.CopyBlock();
}
/// <summary>
/// Pops two addresses and an integer from the evaluation stack, and copies that number of bytes from the first address to the second, with volatile semantics
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator CopyBlockVolatile(this ILGenerator generator)
{
return generator.FluentEmit(OpCodes.Volatile)
.CopyBlock();
}
/// <summary>
/// Pops two address from the evaluation stack and copies the given number of bytes from the first to the second, with volatile semantics
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="bytes">The number of bytes to copy</param>
[PublicAPI]
public static ILGenerator CopyBlockVolatile(this ILGenerator generator, uint bytes)
{
return generator.FluentEmit(OpCodes.Volatile)
.CopyBlock(bytes);
}
/// <summary>
/// Pops an address from the evaluation stack and pushes the value type object (of the given type) at that location onto the evaluation stack
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="type">The type of the value type object</param>
[PublicAPI]
public static ILGenerator LoadValueTypeOntoStack(this ILGenerator generator, Type type)
{
if (!type.IsValueType)
{
throw new InvalidOperationException("This operation is not valid on reference types");
}
if (type == typeof (sbyte))
{
return generator.FluentEmit(OpCodes.Ldind_I1);
}
else if (type == typeof (byte))
{
return generator.FluentEmit(OpCodes.Ldind_U1);
}
else if (type == typeof (short))
{
return generator.FluentEmit(OpCodes.Ldind_I2);
}
else if (type == typeof (ushort))
{
return generator.FluentEmit(OpCodes.Ldind_U2);
}
else if (type == typeof (int))
{
return generator.FluentEmit(OpCodes.Ldind_I4);
}
else if (type == typeof (uint))
{
return generator.FluentEmit(OpCodes.Ldind_U4);
}
else if (type == typeof(long) || type == typeof(ulong))
{
return generator.FluentEmit(OpCodes.Ldind_I8);
}
else if (type == typeof (float))
{
return generator.FluentEmit(OpCodes.Ldind_R4);
}
else if (type == typeof (double))
{
return generator.FluentEmit(OpCodes.Ldind_R8);
}
else
{
return generator.FluentEmit(OpCodes.Ldobj, type);
}
}
/// <summary>
/// Pops an address from the evaluation stack and pushes the value type object (of the given type) at that location onto the evaluation stack
/// </summary>
/// <typeparam name="T">The type of the value type object</typeparam>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator LoadValueTypeOntoStack<T>(this ILGenerator generator) where T : struct
=> generator.LoadValueTypeOntoStack(typeof (T));
/// <summary>
/// Pops an address from the evaluation stack and pushes the value type object (of the given type) at that location onto the evaluation stack, with volatile semantics
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="type">The type of the value type object</param>
[PublicAPI]
public static ILGenerator LoadValueTypeOntoStackVolatile(this ILGenerator generator, Type type)
{
if (!type.IsValueType)
{
throw new InvalidOperationException("This operation is not valid on reference types");
}
return generator.FluentEmit(OpCodes.Volatile)
.LoadValueTypeOntoStack(type);
}
/// <summary>
/// Pops an address from the evaluation stack and pushes the value type object (of the given type) at that location onto the evaluation stack, with volatile semantics
/// </summary>
/// <typeparam name="T">The type of the value type object</typeparam>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator LoadValueTypeOntoStackVolatile<T>(this ILGenerator generator) where T : struct
=> generator.LoadValueTypeOntoStackVolatile(typeof(T));
/// <summary>
/// Pops an address and a value type object (of the given type) from the evaluation stack, and copies the object into the address
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="type">The type of the value type object</param>
[PublicAPI]
public static ILGenerator StoreValueTypeFromStack(this ILGenerator generator, Type type)
{
if (!type.IsValueType)
{
throw new InvalidOperationException("This operation is not valid on reference types");
}
if (type == typeof(sbyte) || type == typeof(byte))
{
return generator.FluentEmit(OpCodes.Ldind_I1);
}
else if (type == typeof(short) || type == typeof(ushort))
{
return generator.FluentEmit(OpCodes.Ldind_I2);
}
else if (type == typeof(int) || type == typeof(uint))
{
return generator.FluentEmit(OpCodes.Ldind_I4);
}
else if (type == typeof(long) || type == typeof(ulong))
{
return generator.FluentEmit(OpCodes.Ldind_I8);
}
else if (type == typeof(float))
{
return generator.FluentEmit(OpCodes.Ldind_R4);
}
else if (type == typeof(double))
{
return generator.FluentEmit(OpCodes.Ldind_R8);
}
else
{
return generator.FluentEmit(OpCodes.Ldobj, type);
}
}
/// <summary>
/// Pops an address and a value type object (of the given type) from the evaluation stack, and copies the object into the address
/// </summary>
/// <typeparam name="T">The type of the value type object</typeparam>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator StoreValueTypeFromStack<T>(this ILGenerator generator) where T : struct
=> generator.StoreValueTypeFromStack(typeof (T));
/// <summary>
/// Pops an address and a value type object (of the given type) from the evaluation stack, and copies the object into the address, with volatile semantics
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="type">The type of the value type object</param>
[PublicAPI]
public static ILGenerator StoreValueTypeFromStackVolatile(this ILGenerator generator, Type type)
{
if (!type.IsValueType)
{
throw new InvalidOperationException("This operation is not valid on a reference type");
}
return generator.FluentEmit(OpCodes.Volatile)
.FluentEmit(OpCodes.Stobj, type);
}
/// <summary>
/// Pops an address and a value type object (of the given type) from the evaluation stack, and copies the object into the address, with volatile semantics
/// </summary>
/// <typeparam name="T">The type of the value type object</typeparam>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator StoreValueTypeFromStackVolatile<T>(this ILGenerator generator) where T : struct
=> generator.StoreValueTypeFromStack(typeof(T));
/// <summary>
/// Pops an address from the evaluation stack, and pushes the object reference located at that address
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator LoadReferenceFromAddress(this ILGenerator generator) => generator.FluentEmit(OpCodes.Ldind_Ref);
}
}