1use super::{members::*, signature, types::*, ResolvedDebug};
2use crate::resolution::Resolution;
3
4use dotnetdll_macros::r_instructions;
5use num_derive::FromPrimitive;
6
7#[derive(Debug, Copy, Clone, Eq, PartialEq)]
8pub enum NumberSign {
9 Signed,
10 Unsigned,
11}
12
13#[derive(Debug, Copy, Clone, Eq, PartialEq)]
14pub enum OverflowDetection {
15 Check,
16 NoCheck,
17}
18
19#[derive(Debug, Copy, Clone, Eq, PartialEq)]
20pub enum ConversionType {
21 Int8,
22 UInt8,
23 Int16,
24 UInt16,
25 Int32,
26 UInt32,
27 Int64,
28 UInt64,
29 IntPtr,
30 UIntPtr,
31}
32
33#[derive(Debug, Copy, Clone, FromPrimitive, Eq, PartialEq)]
34pub enum Alignment {
35 Byte = 1,
36 Double = 2,
37 Quad = 4,
38}
39
40#[derive(Debug, Copy, Clone, Eq, PartialEq)]
41pub enum LoadType {
42 Int8,
43 UInt8,
44 Int16,
45 UInt16,
46 Int32,
47 UInt32,
48 Int64,
49 Float32,
50 Float64,
51 IntPtr,
52 Object,
53}
54
55#[derive(Debug, Copy, Clone, Eq, PartialEq)]
56pub enum StoreType {
57 Int8,
58 Int16,
59 Int32,
60 Int64,
61 Float32,
62 Float64,
63 IntPtr,
64 Object,
65}
66
67type Flag = Option<String>;
68trait InstructionFlag {
69 fn show(self) -> Flag;
70}
71impl InstructionFlag for Option<Alignment> {
72 fn show(self) -> Flag {
73 self.map(|a| format!("aligned({:?})", a))
74 }
75}
76impl InstructionFlag for (&'static str, bool) {
77 fn show(self) -> Flag {
78 if self.1 {
79 Some(self.0.to_string())
80 } else {
81 None
82 }
83 }
84}
85fn show_flags(flags: impl IntoIterator<Item = Flag>) -> String {
86 let set_flags: Vec<_> = flags.into_iter().flatten().collect();
87 if set_flags.is_empty() {
88 String::new()
89 } else {
90 format!("[{}]", set_flags.join(", "))
91 }
92}
93
94trait InstructionShow {
95 fn show(&self, _res: &Resolution) -> String;
96}
97impl<T: ResolvedDebug> InstructionShow for T {
98 fn show(&self, res: &Resolution) -> String {
99 self.show(res)
100 }
101}
102macro_rules! impl_debug {
103 ($($t:ty),*) => {
104 $(
105 impl InstructionShow for $t {
106 fn show(&self, _res: &Resolution) -> String {
107 format!("{:?}", self)
108 }
109 }
110 )*
111 }
112}
113impl_debug!(
115 NumberSign,
116 ConversionType,
117 LoadType,
118 StoreType,
119 u16,
120 i32,
121 i64,
122 f32,
123 f64,
124 usize,
125 Vec<usize>
126);
127impl InstructionShow for Vec<u16> {
129 fn show(&self, _res: &Resolution) -> String {
130 format!("{:?}", String::from_utf16_lossy(self))
131 }
132}
133
134r_instructions! {
135 Add,
136 AddOverflow(NumberSign),
137 And,
138 ArgumentList,
139 BranchEqual(usize),
140 BranchGreaterOrEqual(NumberSign, usize),
141 BranchGreater(NumberSign, usize),
142 BranchLessOrEqual(NumberSign, usize),
143 BranchLess(NumberSign, usize),
144 BranchNotEqual(usize),
145 Branch(usize),
146 Breakpoint,
147 BranchFalsy(usize),
148 BranchTruthy(usize),
149 #[flags(tail_call)]
150 Call(MethodSource),
151 CallConstrained(MethodType, MethodSource),
152 #[flags(tail_call)]
153 CallIndirect(signature::MaybeUnmanagedMethod<MethodType>),
154 CompareEqual,
155 CompareGreater(NumberSign),
156 CheckFinite,
157 CompareLess(NumberSign),
158 Convert(ConversionType),
159 ConvertOverflow(ConversionType, NumberSign),
160 ConvertFloat32,
161 ConvertFloat64,
162 ConvertUnsignedToFloat,
163 #[flags(unaligned, volatile)]
164 CopyMemoryBlock,
165 Divide(NumberSign),
166 Duplicate,
167 EndFilter,
168 EndFinally,
169 #[flags(unaligned, volatile)]
170 InitializeMemoryBlock,
171 Jump(MethodSource),
172 LoadArgument(u16),
173 LoadArgumentAddress(u16),
174 LoadConstantInt32(i32),
175 LoadConstantInt64(i64),
176 LoadConstantFloat32(f32),
177 LoadConstantFloat64(f64),
178 LoadMethodPointer(MethodSource),
179 #[flags(unaligned, volatile)]
180 LoadIndirect(LoadType),
181 LoadLocal(u16),
182 LoadLocalAddress(u16),
183 LoadNull,
184 Leave(usize),
185 LocalMemoryAllocate,
186 Multiply,
187 MultiplyOverflow(NumberSign),
188 Negate,
189 NoOperation,
190 Not,
191 Or,
192 Pop,
193 Remainder(NumberSign),
194 Return,
195 ShiftLeft,
196 ShiftRight(NumberSign),
197 StoreArgument(u16),
198 #[flags(unaligned, volatile)]
199 StoreIndirect(StoreType),
200 StoreLocal(u16),
201 Subtract,
202 SubtractOverflow(NumberSign),
203 Switch(Vec<usize>),
204 Xor,
205
206 BoxValue(MethodType),
207 #[flags(null)]
208 CallVirtual(MethodSource),
209 CallVirtualConstrained(MethodType, MethodSource),
210 CallVirtualTail(MethodSource),
211 #[flags(type)]
212 CastClass(MethodType),
213 CopyObject(MethodType),
214 InitializeForObject(MethodType),
215 IsInstance(MethodType),
216 #[flags(range, null)]
217 LoadElement(MethodType),
218 #[flags(range, null)]
219 LoadElementPrimitive(LoadType),
220 #[flags(type, range, null)]
221 LoadElementAddress(MethodType),
222 LoadElementAddressReadonly(MethodType),
223 #[flags(unaligned, volatile)]
224 LoadField(FieldSource),
225 LoadFieldAddress(FieldSource),
226 LoadFieldSkipNullCheck(FieldSource),
227 LoadLength,
228 #[flags(unaligned, volatile)]
229 LoadObject(MethodType),
230 #[flags(volatile)]
231 LoadStaticField(FieldSource),
232 LoadStaticFieldAddress(FieldSource),
233 #[skip_constructor]
234 LoadString(Vec<u16>),
235 LoadTokenField(FieldSource),
236 LoadTokenMethod(MethodSource),
237 LoadTokenType(MethodType),
238 #[flags(null)]
239 LoadVirtualMethodPointer(MethodSource),
240 MakeTypedReference(MethodType),
241 NewArray(MethodType),
242 NewObject(UserMethod),
243 ReadTypedReferenceType,
244 ReadTypedReferenceValue(MethodType),
245 Rethrow,
246 Sizeof(MethodType),
247 #[flags(type, range, null)]
248 StoreElement(MethodType),
249 #[flags(type, range, null)]
250 StoreElementPrimitive(StoreType),
251 #[flags(unaligned, volatile)]
252 StoreField(FieldSource),
253 StoreFieldSkipNullCheck(FieldSource),
254 #[flags(unaligned, volatile)]
255 StoreObject(MethodType),
256 #[flags(volatile)]
257 StoreStaticField(FieldSource),
258 Throw,
259 #[flags(type)]
260 UnboxIntoAddress(MethodType),
261 UnboxIntoValue(MethodType)
262}
263
264impl Instruction {
265 pub fn load_string(s: impl AsRef<str>) -> Self {
266 Instruction::LoadString(s.as_ref().encode_utf16().collect())
267 }
268}
269
270#[macro_export]
271macro_rules! asm {
272 ($ins:ident) => {
273 Instruction::$ins
274 };
275 ($ins:ident $($param:expr),+) => {
276 Instruction::$ins($($param),+)
277 };
278 ($($(@ $label:ident)? $(+ $label_export:ident)? $ins:ident $($param:expr),*;)*) => {{
279 let mut _counter = 0;
280 $(
281 $(let $label = _counter;)?
282 $(let $label_export = _counter;)?
283 _counter += 1;
284 )*
285
286 let _ins = vec![
287 $(
288 $crate::asm! { $ins $($param),* }
289 ),*
290 ];
291
292 (_ins
293 $(
294 $(
295 ,$label_export
296 )?
297 )*
298 )
299 }};
300}