-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathCliMarshaller.cs
More file actions
143 lines (122 loc) · 5.25 KB
/
CliMarshaller.cs
File metadata and controls
143 lines (122 loc) · 5.25 KB
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
using System.Collections.Generic;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using AsmResolver.PE.DotNet.Metadata.Tables;
using Echo.Memory;
using Echo.Platforms.AsmResolver.Emulation.Stack;
namespace Echo.Platforms.AsmResolver.Emulation
{
/// <summary>
/// Provides a mechanism for marshalling values in and out of the evaluation stack.
/// </summary>
public class CliMarshaller
{
private readonly ValueFactory _valueFactory;
private readonly Dictionary<TypeSignature, TypeDefinition> _resolvedTypes = new();
/// <summary>
/// Creates a new instance of the <see cref="CliMarshaller"/> class.
/// </summary>
/// <param name="valueFactory">The factory that is used to create new objects with.</param>
public CliMarshaller(ValueFactory valueFactory)
{
_valueFactory = valueFactory;
}
private TypeSignature GetElementType(TypeSignature type)
{
switch (type.ElementType)
{
case ElementType.ValueType:
if (!_resolvedTypes.TryGetValue(type, out var definition))
{
if (type.TryResolve(_valueFactory.RuntimeContext, out definition))
_resolvedTypes.Add(type, definition);
}
if (definition is null || !definition.IsEnum)
return type;
if (definition.GetEnumUnderlyingType() is not { } enumUnderlyingType)
throw new CilEmulatorException($"Could not resolve enum type {type.FullName}.");
return enumUnderlyingType;
default:
return type;
}
}
private bool IsFloatType(TypeSignature type) => type.ElementType is ElementType.R4 or ElementType.R8;
private bool IsSignedIntegerType(TypeSignature type)
{
switch (type.ElementType)
{
case ElementType.I1:
case ElementType.I2:
case ElementType.I4:
case ElementType.I8:
case ElementType.I:
return true;
default:
return false;
}
}
private bool IsUnsignedIntegerType(TypeSignature type)
{
switch (type.ElementType)
{
case ElementType.Boolean:
case ElementType.U1:
case ElementType.U2:
case ElementType.U4:
case ElementType.U8:
case ElementType.U:
case ElementType.Char:
return true;
default:
return false;
}
}
/// <summary>
/// Marshals the provided value to a value that can be pushed onto the stack.
/// </summary>
/// <param name="value">The value to marshal.</param>
/// <param name="originalType">The type to push the value as.</param>
/// <returns>The marshalled stack slot.</returns>
public StackSlot ToCliValue(BitVector value, TypeSignature originalType)
{
// Resolve the "underlying" element type, if there is any.
originalType = GetElementType(originalType);
// Measure the new size on the stack.
uint size = _valueFactory.GetTypeValueMemoryLayout(originalType).Size;
size = size switch
{
<= 4 => 4,
<= 8 => 8,
_ => size
};
// Create the new bit vector.
bool signExtend = IsSignedIntegerType(originalType);
var result = value.Resize((int) (size * 8), signExtend, _valueFactory.BitVectorPool);
// Determine the type of value on the stack.
StackSlotTypeHint typeHint;
if (signExtend || IsUnsignedIntegerType(originalType))
typeHint = StackSlotTypeHint.Integer;
else if (IsFloatType(originalType))
typeHint = StackSlotTypeHint.Float;
else if (originalType.IsValueType)
typeHint = StackSlotTypeHint.Structure;
else
typeHint = StackSlotTypeHint.Integer; // We might need to classify objects.
return new StackSlot(result, typeHint);
}
/// <summary>
/// Marshals the provided stack slot back to a normal bit vector that is to be used outside of the stack.
/// </summary>
/// <param name="value">The stack value.</param>
/// <param name="targetType">The type to marshal to.</param>
/// <returns>The marshalled value.</returns>
public BitVector FromCliValue(StackSlot value, TypeSignature targetType)
{
// Resolve the "underlying" element type, if there is any.
targetType = GetElementType(targetType);
uint size = _valueFactory.GetTypeValueMemoryLayout(targetType).Size;
bool signExtend = IsSignedIntegerType(targetType);
return value.Contents.Resize((int) (size * 8), signExtend, _valueFactory.BitVectorPool);
}
}
}