Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
CastHelpers.cs
Go to the documentation of this file.
6
8
9internal static class CastHelpers
10{
11 [DebuggerDisplay("Source = {_source}; Target = {_targetAndResult & ~1}; Result = {_targetAndResult & 1}; VersionNum = {_version & ((1 << 29) - 1)}; Distance = {_version >> 29};")]
12 private struct CastCacheEntry
13 {
14 internal int _version;
15
16 internal nuint _source;
17
18 internal nuint _targetAndResult;
19 }
20
21 private enum CastResult
22 {
24 CanCast,
26 }
27
28 internal struct ArrayElement
29 {
30 public object Value;
31 }
32
33 private static int[] s_table;
34
35 [MethodImpl(MethodImplOptions.AggressiveInlining)]
36 private static int KeyToBucket(ref int tableData, nuint source, nuint target)
37 {
38 int num = HashShift(ref tableData);
39 ulong num2 = BitOperations.RotateLeft(source, 32) ^ target;
40 return (int)((long)num2 * -7046029254386353131L >>> num);
41 }
42
43 [MethodImpl(MethodImplOptions.AggressiveInlining)]
44 private static ref int TableData(int[] table)
45 {
46 return ref MemoryMarshal.GetArrayDataReference(table);
47 }
48
49 [MethodImpl(MethodImplOptions.AggressiveInlining)]
50 private static ref CastCacheEntry Element(ref int tableData, int index)
51 {
52 return ref Unsafe.Add(ref Unsafe.As<int, CastCacheEntry>(ref tableData), index + 1);
53 }
54
55 [MethodImpl(MethodImplOptions.AggressiveInlining)]
56 private static int HashShift(ref int tableData)
57 {
58 return tableData;
59 }
60
61 [MethodImpl(MethodImplOptions.AggressiveInlining)]
62 private static int TableMask(ref int tableData)
63 {
64 return Unsafe.Add(ref tableData, 1);
65 }
66
67 [MethodImpl(MethodImplOptions.AggressiveInlining)]
68 private static CastResult TryGet(nuint source, nuint target)
69 {
70 ref int tableData = ref TableData(s_table);
71 int num = KeyToBucket(ref tableData, source, target);
72 int num2 = 0;
73 while (num2 < 8)
74 {
75 ref CastCacheEntry reference = ref Element(ref tableData, num);
76 int num3 = Volatile.Read(ref reference._version);
77 nuint source2 = reference._source;
78 num3 &= -2;
79 if (source2 == source)
80 {
81 nuint targetAndResult = reference._targetAndResult;
82 targetAndResult ^= target;
83 if (targetAndResult <= 1)
84 {
86 if (num3 != reference._version)
87 {
88 break;
89 }
90 return (CastResult)targetAndResult;
91 }
92 }
93 if (num3 == 0)
94 {
95 break;
96 }
97 num2++;
98 num = (num + num2) & TableMask(ref tableData);
99 }
100 return CastResult.MaybeCast;
101 }
102
103 [MethodImpl(MethodImplOptions.InternalCall)]
104 private unsafe static extern object IsInstanceOfAny_NoCacheLookup(void* toTypeHnd, object obj);
105
106 [MethodImpl(MethodImplOptions.InternalCall)]
107 private unsafe static extern object ChkCastAny_NoCacheLookup(void* toTypeHnd, object obj);
108
109 [MethodImpl(MethodImplOptions.InternalCall)]
110 private unsafe static extern ref byte Unbox_Helper(void* toTypeHnd, object obj);
111
112 [MethodImpl(MethodImplOptions.InternalCall)]
113 private static extern void WriteBarrier(ref object dst, object obj);
114
115 [DebuggerHidden]
116 [StackTraceHidden]
117 [DebuggerStepThrough]
118 private unsafe static object IsInstanceOfAny(void* toTypeHnd, object obj)
119 {
120 if (obj != null)
121 {
122 void* methodTable = RuntimeHelpers.GetMethodTable(obj);
123 if (methodTable != toTypeHnd)
124 {
125 CastResult castResult = TryGet((nuint)methodTable, (nuint)toTypeHnd);
126 if (castResult != CastResult.CanCast)
127 {
128 if (castResult != 0)
129 {
130 return IsInstanceOfAny_NoCacheLookup(toTypeHnd, obj);
131 }
132 obj = null;
133 }
134 }
135 }
136 return obj;
137 }
138
139 [DebuggerHidden]
140 [StackTraceHidden]
141 [DebuggerStepThrough]
142 private unsafe static object IsInstanceOfInterface(void* toTypeHnd, object obj)
143 {
144 MethodTable* methodTable;
145 nint num;
146 MethodTable** ptr;
147 if (obj != null)
148 {
149 methodTable = RuntimeHelpers.GetMethodTable(obj);
150 num = methodTable->InterfaceCount;
151 if (num == 0)
152 {
153 goto IL_0083;
154 }
155 ptr = methodTable->InterfaceMap;
156 if (num < 4)
157 {
158 goto IL_006c;
159 }
160 while (*ptr != toTypeHnd && ptr[1] != toTypeHnd && ptr[2] != toTypeHnd && ptr[3] != toTypeHnd)
161 {
162 ptr += 4;
163 num -= 4;
164 if (num >= 4)
165 {
166 continue;
167 }
168 goto IL_0069;
169 }
170 }
171 goto IL_008e;
172 IL_006c:
173 while (*ptr != toTypeHnd)
174 {
175 ptr++;
176 num--;
177 if (num > 0)
178 {
179 continue;
180 }
181 goto IL_0083;
182 }
183 goto IL_008e;
184 IL_0083:
185 if (!methodTable->NonTrivialInterfaceCast)
186 {
187 obj = null;
188 goto IL_008e;
189 }
190 return IsInstance_Helper(toTypeHnd, obj);
191 IL_008e:
192 return obj;
193 IL_0069:
194 if (num != 0)
195 {
196 goto IL_006c;
197 }
198 goto IL_0083;
199 }
200
201 [DebuggerHidden]
202 [StackTraceHidden]
203 [DebuggerStepThrough]
204 private unsafe static object IsInstanceOfClass(void* toTypeHnd, object obj)
205 {
206 if (obj == null || RuntimeHelpers.GetMethodTable(obj) == toTypeHnd)
207 {
208 return obj;
209 }
210 MethodTable* parentMethodTable = RuntimeHelpers.GetMethodTable(obj)->ParentMethodTable;
211 while (parentMethodTable != toTypeHnd)
212 {
213 if (parentMethodTable != null)
214 {
215 parentMethodTable = parentMethodTable->ParentMethodTable;
216 if (parentMethodTable == toTypeHnd)
217 {
218 break;
219 }
220 if (parentMethodTable != null)
221 {
222 parentMethodTable = parentMethodTable->ParentMethodTable;
223 if (parentMethodTable == toTypeHnd)
224 {
225 break;
226 }
227 if (parentMethodTable != null)
228 {
229 parentMethodTable = parentMethodTable->ParentMethodTable;
230 if (parentMethodTable == toTypeHnd)
231 {
232 break;
233 }
234 if (parentMethodTable != null)
235 {
236 parentMethodTable = parentMethodTable->ParentMethodTable;
237 continue;
238 }
239 }
240 }
241 }
242 obj = null;
243 break;
244 }
245 return obj;
246 }
247
248 [MethodImpl(MethodImplOptions.NoInlining)]
249 [DebuggerHidden]
250 [StackTraceHidden]
251 [DebuggerStepThrough]
252 private unsafe static object IsInstance_Helper(void* toTypeHnd, object obj)
253 {
254 return TryGet((nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)toTypeHnd) switch
255 {
256 CastResult.CanCast => obj,
257 CastResult.CannotCast => null,
258 _ => IsInstanceOfAny_NoCacheLookup(toTypeHnd, obj),
259 };
260 }
261
262 [DebuggerHidden]
263 [StackTraceHidden]
264 [DebuggerStepThrough]
265 private unsafe static object ChkCastAny(void* toTypeHnd, object obj)
266 {
267 if (obj != null)
268 {
269 void* methodTable = RuntimeHelpers.GetMethodTable(obj);
270 if (methodTable != toTypeHnd)
271 {
272 CastResult castResult = TryGet((nuint)methodTable, (nuint)toTypeHnd);
273 if (castResult != CastResult.CanCast)
274 {
275 return ChkCastAny_NoCacheLookup(toTypeHnd, obj);
276 }
277 }
278 }
279 return obj;
280 }
281
282 [MethodImpl(MethodImplOptions.NoInlining)]
283 [DebuggerHidden]
284 [StackTraceHidden]
285 [DebuggerStepThrough]
286 private unsafe static object ChkCast_Helper(void* toTypeHnd, object obj)
287 {
288 CastResult castResult = TryGet((nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)toTypeHnd);
289 if (castResult == CastResult.CanCast)
290 {
291 return obj;
292 }
293 return ChkCastAny_NoCacheLookup(toTypeHnd, obj);
294 }
295
296 [DebuggerHidden]
297 [StackTraceHidden]
298 [DebuggerStepThrough]
299 private unsafe static object ChkCastInterface(void* toTypeHnd, object obj)
300 {
301 nint num;
302 MethodTable** ptr;
303 if (obj != null)
304 {
306 num = methodTable->InterfaceCount;
307 if (num == 0)
308 {
309 goto IL_0084;
310 }
311 ptr = methodTable->InterfaceMap;
312 if (num < 4)
313 {
314 goto IL_0069;
315 }
316 while (*ptr != toTypeHnd && ptr[1] != toTypeHnd && ptr[2] != toTypeHnd && ptr[3] != toTypeHnd)
317 {
318 ptr += 4;
319 num -= 4;
320 if (num >= 4)
321 {
322 continue;
323 }
324 goto IL_0066;
325 }
326 }
327 goto IL_0082;
328 IL_0082:
329 return obj;
330 IL_0069:
331 while (*ptr != toTypeHnd)
332 {
333 ptr++;
334 num--;
335 if (num > 0)
336 {
337 continue;
338 }
339 goto IL_0084;
340 }
341 goto IL_0082;
342 IL_0066:
343 if (num != 0)
344 {
345 goto IL_0069;
346 }
347 goto IL_0084;
348 IL_0084:
349 return ChkCast_Helper(toTypeHnd, obj);
350 }
351
352 [DebuggerHidden]
353 [StackTraceHidden]
354 [DebuggerStepThrough]
355 private unsafe static object ChkCastClass(void* toTypeHnd, object obj)
356 {
357 if (obj == null || RuntimeHelpers.GetMethodTable(obj) == toTypeHnd)
358 {
359 return obj;
360 }
361 return ChkCastClassSpecial(toTypeHnd, obj);
362 }
363
364 [DebuggerHidden]
365 [StackTraceHidden]
366 [DebuggerStepThrough]
367 private unsafe static object ChkCastClassSpecial(void* toTypeHnd, object obj)
368 {
370 while (true)
371 {
372 ptr = ptr->ParentMethodTable;
373 if (ptr != toTypeHnd)
374 {
375 if (ptr == null)
376 {
377 break;
378 }
379 ptr = ptr->ParentMethodTable;
380 if (ptr != toTypeHnd)
381 {
382 if (ptr == null)
383 {
384 break;
385 }
386 ptr = ptr->ParentMethodTable;
387 if (ptr != toTypeHnd)
388 {
389 if (ptr == null)
390 {
391 break;
392 }
393 ptr = ptr->ParentMethodTable;
394 if (ptr != toTypeHnd)
395 {
396 if (ptr == null)
397 {
398 break;
399 }
400 continue;
401 }
402 }
403 }
404 }
405 return obj;
406 }
407 return ChkCast_Helper(toTypeHnd, obj);
408 }
409
410 [DebuggerHidden]
411 [StackTraceHidden]
412 [DebuggerStepThrough]
413 private unsafe static ref byte Unbox(void* toTypeHnd, object obj)
414 {
415 if (RuntimeHelpers.GetMethodTable(obj) == toTypeHnd)
416 {
417 return ref obj.GetRawData();
418 }
419 return ref Unbox_Helper(toTypeHnd, obj);
420 }
421
422 [DebuggerHidden]
423 [StackTraceHidden]
424 [DebuggerStepThrough]
425 private static ref object ThrowArrayMismatchException()
426 {
427 throw new ArrayTypeMismatchException();
428 }
429
430 [MethodImpl(MethodImplOptions.AggressiveOptimization)]
431 [DebuggerHidden]
432 [StackTraceHidden]
433 [DebuggerStepThrough]
434 private unsafe static ref object LdelemaRef(Array array, int index, void* type)
435 {
436 ref object value = ref Unsafe.As<ArrayElement[]>(array)[index].Value;
437 void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType;
438 if (elementType == type)
439 {
440 return ref value;
441 }
442 return ref ThrowArrayMismatchException();
443 }
444
445 [MethodImpl(MethodImplOptions.AggressiveOptimization)]
446 [DebuggerHidden]
447 [StackTraceHidden]
448 [DebuggerStepThrough]
449 private unsafe static void StelemRef(Array array, int index, object obj)
450 {
451 ref object value = ref Unsafe.As<ArrayElement[]>(array)[index].Value;
452 void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType;
453 if (obj != null)
454 {
455 if (elementType == RuntimeHelpers.GetMethodTable(obj) || array.GetType() == typeof(object[]))
456 {
457 WriteBarrier(ref value, obj);
458 }
459 else
460 {
462 }
463 }
464 else
465 {
466 value = null;
467 }
468 }
469
470 [MethodImpl(MethodImplOptions.NoInlining)]
471 [DebuggerHidden]
472 [StackTraceHidden]
473 [DebuggerStepThrough]
474 private unsafe static void StelemRef_Helper(ref object element, void* elementType, object obj)
475 {
476 CastResult castResult = TryGet((nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)elementType);
477 if (castResult == CastResult.CanCast)
478 {
479 WriteBarrier(ref element, obj);
480 }
481 else
482 {
484 }
485 }
486
487 [DebuggerHidden]
488 [StackTraceHidden]
489 [DebuggerStepThrough]
490 private unsafe static void StelemRef_Helper_NoCacheLookup(ref object element, void* elementType, object obj)
491 {
493 if (obj != null)
494 {
495 WriteBarrier(ref element, obj);
496 return;
497 }
498 throw new ArrayTypeMismatchException();
499 }
500}
static uint RotateLeft(uint value, int offset)
static unsafe object IsInstanceOfAny_NoCacheLookup(void *toTypeHnd, object obj)
static ref int TableData(int[] table)
static unsafe void StelemRef_Helper(ref object element, void *elementType, object obj)
static unsafe object ChkCastAny_NoCacheLookup(void *toTypeHnd, object obj)
static unsafe object IsInstanceOfInterface(void *toTypeHnd, object obj)
static unsafe object IsInstance_Helper(void *toTypeHnd, object obj)
static unsafe ref object LdelemaRef(Array array, int index, void *type)
static unsafe object ChkCastClassSpecial(void *toTypeHnd, object obj)
static unsafe object ChkCastClass(void *toTypeHnd, object obj)
static unsafe object IsInstanceOfAny(void *toTypeHnd, object obj)
static unsafe ref byte Unbox(void *toTypeHnd, object obj)
static unsafe object IsInstanceOfClass(void *toTypeHnd, object obj)
static CastResult TryGet(nuint source, nuint target)
static unsafe object ChkCast_Helper(void *toTypeHnd, object obj)
static unsafe object ChkCastAny(void *toTypeHnd, object obj)
static unsafe ref byte Unbox_Helper(void *toTypeHnd, object obj)
static unsafe object ChkCastInterface(void *toTypeHnd, object obj)
static void WriteBarrier(ref object dst, object obj)
static unsafe void StelemRef(Array array, int index, object obj)
static int HashShift(ref int tableData)
static ref CastCacheEntry Element(ref int tableData, int index)
static unsafe void StelemRef_Helper_NoCacheLookup(ref object element, void *elementType, object obj)
static int KeyToBucket(ref int tableData, nuint source, nuint target)
static int TableMask(ref int tableData)
static unsafe MethodTable * GetMethodTable(object obj)
static unsafe ref byte GetArrayDataReference(Array array)
static void ReadMemoryBarrier()
static bool Read(ref bool location)
Definition Volatile.cs:67