Skip to main content

ferro_babe/model/
instruction.rs

1use rust_asm::insn::{Insn, LdcValue, MemberRef};
2
3use super::ConstantPoolIndex;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct ByteOffset(u16);
7
8impl ByteOffset {
9    pub(crate) const fn new(offset: u16) -> Self {
10        Self(offset)
11    }
12
13    #[must_use]
14    pub const fn get(self) -> u16 {
15        self.0
16    }
17}
18
19#[derive(Debug, Clone, Copy)]
20pub struct Instruction<'a> {
21    offset: ByteOffset,
22    instruction: &'a Insn,
23}
24
25impl<'a> Instruction<'a> {
26    pub(crate) const fn new(offset: u16, instruction: &'a Insn) -> Self {
27        Self {
28            offset: ByteOffset::new(offset),
29            instruction,
30        }
31    }
32
33    #[must_use]
34    pub const fn offset(&self) -> ByteOffset {
35        self.offset
36    }
37
38    #[must_use]
39    pub fn opcode(&self) -> u8 {
40        opcode_of(self.instruction)
41    }
42
43    #[must_use]
44    pub fn operand(&self) -> InstructionOperand<'a> {
45        let offset = i32::from(self.offset.get());
46
47        match self.instruction {
48            Insn::Simple(_) => InstructionOperand::None,
49            Insn::Int(node) => InstructionOperand::Immediate(node.operand),
50            Insn::Var(node) => InstructionOperand::Local(node.var_index),
51            Insn::Type(node) => {
52                InstructionOperand::ConstantPool(ConstantPoolIndex::new(node.type_index))
53            }
54            Insn::Field(node) => InstructionOperand::Member(MemberReference::from(&node.field_ref)),
55            Insn::Method(node) => {
56                InstructionOperand::Member(MemberReference::from(&node.method_ref))
57            }
58            Insn::InvokeInterface(node) => InstructionOperand::InvokeInterface {
59                method: ConstantPoolIndex::new(node.method_index),
60                count: node.count,
61            },
62            Insn::InvokeDynamic(node) => InstructionOperand::InvokeDynamic {
63                call_site: ConstantPoolIndex::new(node.method_index),
64            },
65            Insn::Jump(node) => InstructionOperand::Branch {
66                relative: node.offset,
67                target: offset + node.offset,
68            },
69            Insn::Ldc(node) => InstructionOperand::Ldc(LdcValueRef::from(&node.value)),
70            Insn::Iinc(node) => InstructionOperand::Increment {
71                local: node.var_index,
72                amount: node.increment,
73            },
74            Insn::TableSwitch(node) => InstructionOperand::TableSwitch {
75                default: SwitchTarget::new(node.default_offset, offset + node.default_offset),
76                low: node.low,
77                high: node.high,
78                targets: &node.offsets,
79                base_offset: self.offset,
80            },
81            Insn::LookupSwitch(node) => InstructionOperand::LookupSwitch {
82                default: SwitchTarget::new(node.default_offset, offset + node.default_offset),
83                pairs: &node.pairs,
84                base_offset: self.offset,
85            },
86            Insn::MultiANewArray(node) => InstructionOperand::MultiArray {
87                class: ConstantPoolIndex::new(node.type_index),
88                dimensions: node.dimensions,
89            },
90        }
91    }
92}
93
94#[derive(Debug, Clone, Copy)]
95pub enum InstructionOperand<'a> {
96    None,
97    Immediate(i32),
98    Local(u16),
99    ConstantPool(ConstantPoolIndex),
100    Member(MemberReference<'a>),
101    InvokeInterface {
102        method: ConstantPoolIndex,
103        count: u8,
104    },
105    InvokeDynamic {
106        call_site: ConstantPoolIndex,
107    },
108    Branch {
109        relative: i32,
110        target: i32,
111    },
112    Ldc(LdcValueRef<'a>),
113    Increment {
114        local: u16,
115        amount: i16,
116    },
117    TableSwitch {
118        default: SwitchTarget,
119        low: i32,
120        high: i32,
121        targets: &'a [i32],
122        base_offset: ByteOffset,
123    },
124    LookupSwitch {
125        default: SwitchTarget,
126        pairs: &'a [(i32, i32)],
127        base_offset: ByteOffset,
128    },
129    MultiArray {
130        class: ConstantPoolIndex,
131        dimensions: u8,
132    },
133}
134
135#[derive(Debug, Clone, Copy)]
136pub enum MemberReference<'a> {
137    ConstantPool(ConstantPoolIndex),
138    Symbolic {
139        owner: &'a str,
140        name: &'a str,
141        descriptor: &'a str,
142    },
143}
144
145impl<'a> From<&'a MemberRef> for MemberReference<'a> {
146    fn from(value: &'a MemberRef) -> Self {
147        match value {
148            MemberRef::Index(index) => Self::ConstantPool(ConstantPoolIndex::new(*index)),
149            MemberRef::Symbolic {
150                owner,
151                name,
152                descriptor,
153            } => Self::Symbolic {
154                owner,
155                name,
156                descriptor,
157            },
158        }
159    }
160}
161
162#[derive(Debug, Clone, Copy)]
163pub enum LdcValueRef<'a> {
164    ConstantPool(ConstantPoolIndex),
165    String(&'a str),
166    TypeDescriptor,
167    Integer(i32),
168    Float(f32),
169    Long(i64),
170    Double(f64),
171}
172
173impl<'a> From<&'a LdcValue> for LdcValueRef<'a> {
174    fn from(value: &'a LdcValue) -> Self {
175        match value {
176            LdcValue::Index(index) => Self::ConstantPool(ConstantPoolIndex::new(*index)),
177            LdcValue::String(value) => Self::String(value),
178            LdcValue::Type(_) => Self::TypeDescriptor,
179            LdcValue::Int(value) => Self::Integer(*value),
180            LdcValue::Float(value) => Self::Float(*value),
181            LdcValue::Long(value) => Self::Long(*value),
182            LdcValue::Double(value) => Self::Double(*value),
183        }
184    }
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
188pub struct SwitchTarget {
189    relative: i32,
190    target: i32,
191}
192
193impl SwitchTarget {
194    const fn new(relative: i32, target: i32) -> Self {
195        Self { relative, target }
196    }
197
198    #[must_use]
199    pub const fn relative(self) -> i32 {
200        self.relative
201    }
202
203    #[must_use]
204    pub const fn target(self) -> i32 {
205        self.target
206    }
207}
208
209fn opcode_of(instruction: &Insn) -> u8 {
210    match instruction {
211        Insn::Simple(node) => node.opcode,
212        Insn::Int(node) => node.insn.opcode,
213        Insn::Var(node) => node.insn.opcode,
214        Insn::Type(node) => node.insn.opcode,
215        Insn::Field(node) => node.insn.opcode,
216        Insn::Method(node) => node.insn.opcode,
217        Insn::InvokeInterface(node) => node.insn.opcode,
218        Insn::InvokeDynamic(node) => node.insn.opcode,
219        Insn::Jump(node) => node.insn.opcode,
220        Insn::Ldc(node) => node.insn.opcode,
221        Insn::Iinc(node) => node.insn.opcode,
222        Insn::TableSwitch(node) => node.insn.opcode,
223        Insn::LookupSwitch(node) => node.insn.opcode,
224        Insn::MultiANewArray(node) => node.insn.opcode,
225    }
226}