1use rust_asm::insn::{Insn, LdcValue, MemberRef};
2
3use super::ConstantPoolIndex;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct ByteOffset(u16);
8
9impl ByteOffset {
10 pub(crate) const fn new(offset: u16) -> Self {
11 Self(offset)
12 }
13
14 #[must_use]
16 pub const fn get(self) -> u16 {
17 self.0
18 }
19}
20
21#[derive(Debug, Clone, Copy)]
22pub struct Instruction<'a> {
24 offset: ByteOffset,
25 instruction: &'a Insn,
26}
27
28impl<'a> Instruction<'a> {
29 pub(crate) const fn new(offset: u16, instruction: &'a Insn) -> Self {
30 Self {
31 offset: ByteOffset::new(offset),
32 instruction,
33 }
34 }
35
36 #[must_use]
38 pub const fn offset(&self) -> ByteOffset {
39 self.offset
40 }
41
42 #[must_use]
44 pub fn opcode(&self) -> u8 {
45 opcode_of(self.instruction)
46 }
47
48 #[must_use]
54 pub fn operand(&self) -> InstructionOperand<'a> {
55 let offset = i32::from(self.offset.get());
56
57 match self.instruction {
58 Insn::Simple(_) => InstructionOperand::None,
59 Insn::Int(node) => InstructionOperand::Immediate(node.operand),
60 Insn::Var(node) => InstructionOperand::Local(node.var_index),
61 Insn::Type(node) => {
62 InstructionOperand::ConstantPool(ConstantPoolIndex::new(node.type_index))
63 }
64 Insn::Field(node) => InstructionOperand::Member(MemberReference::from(&node.field_ref)),
65 Insn::Method(node) => {
66 InstructionOperand::Member(MemberReference::from(&node.method_ref))
67 }
68 Insn::InvokeInterface(node) => InstructionOperand::InvokeInterface {
69 method: ConstantPoolIndex::new(node.method_index),
70 count: node.count,
71 },
72 Insn::InvokeDynamic(node) => InstructionOperand::InvokeDynamic {
73 call_site: ConstantPoolIndex::new(node.method_index),
74 },
75 Insn::Jump(node) => InstructionOperand::Branch {
76 relative: node.offset,
77 target: offset + node.offset,
78 },
79 Insn::Ldc(node) => InstructionOperand::Ldc(LdcValueRef::from(&node.value)),
80 Insn::Iinc(node) => InstructionOperand::Increment {
81 local: node.var_index,
82 amount: node.increment,
83 },
84 Insn::TableSwitch(node) => InstructionOperand::TableSwitch {
85 default: SwitchTarget::new(node.default_offset, offset + node.default_offset),
86 low: node.low,
87 high: node.high,
88 targets: &node.offsets,
89 base_offset: self.offset,
90 },
91 Insn::LookupSwitch(node) => InstructionOperand::LookupSwitch {
92 default: SwitchTarget::new(node.default_offset, offset + node.default_offset),
93 pairs: &node.pairs,
94 base_offset: self.offset,
95 },
96 Insn::MultiANewArray(node) => InstructionOperand::MultiArray {
97 class: ConstantPoolIndex::new(node.type_index),
98 dimensions: node.dimensions,
99 },
100 }
101 }
102}
103
104#[derive(Debug, Clone, Copy)]
105pub enum InstructionOperand<'a> {
110 None,
112 Immediate(i32),
114 Local(u16),
116 ConstantPool(ConstantPoolIndex),
118 Member(MemberReference<'a>),
120 InvokeInterface {
122 method: ConstantPoolIndex,
124 count: u8,
126 },
127 InvokeDynamic {
129 call_site: ConstantPoolIndex,
131 },
132 Branch {
134 relative: i32,
136 target: i32,
138 },
139 Ldc(LdcValueRef<'a>),
141 Increment {
143 local: u16,
145 amount: i16,
147 },
148 TableSwitch {
150 default: SwitchTarget,
152 low: i32,
154 high: i32,
156 targets: &'a [i32],
158 base_offset: ByteOffset,
160 },
161 LookupSwitch {
163 default: SwitchTarget,
165 pairs: &'a [(i32, i32)],
167 base_offset: ByteOffset,
169 },
170 MultiArray {
172 class: ConstantPoolIndex,
174 dimensions: u8,
176 },
177}
178
179#[derive(Debug, Clone, Copy)]
180pub enum MemberReference<'a> {
182 ConstantPool(ConstantPoolIndex),
184 Symbolic {
186 owner: &'a str,
188 name: &'a str,
190 descriptor: &'a str,
192 },
193}
194
195impl<'a> From<&'a MemberRef> for MemberReference<'a> {
196 fn from(value: &'a MemberRef) -> Self {
197 match value {
198 MemberRef::Index(index) => Self::ConstantPool(ConstantPoolIndex::new(*index)),
199 MemberRef::Symbolic {
200 owner,
201 name,
202 descriptor,
203 } => Self::Symbolic {
204 owner,
205 name,
206 descriptor,
207 },
208 }
209 }
210}
211
212#[derive(Debug, Clone, Copy)]
213pub enum LdcValueRef<'a> {
215 ConstantPool(ConstantPoolIndex),
217 String(&'a str),
219 TypeDescriptor,
221 Integer(i32),
223 Float(f32),
225 Long(i64),
227 Double(f64),
229}
230
231impl<'a> From<&'a LdcValue> for LdcValueRef<'a> {
232 fn from(value: &'a LdcValue) -> Self {
233 match value {
234 LdcValue::Index(index) => Self::ConstantPool(ConstantPoolIndex::new(*index)),
235 LdcValue::String(value) => Self::String(value),
236 LdcValue::Type(_) => Self::TypeDescriptor,
237 LdcValue::Int(value) => Self::Integer(*value),
238 LdcValue::Float(value) => Self::Float(*value),
239 LdcValue::Long(value) => Self::Long(*value),
240 LdcValue::Double(value) => Self::Double(*value),
241 }
242 }
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq)]
246pub struct SwitchTarget {
248 relative: i32,
249 target: i32,
250}
251
252impl SwitchTarget {
253 const fn new(relative: i32, target: i32) -> Self {
254 Self { relative, target }
255 }
256
257 #[must_use]
259 pub const fn relative(self) -> i32 {
260 self.relative
261 }
262
263 #[must_use]
265 pub const fn target(self) -> i32 {
266 self.target
267 }
268}
269
270fn opcode_of(instruction: &Insn) -> u8 {
271 match instruction {
272 Insn::Simple(node) => node.opcode,
273 Insn::Int(node) => node.insn.opcode,
274 Insn::Var(node) => node.insn.opcode,
275 Insn::Type(node) => node.insn.opcode,
276 Insn::Field(node) => node.insn.opcode,
277 Insn::Method(node) => node.insn.opcode,
278 Insn::InvokeInterface(node) => node.insn.opcode,
279 Insn::InvokeDynamic(node) => node.insn.opcode,
280 Insn::Jump(node) => node.insn.opcode,
281 Insn::Ldc(node) => node.insn.opcode,
282 Insn::Iinc(node) => node.insn.opcode,
283 Insn::TableSwitch(node) => node.insn.opcode,
284 Insn::LookupSwitch(node) => node.insn.opcode,
285 Insn::MultiANewArray(node) => node.insn.opcode,
286 }
287}