dotnetdll/resolved/
il.rs

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}
113// can't just impl<T: Debug> since no specialization yet
114impl_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);
127// special impl: UTF-16 LoadString
128impl 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}