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}