blob: b8e1a23ca21e53b3b0f23fec8494e5e8d2432ead (
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
|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Internal.TypeSystem;
using Debug = System.Diagnostics.Debug;
namespace Internal.IL.Stubs
{
/// <summary>
/// Provides method bodies for System.Runtime.CompilerServices.RuntimeHelpers intrinsics.
/// </summary>
public static class RuntimeHelpersIntrinsics
{
public static MethodIL EmitIL(MethodDesc method)
{
Debug.Assert(((MetadataType)method.OwningType).Name == "RuntimeHelpers");
string methodName = method.Name;
if (methodName == "GetMethodTable")
{
ILEmitter emit = new ILEmitter();
ILCodeStream codeStream = emit.NewCodeStream();
codeStream.EmitLdArg(0);
codeStream.Emit(ILOpcode.ldflda, emit.NewToken(method.Context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "RawData").GetField("Data")));
codeStream.EmitLdc(-method.Context.Target.PointerSize);
codeStream.Emit(ILOpcode.add);
codeStream.Emit(ILOpcode.ldind_i);
codeStream.Emit(ILOpcode.ret);
return emit.Link(method);
}
// All the methods handled below are per-instantiation generic methods
if (method.Instantiation.Length != 1 || method.IsTypicalMethodDefinition)
return null;
TypeDesc elementType = method.Instantiation[0];
// Fallback to non-intrinsic implementation for universal generics
if (elementType.IsCanonicalSubtype(CanonicalFormKind.Universal))
return null;
bool result;
if (methodName == "IsReferenceOrContainsReferences")
{
result = elementType.IsGCPointer || (elementType is DefType defType && defType.ContainsGCPointers);
}
else if (methodName == "IsReference")
{
result = elementType.IsGCPointer;
}
else if (methodName == "IsBitwiseEquatable")
{
// Ideally we could detect automatically whether a type is trivially equatable
// (i.e., its operator == could be implemented via memcmp). But for now we'll
// do the simple thing and hardcode the list of types we know fulfill this contract.
// n.b. This doesn't imply that the type's CompareTo method can be memcmp-implemented,
// as a method like CompareTo may need to take a type's signedness into account.
switch (elementType.UnderlyingType.Category)
{
case TypeFlags.Boolean:
case TypeFlags.Byte:
case TypeFlags.SByte:
case TypeFlags.Char:
case TypeFlags.UInt16:
case TypeFlags.Int16:
case TypeFlags.UInt32:
case TypeFlags.Int32:
case TypeFlags.UInt64:
case TypeFlags.Int64:
case TypeFlags.IntPtr:
case TypeFlags.UIntPtr:
result = true;
break;
default:
var mdType = elementType as MetadataType;
if (mdType != null && mdType.Name == "Rune" && mdType.Namespace == "System.Text")
result = true;
else if (mdType != null && mdType.Name == "Char8" && mdType.Namespace == "System")
result = true;
else
result = false;
break;
}
}
else
{
return null;
}
ILOpcode opcode = result ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0;
return new ILStubMethodIL(method, new byte[] { (byte)opcode, (byte)ILOpcode.ret }, Array.Empty<LocalVariableDefinition>(), Array.Empty<object>());
}
}
}
|